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

Introduced detector for rule VNA-00 and VNA-02 with test cases #2077

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

gonczmisi
Copy link
Contributor

@gonczmisi gonczmisi commented May 29, 2022

Introducing new detector for SEI CERT rules:

The detectors looks for classes that could be part of multithreaded code. This means that the detector only analyzes classes, if either of the following conditions are true for the context of the class:

  • the class implements the java.lang.Runnable interface (this includes extending the java.lang.Thread class as well, due to transitive cheking for the Runnable interface)
  • the class contains any synchronized method or block
  • the class contains any volatile or atomic type variables (the latter means the java.util.concurrent.atomic package)
  • there is a java.util.concurrent.locks.Lock interface call anywhere in it (lock(), trylock(), unlock())

If any of the above mentioned conditions are present, then the VNA00 detector looks for primitive variables that match all of the following conditions:

  • the variable gets compared in a not multithreaded method (contains loop conditions as well)
  • the variable is witten in any method, other then the one it got compared in
  • the variable is not declared as volatile, nor as an atomic type (java.util.concurrent.atomic package)
  • there are no manual lock calls in the method where the access is (java.util.concurrent.locks.Lock interface call: lock(), trylock(), unlock())

If any of the above mentioned conditions are present, then the VNA02 detector looks for primitive variables that match all of the following conditions:

  • the variable gets red in a not secured method
  • the variable is witten by a compound operation in a not secured method, other then the one it got compared in
  • the variable is not declared as an atomic type (java.util.concurrent.atomic package), important that volatile is not a guarantee in this rule
  • there are no manual lock calls in the method where the access is (java.util.concurrent.locks.Lock interface call: lock(), trylock(), unlock())

Note: a method is considered secured, if the following either of the following conditions are true:

  • the method is snychronized
  • the method contains any local variables that has an atomic type
  • the method contains a synchronized block
  • the method contains any manual lock calls

Both detectors were tested against the code of the following repositories:

I provieded unit tests for each detectors, that covers all possible test cases (multiple types of multithreaded classes, every kind of compund operations for VNA02 etc.).

Although the numbers of the found bugs were high (specially in the case of Jenkins), all bugs seemed to be a possible vulnerability described by the VNA00 or VNA02 rules.

@gonczmisi
Copy link
Contributor Author

Sorry for the big PR, but these two rules are really in a close connection with each other, so it made more sense for me to develop them together.
Hope it's not gonna be a problem!

@gtoison
Copy link
Contributor

gtoison commented Jun 9, 2022

Hello, this is not a proper review because all of this a above my pay-grade but here are a couple of comments and questions:

  • The detector is testing for Runnable, maybe other interfaces such as Callable should be suspects too?
  • Have you considered using XMethod.usesConcurrency()?
  • There seem to be typos in CompoundOperationsOnSharedVariables (wrote / red instead of written / read)
  • The license headers seem to be missing

@gonczmisi
Copy link
Contributor Author

Hello, this is not a proper review because all of this a above my pay-grade but here are a couple of comments and questions:

  • The detector is testing for Runnable, maybe other interfaces such as Callable should be suspects too?
  • Have you considered using XMethod.usesConcurrency()?
  • There seem to be typos in CompoundOperationsOnSharedVariables (wrote / red instead of written / read)
  • The license headers seem to be missing

Thank you for your remarks @gtoison, I really appreciate them!

  • I will take a look at Callable, and maybe extend this detector in another PR, but this requires some more investigation on the results
  • Unfortunately, I check Method against concurrency, and I make use of its MethodGen
  • Thanks, really bad english by me 😅
  • I though they are added somehow automatically, I added them to make sure

@gonczmisi gonczmisi requested a review from ThrawnCA June 13, 2022 21:12
@gonczmisi
Copy link
Contributor Author

@ThrawnCA could you review this again please?

@gonczmisi gonczmisi requested a review from ThrawnCA June 24, 2022 13:56
@gonczmisi
Copy link
Contributor Author

@ThrawnCA thanks for the review, I pushed the fixes, please check again.

ThrawnCA
ThrawnCA previously approved these changes Jun 27, 2022

@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Contributor

Choose a reason for hiding this comment

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

What is "ful"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume it stands for FindUnreleasedLock, it is the system property that defines the DEBUG flag in the class.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe it would be worth to comment it here, so later the codereader will know it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, IMO the tests shouldn't modify the state of the system, so it would be worth to set it back to the original setting after the tests.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What does the FindUnreleasedLock have to do with this test? Why do you need to set this value?

spotbugs/etc/messages.xml Outdated Show resolved Hide resolved
@gonczmisi gonczmisi requested review from ThrawnCA and KengoTODA and removed request for KengoTODA and ThrawnCA February 23, 2023 20:34
@gonczmisi gonczmisi requested a review from ThrawnCA April 13, 2023 20:51
@gonczmisi
Copy link
Contributor Author

Hi @baloghadamsoftware!
I have checked your PR, as I see only the github actions are the difference.
There are multiple unresolved comments on them, so I didn't integrate them into this PR yet.

Let me know if you wish for that commit to be in this PR, and if so, how would you like to proceed.

@baloghadamsoftware
Copy link
Contributor

The github actions in my PR are a mistake, I did not write them and did not intend to put them into this PR. I only tried to address the comments that you got on your PR. So please continue your work.

### Added
* New detector `BadVisibilityOnSharedPrimitiveVariables` for new bug type `SPV_BAD_VISIBILITY_ON_SHARED_PRIMITIVE_VARIABLES` (See [SEI CERT rule VNA00-J](https://wiki.sei.cmu.edu/confluence/display/java/VNA00-J.+Ensure+visibility+when+accessing+shared+primitive+variables))
* New detector `CompoundOperationsOnSharedVariables` for new bug type `COSV_COMPOUND_OPERATIONS_ON_SHARED_VARIABLES` (See [SEI CERT rule VNA02-J](https://wiki.sei.cmu.edu/confluence/display/java/VNA02-J.+Ensure+that+compound+operations+on+shared+variables+are+atomic))

Copy link
Collaborator

Choose a reason for hiding this comment

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

There is already an Added section in Unreleased. Can you please merge the two?


@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe it would be worth to comment it here, so later the codereader will know it.


@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, IMO the tests shouldn't modify the state of the system, so it would be worth to set it back to the original setting after the tests.

return;
}

if (seen == Const.IFGE || seen == Const.IFGT || seen == Const.IFLT || seen == Const.IFLE || seen == Const.IFNE || seen == Const.IFEQ) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this and the conditions for the if in line 92 are disjunct, it would be worth to have this in an else block, so this if isn't evaluated unnecessarily.

}

private boolean nameIsConstructor(String name) {
return name.equals(Const.CONSTRUCTOR_NAME);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's better to compare to the const value to avoid NPE.

public static boolean implementsRunnable(JavaClass javaClass) {
try {
return Stream.of(javaClass.getAllInterfaces())
.anyMatch(ifc -> ifc.getClassName().equals(RUNNABLE_SIGNATURE));
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's better to compare to the const value to avoid NPE.


LocalVariableTable lvt = method.getLocalVariableTable();
if (lvt != null && Stream.of(lvt.getLocalVariableTable())
.anyMatch(lv -> signatureIsFromAtomicPackage(lv.getSignature()))) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe it would help the readability if you had the condition in a separate variable.


@Before
public void setup() {
SystemProperties.setProperty("ful.debug", "true");
Copy link
Collaborator

Choose a reason for hiding this comment

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

IMO the tests shouldn't modify the state of the system, so it would be worth to set it back to the original setting after the tests.

return Stream.of(classToCheck.getMethods()).anyMatch(method -> isMethodMultiThreaded(method, classContext));
}

public static boolean implementsRunnable(JavaClass javaClass) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I can see, this function is only called from inside this class. Wouldn't it be better to restrict the visibility?

return hasMultiThreadedInstruction(methodGen);
}

public static boolean hasMultiThreadedInstruction(MethodGen methodGen) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I can see, this function is only called from inside this class. Wouldn't it be better to restrict the visibility?

return false;
}

public static boolean isConcurrentLockInterfaceCall(String methodName) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I can see, this function is only called from inside this class. Wouldn't it be better to restrict the visibility?

@github-actions github-actions bot added the Stale label Mar 4, 2024
@github-actions github-actions bot closed this Apr 8, 2024
@hazendaz hazendaz reopened this Apr 12, 2024
@github-actions github-actions bot removed the Stale label Apr 13, 2024
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

7 participants