Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new rule REFL_REFLECTION_INCREASES_ACCESSIBILITY_OF_CLASS #1541

Merged
merged 11 commits into from
Nov 7, 2021

Conversation

baloghadamsoftware
Copy link
Contributor

@baloghadamsoftware baloghadamsoftware commented May 7, 2021

SEI CERT rule SEC05-J forbids the use of reflection to increase
accessibility of classes, methods or fields. If a class in a package
provides a public method which takes an instance of java.lang.Class as
its parameter and calls its newInstance() method then it increases
accessibility of classes in the same package without public constructors.
An attacker code may call this method and pass such class to create an
instance of it. This should be avoided by either making the method
non-public or by invoking SecurityManager.checkPackageAccess on the
package. A third possiblity is to use the java.beans.Beans.instantiate()
method instead of java.lang.Class.newInstance() which checks whether the
Class object being received has any public constructors.

This patch adds a new detector to check this rule.

Change-Id: I1881502512848f8a04b7ee6be95539f5fe88c6b3


Make sure these boxes are checked before submitting your PR -- thank you!

  • Added an entry into CHANGELOG.md if you have changed SpotBugs code

securityCheck = true;
}
} catch (ClassNotFoundException e) {
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There probably should be at least a comment here explaining why we take no action.

a class in a package provides a public method which takes an instance of java.lang.Class as its parameter and
calls its newInstance() method then it increases accessibility of classes in the same package without public
constructors. An attacker code may call this method and pass such class to create an instance of it. This should
be avoided by either making the method non-public or by invoking SecurityManager.checkPackageAccess on the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The security manager is being deprecated and will be removed (see JEP 411).

package. A third possiblity is to use the java.beans.Beans.instantiate() method instead of
java.lang.Class.newInstance() which checks whether the Class object being received has any public constructors.
be avoided by either making the method non-public or by checking for package access permission on the package.
A third possiblity is to use the java.beans.Beans.instantiate() method instead of java.lang.Class.newInstance()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misspelled "possibility"

@baloghadamsoftware
Copy link
Contributor Author

Sorry for force pushing but there was a git mess which I had to sort out.

@baloghadamsoftware
Copy link
Contributor Author

We tested this on some open-source projects and found some true positives. (I mean that they are violations of the SEI CERT rule.)

MATSim
NanoHTTPD

On the rest we did not found anything. Thus no false positives at all and no crashes:
SpotBugs itself
Jenkins
Bt
Ttorrent

@@ -0,0 +1,82 @@
/*
* FindBugs - Find bugs in Java programs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New files should use a SpotBugs copyright notice, not FindBugs.

@KengoTODA KengoTODA requested a review from ThrawnCA July 1, 2021 22:57
ThrawnCA
ThrawnCA previously approved these changes Jul 2, 2021
CHANGELOG.md Outdated Show resolved Hide resolved
KengoTODA added a commit that referenced this pull request Jul 2, 2021
commit 54e0306
Author: Ádám Balogh <adam.balogh@ericsson.com>
Date:   Wed Jun 30 20:04:00 2021 +0200

    Comment header updated from FindBugs to SpotBugs

commit 34430ab
Author: Ádám Balogh <adam.balogh@ericsson.com>
Date:   Fri May 14 11:18:04 2021 +0200

    Nullness check for returned JavaClass instance added

commit 0b10681
Author: Ádám Balogh <adam.balogh@ericsson.com>
Date:   Fri May 14 11:03:56 2021 +0200

    Fixed typo in messages.xml

commit d9ae166
Author: Ádám Balogh <adam.balogh@ericsson.com>
Date:   Mon May 10 13:07:45 2021 +0200

    Added report for missing class and long description rephrased

commit 2c5aa45
Author: Ádám Balogh <adam.balogh@ericsson.com>
Date:   Fri May 7 15:25:20 2021 +0200

    Add new rule REFL_REFLECTION_INCREASES_ACCESSIBILITY_OF_CLASS

    SEI CERT rule SEC05-J forbids the use of reflection to increase
    accessibility of classes, methods or fields. If a class in a package
    provides a public method which takes an instance of java.lang.Class as
    its parameter and calls its newInstance() method then it increases
    accessibility of classes in the same package without public constructors.
    An attacker code may call this method and pass such class to create an
    instance of it. This should be avoided by either making the method
    non-public or by invoking SecurityManager.checkPackageAccess on the
    package. A third possiblity is to use the java.beans.Beans.instantiate()
    method instead of java.lang.Class.newInstance() which checks whether the
    Class object being received has any public constructors.

    This patch adds a new detector to check this rule.
SEI CERT rule SEC05-J forbids the use of reflection to increase
accessibility of classes, methods or fields. If a class in a package
provides a public method which takes an instance of java.lang.Class as
its parameter and calls its newInstance() method then it increases
accessibility of classes in the same package without public constructors.
An attacker code may call this method and pass such class to create an
instance of it. This should be avoided by either making the method
non-public or by invoking SecurityManager.checkPackageAccess on the
package. A third possiblity is to use the java.beans.Beans.instantiate()
method instead of java.lang.Class.newInstance() which checks whether the
Class object being received has any public constructors.

This patch adds a new detector to check this rule.
@baloghadamsoftware
Copy link
Contributor Author

@KengoTODA Rebasing done, also moved line in CHANGELOG.md to ###Unreleased.

KengoTODA
KengoTODA previously approved these changes Jul 23, 2021
@baloghadamsoftware
Copy link
Contributor Author

@KengoTODA It seems that you approved this one. Are there any obstacles in merging it?

@KengoTODA
Copy link
Member

@baloghadamsoftware thanks for reminding me. Could you merge origin/master again and move your CHANGELOG entry to ## Unreleased?

@baloghadamsoftware
Copy link
Contributor Author

@KengoTODA?

Copy link
Member

@KengoTODA KengoTODA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation catches just limited cases and will trigger false positives (expected reflection access). We need a more complicated analysis to make this detector productive.

And please merge the latest master branch, to resolve conflict in the CHANGELOG.md.


@Override
public void sawOpcode(int seen) {
if (seen == Const.INVOKEVIRTUAL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to exit method to reduce nest, so I suggest moving securityCheck confirmation to here like below:

if (securityCheck || seen != Const.INVOKEVIRTUAL) {
    return;
}

Comment on lines 64 to 66
if (!securityCheck && obj.isInitialParameter() && "java.lang.Class".equals(cls.getClassName()) &&
"newInstance".equals(met.getName()) && "()Ljava/lang/Object;".equals(met.getSignature()) &&
getMethod().isPublic()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel these conditions are not so suitable to detect the target defect. What we need to avoid is increasing accessibility, but this method does not check the accessibility of the constructor and the target class.

@baloghadamsoftware
Copy link
Contributor Author

Current implementation catches just limited cases and will trigger false positives (expected reflection access). We need a more complicated analysis to make this detector productive.

And please merge the latest master branch, to resolve conflict in the CHANGELOG.md.

Thank you for taking you time to do a second review on this PR. I merged master into this PR and also fixed the CHANGELOG. Furthermore, I made the change in the condition check you requested and added an additional condition to work only on public classes.

You are completely right, this detector is only the first step, it only catches the second non-compliant example described in the SEI-CERT rule. I originally planned to add the rest in a subsequent PR. Should I do it now, in this particular one?

I tested this on several open-source projects, as you can see above and could not find any false positives, Could you suggest me an example project where we get the false positive you mentioned?

What more complex analysis do you suggest? Actually, a public method in a public class can be called by anyone, even outside the package. If such a method takes a class as its parameter and instantiates it without any security check then we can call it a vulnerability because anyone can pass it a class that is not meant to be instantiated by any other class, just some special classes. We cannot check the actual "increase" because we must be able to detect the vulnerability itself, without the attacker code being present. Thus at the time of the analysis we are not aware of the actual parameter passed to the method. Maybe we should change the error message to contain the "potential" word?

@baloghadamsoftware
Copy link
Contributor Author

Hmm, maybe REFL_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_CLASS?

Ádám Balogh added 3 commits October 27, 2021 16:09
Because of field summaries some fields may also be initial parameters if they are initialized from constructor parameters. Let us exclude them!
The SEI CERT rule also mentions two uncompliant code pieces where accessibility of fields are increased.
This patch extends the detector to also report these cases: REFL_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_FIELD.
@baloghadamsoftware
Copy link
Contributor Author

baloghadamsoftware commented Oct 27, 2021

We tested this on some open-source projects and found some true positives. (I mean that they are violations of the SEI CERT rule.)

MATSim
NanoHTTPD

One out of the three findings on MATSim-Libs and one out of the two findings on NanoHTTPD were actually false positives beause isInitialParameter on OpcodeStack.Item returned true on fields which where initialized by a constructor. Now they are excluded so we only have two true positives on MATSim-Libs and one true positive on NanoHTTPD. No true or false positives on the rest of the projects.

ThrawnCA
ThrawnCA previously approved these changes Oct 31, 2021
@@ -8676,4 +8717,5 @@ after the call to initLogging, the logger configuration is lost
<BugCode abbrev="DL">Unintended contention or possible deadlock due to locking on shared objects</BugCode>
<BugCode abbrev="JUA">Problems in JUnit Assertions</BugCode>
<BugCode abbrev="EOS">Bad End of Stream check</BugCode>
<BugCode abbrev="REFL">Reflection increasing accessibility of classes, methods and fields</BugCode>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to add another BugCode element even in the findbugs.xml

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that I should use two different bug codes for the two kinds of bugs? I changed them now to REFLC and REFLF.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that I should separate the bug codes? I did it, now we have REFLC and REFLF.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you need to add <BugCode> element in another file. Both messages.xml and findbugs.xml have <BugCode> element.

KengoTODA
KengoTODA previously approved these changes Nov 3, 2021
Copy link
Member

@KengoTODA KengoTODA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for your contribution! I will keep this PR open for a while, to get more feedback from the team.

ThrawnCA
ThrawnCA previously approved these changes Nov 3, 2021
@KengoTODA KengoTODA mentioned this pull request Nov 4, 2021
@KengoTODA
Copy link
Member

@baloghadamsoftware Please resolve conflict, probably around CHANGELOG.md.

@baloghadamsoftware
Copy link
Contributor Author

@baloghadamsoftware Please resolve conflict, probably around CHANGELOG.md.

Done.

@KengoTODA KengoTODA merged commit 085339f into spotbugs:master Nov 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants