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
MC_OVERRIDABLE_METHOD_CALL_IN_READ_OBJECT false positive in 4.8.4 #2957
Comments
For what it's worth, I'm using spotbugs-maven-plugin 4.8.3.1 (or 4.8.4.0) with spotbugs 4.8.5-SNAPSHOT.
|
I'm having the same issue with |
Hello @isuckatcs, maybe this changed with #2895, could you please have a look a this issue ? |
Here the error is not triggered, because See SER09-J:
AFAIK the way the check is written should prevent these errors to be reported, but after thinking about it further these might actually be correct to report. SER09-J says the following:
When the overridden method is invoked, the stack frame looks like this:
This means, that if the caller of @JuditKnoll any thought on this? |
Thanks for the complete explanation. You are correct that both
Is that the expected behavior? |
@dsubelman I double checked your example, and according to the current rules of the check, the private boolean shouldIgnoreCallInReadObject(XMethod method) {
// SER09-J-EX0: The readObject() method may invoke the overridable methods defaultReadObject() and readFields()
// in class java.io.ObjectInputStream
boolean inOIS = "java.io.ObjectInputStream".equals(method.getClassName());
String methodName = method.getName();
return inOIS && ("defaultReadObject".equals(methodName) || "readFields".equals(methodName));
}
if (!shouldIgnoreCallInReadObject(method) && !method.isPrivate() && !method.isFinal()) {
bugAccumulator.accumulateBug(
new BugInstance(this, "MC_OVERRIDABLE_METHOD_CALL_IN_READ_OBJECT", NORMAL_PRIORITY)
.addClass(this)
.addMethod(caller)
.addString(method.getName()), sourceLine);
return false;
} These rules correspong to the wording of SER09-J, according to which
The rule says any overridable methods, not just the ones invoked on Initially I remembered that the check is written so that it only checks calls on |
@isuckatcs understood, thanks again for the complete explanation. |
I'm not quite following this logic. I mean, how else would you be able to call Yes, you may have a scenario where calling some other object's method indirectly calls an overridable method of our instance, but I'm pretty sure you won't be able reliably detect these cases while allowing all others, so why bother going beyond the exact, simple scenario given in SER09-J? Coming back to my original problem, could you please, if I'm mistaken, suggest how I should rewrite the following method so spotbugs won't fail?
|
You are correct that the example only mentions the overridable method of the instance, but in that context the exception wouldn't make sense I think.
If we only care about overridable methods invoked on the instance, why does it have to be explicitly stated, that calling 2 overridable methods and only these 2 on For a moment I came to think about what if the exception refers to the public class ObjectInputStream
extends InputStream implements ObjectInput, ObjectStreamConstants
{
...
private final Object readObject(Class<?> type)
throws IOException, ClassNotFoundException
{
...
}
public final Object readObject()
throws IOException, ClassNotFoundException {
return readObject(Object.class);
}
...
} However I think it wouldn't make sense in this context, because these methods cannot be overridden and are also shipped with the JDK you use, so you have no way to modify them. So it probably doesn't even make sense to report errors for them, as you have no way to deal with the errors.
This logic was implemented in #1716, I only extended the check and this feature was already supported.
If I understand it correctly, this method is supposed to deserialize the object. During serialization you convert the object to a byte stream and store it on the disk. Conversely, when you deserialize, you read that exact bytestream and convert it back to the object, which shouldn't require any additional logic. What I see in your method is that you first created a different kind of representation of the object, which you stored on disk and now you read that different representation and try to parse it into the object. I think this transformation wasn't considered, when SER09-J was written, unless I understand something wrong. |
The
But that is beside the point. Importantly, after reviewing SER09-J and the cited SCG 2009 guidelines, I feel that the exception SER09-J-EX0
is not quoting the cited guidelines correctly. "Guideline 7-4 / OBJECT-4: Prevent constructors from calling methods that can be overridden" says:
So the Sun guidelines claim that calling Why would we therefore make an exception for it??? Now, in "Guideline 8-3 / SERIAL-3: View deserialization the same as object construction", they indeed explain an alternative approach, which doesn't require
While this may indeed be a "stricter" solution, this is not always desirable because one would have to manually assign all fields (which exactly So, should we then only allow No. If you look at In fact, ObjectInputStream only has access to How will an attacker make use of an ObjectInputStream subclass then? It doesn't make sense! Therefore, it also doesn't make sense for spotbugs to consider Is As I've just shown, So, we've now established that the goal of these guidelines were to:
We've ruled out possibility 1: there is no way an ObjectInputStream subclass could access Possibility 2 is indeed a legitimate use case for |
When you use JNI, you declare the method in Java and implement it in C++ AFAIK. The C++ method has access to From Java, I don't see any straightforward way to get access to I agree that On the other hand, limiting the check for overridable methods invoked on |
With JNI, the Java security model is entirely defeated (you can access private members, raw memory, etc.). There are separate warnings that cover this scenario already. Reflection access has been historically similarly dangerous, and is easier to contain since Java 9. Serialization is a typical attack vector when it comes to providing malicious data, but, in my view, the scenario where providing a custom ObjectInputStream subclass may lead to a problem that can only be triggered via JNI is a very hypothetical problem. If there is an attacker with JNI access, they can just initialize the class themselves and assign members at will. Given that SER09-J is already considered a low P4 / Low Severity problem, and given the history of spotbugs previously not hitting this issue, I feel that these new warnings (which at least for the string comparison in line 906 of my example is a clear false positive) are not helpful. |
The scenario where a native library is used with a custom ObjectInputStream seems very far-fetched to me too. IMO the rule is for attacks where the code is something like:
An attacker might get an object where the private |
@gtoison Correct, and that (possibility 2) is why I think having this warning in the general case is important, rather than to silence it altogether. I do see some paranoid use case for the override-ObjectInputStream scenario; in case that is desired to be checked by spotbugs, such warning should then be separate, and not be enabled by default. |
With 4.8.4 (and latest 4.8.5-SNAPSHOT), I'm getting two false-positive errors:
Method in question:
In 905, it's clearly a false-positive because the object has been passed as the
ObjectInputStream
.In 906, it's clearly a false-positive because we're operating on a string constant.
I think generally, these errors should not occur because they don't work on
this
(the instance wherereadObject
is called) but on some other object.I understand MC_OVERRIDABLE_METHOD_CALL_IN_READ_OBJECT has been newly introduced in 4.8.4.
The text was updated successfully, but these errors were encountered: