Skip to content

Commit 6b4ca31

Browse files
authored
Merge pull request github#6849 from Marcono1234/marcono1234/improvements
Java: Serialization query improvements
2 parents 1c32399 + ba0dbd5 commit 6b4ca31

File tree

11 files changed

+65
-71
lines changed

11 files changed

+65
-71
lines changed

java/ql/lib/semmle/code/java/JDK.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ class TypeObjectOutputStream extends RefType {
156156
TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") }
157157
}
158158

159+
/** The type `java.io.ObjectInputStream`. */
160+
class TypeObjectInputStream extends RefType {
161+
TypeObjectInputStream() { hasQualifiedName("java.io", "ObjectInputStream") }
162+
}
163+
159164
/** The class `java.nio.file.Paths`. */
160165
class TypePaths extends Class {
161166
TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") }
@@ -275,7 +280,7 @@ class WriteObjectMethod extends Method {
275280
*/
276281
class ReadObjectMethod extends Method {
277282
ReadObjectMethod() {
278-
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
283+
this.getDeclaringType() instanceof TypeObjectInputStream and
279284
(
280285
this.hasName("readObject") or
281286
this.hasName("readObjectOverride") or

java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ private predicate taintPreservingQualifierToMethod(Method m) {
269269
m.getName() = "toString"
270270
)
271271
or
272-
m.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
272+
m.getDeclaringType() instanceof TypeObjectInputStream and
273273
m.getName().matches("read%")
274274
or
275275
m instanceof GetterMethod and

java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -299,10 +299,7 @@ class RuntimeExitOrHaltMethod extends Method {
299299
(this.hasName("exit") or this.hasName("halt")) and
300300
this.getNumberOfParameters() = 1 and
301301
this.getParameter(0).getType().(PrimitiveType).hasName("int") and
302-
this.getDeclaringType()
303-
.getASupertype*()
304-
.getSourceDeclaration()
305-
.hasQualifiedName("java.lang", "Runtime")
302+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
306303
}
307304
}
308305

@@ -315,10 +312,7 @@ class RuntimeAddOrRemoveShutdownHookMethod extends Method {
315312
(this.hasName("addShutdownHook") or this.hasName("removeShutdownHook")) and
316313
this.getNumberOfParameters() = 1 and
317314
this.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "Thread") and
318-
this.getDeclaringType()
319-
.getASupertype*()
320-
.getSourceDeclaration()
321-
.hasQualifiedName("java.lang", "Runtime")
315+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
322316
}
323317
}
324318

@@ -414,33 +408,29 @@ class ForbiddenSerializationMethod extends Method {
414408

415409
/**
416410
* A method named `enableReplaceObject` declared in
417-
* the class `java.io.ObjectInputStream` or a subclass thereof.
411+
* the class `java.io.ObjectOutputStream` or a subclass thereof.
418412
*/
419413
class EnableReplaceObjectMethod extends Method {
420414
EnableReplaceObjectMethod() {
421415
this.hasName("enableReplaceObject") and
422416
this.getNumberOfParameters() = 1 and
423417
this.getParameter(0).getType().(PrimitiveType).hasName("boolean") and
424-
this.getDeclaringType()
425-
.getASupertype*()
426-
.getSourceDeclaration()
427-
.hasQualifiedName("java.io", "ObjectOutputStream")
418+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof
419+
TypeObjectOutputStream
428420
}
429421
}
430422

431423
/**
432424
* A method named `replaceObject` declared in
433-
* the class `java.io.ObjectInputStream` or a subclass thereof.
425+
* the class `java.io.ObjectOutputStream` or a subclass thereof.
434426
*/
435427
class ReplaceObjectMethod extends Method {
436428
ReplaceObjectMethod() {
437429
this.hasName("replaceObject") and
438430
this.getNumberOfParameters() = 1 and
439431
this.getParameter(0).getType() instanceof TypeObject and
440-
this.getDeclaringType()
441-
.getASupertype*()
442-
.getSourceDeclaration()
443-
.hasQualifiedName("java.io", "ObjectOutputStream")
432+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof
433+
TypeObjectOutputStream
444434
}
445435
}
446436

@@ -453,10 +443,7 @@ class EnableResolveObjectMethod extends Method {
453443
this.hasName("enableResolveObject") and
454444
this.getNumberOfParameters() = 1 and
455445
this.getParameter(0).getType().(PrimitiveType).hasName("boolean") and
456-
this.getDeclaringType()
457-
.getASupertype*()
458-
.getSourceDeclaration()
459-
.hasQualifiedName("java.io", "ObjectInputStream")
446+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
460447
}
461448
}
462449

@@ -469,10 +456,7 @@ class ResolveObjectMethod extends Method {
469456
this.hasName("resolveObject") and
470457
this.getNumberOfParameters() = 1 and
471458
this.getParameter(0).getType() instanceof TypeObject and
472-
this.getDeclaringType()
473-
.getASupertype*()
474-
.getSourceDeclaration()
475-
.hasQualifiedName("java.io", "ObjectInputStream")
459+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
476460
}
477461
}
478462

@@ -485,10 +469,7 @@ class ResolveClassMethod extends Method {
485469
this.hasName("resolveClass") and
486470
this.getNumberOfParameters() = 1 and
487471
this.getParameter(0).getType().(RefType).hasQualifiedName("java.io", "ObjectStreamClass") and
488-
this.getDeclaringType()
489-
.getASupertype*()
490-
.getSourceDeclaration()
491-
.hasQualifiedName("java.io", "ObjectInputStream")
472+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
492473
}
493474
}
494475

@@ -500,16 +481,8 @@ class ResolveProxyClassMethod extends Method {
500481
ResolveProxyClassMethod() {
501482
this.hasName("resolveProxyClass") and
502483
this.getNumberOfParameters() = 1 and
503-
this.getParameter(0)
504-
.getType()
505-
.(Array)
506-
.getComponentType()
507-
.(RefType)
508-
.hasQualifiedName("java.lang", "String") and
509-
this.getDeclaringType()
510-
.getASupertype*()
511-
.getSourceDeclaration()
512-
.hasQualifiedName("java.io", "ObjectInputStream")
484+
this.getParameter(0).getType().(Array).getComponentType() instanceof TypeString and
485+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
513486
}
514487
}
515488

@@ -598,16 +571,13 @@ class SystemOrRuntimeLoadLibraryMethod extends Method {
598571
SystemOrRuntimeLoadLibraryMethod() {
599572
(this.hasName("load") or this.hasName("loadLibrary")) and
600573
this.getNumberOfParameters() = 1 and
601-
this.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "String") and
574+
this.getParameter(0).getType() instanceof TypeString and
602575
(
603576
this.getDeclaringType()
604577
.getASupertype*()
605578
.getSourceDeclaration()
606579
.hasQualifiedName("java.lang", "System") or
607-
this.getDeclaringType()
608-
.getASupertype*()
609-
.getSourceDeclaration()
610-
.hasQualifiedName("java.lang", "Runtime")
580+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
611581
)
612582
}
613583
}
@@ -619,9 +589,6 @@ class SystemOrRuntimeLoadLibraryMethod extends Method {
619589
class RuntimeExecMethod extends Method {
620590
RuntimeExecMethod() {
621591
this.hasName("exec") and
622-
this.getDeclaringType()
623-
.getASupertype*()
624-
.getSourceDeclaration()
625-
.hasQualifiedName("java.lang", "Runtime")
592+
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
626593
}
627594
}

java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private import semmle.code.java.Reflection
2222

2323
private class ObjectInputStreamReadObjectMethod extends Method {
2424
ObjectInputStreamReadObjectMethod() {
25-
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.io", "ObjectInputStream") and
25+
this.getDeclaringType().getASourceSupertype*() instanceof TypeObjectInputStream and
2626
(this.hasName("readObject") or this.hasName("readUnshared"))
2727
}
2828
}

java/ql/src/Likely Bugs/Concurrency/SynchWriteObject.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ where
2020
m.getDeclaringType().getASupertype*() instanceof TypeSerializable and
2121
m.hasName("writeObject") and
2222
m.getNumberOfParameters() = 1 and
23-
m.getAParamType().(Class).hasQualifiedName("java.io", "ObjectOutputStream") and
23+
m.getAParamType() instanceof TypeObjectOutputStream and
2424
m.isSynchronized() and
2525
not exists(Method s |
2626
m.getDeclaringType().inherits(s) and

java/ql/src/Likely Bugs/Reflection/AnnotationPresentCheck.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ where
1919
m.getNumberOfParameters() = 1 and
2020
c.getArgument(0).getType() = p and
2121
p.getATypeArgument() = t and
22-
not exists(Annotation a |
22+
not exists(RetentionAnnotation a |
2323
t.getAnAnnotation() = a and
24-
a.getType().hasQualifiedName("java.lang.annotation", "Retention") and
2524
a.getAValue().(VarAccess).getVariable().hasName("RUNTIME")
2625
)
2726
select c, "Call to isAnnotationPresent where no annotation has the RUNTIME retention policy."

java/ql/src/Likely Bugs/Serialization/IncorrectSerializableMethods.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ void readObject(ObjectInputStream in) {
55
//...
66
}
77

8+
// BAD: Does not match the exact signature required for a custom
9+
// deserialization protocol. Will not be called during deserialization.
10+
void readObjectNoData() {
11+
//...
12+
}
13+
814
// BAD: Does not match the exact signature required for a custom
915
// serialization protocol. Will not be called during serialization.
1016
protected void writeObject(ObjectOutputStream out) {
@@ -18,6 +24,11 @@ private void readObject(ObjectInputStream in) {
1824
//...
1925
}
2026

27+
// GOOD: Signature for a custom deserialization implementation.
28+
private void readObjectNoData() {
29+
//...
30+
}
31+
2132
// GOOD: Signature for a custom serialization implementation.
2233
private void writeObject(ObjectOutputStream out) {
2334
//...

java/ql/src/Likely Bugs/Serialization/IncorrectSerializableMethods.qhelp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,26 @@
77
<overview>
88
<p>
99
A serializable object that defines its own serialization protocol using the methods
10-
<code>readObject</code> and <code>writeObject</code> must use the signature that is expected by the
11-
Java serialization framework. Otherwise, the default serialization mechanism is used.
10+
<code>readObject</code>, <code>readObjectNoData</code> or <code>writeObject</code> must use
11+
the signature that is expected by the Java serialization framework. Otherwise, the default
12+
serialization mechanism is used.
1213
</p>
1314

1415
</overview>
1516
<recommendation>
1617
<p>
17-
Make sure that the signatures of <code>readObject</code> and <code>writeObject</code> on
18-
serializable classes use these exact signatures:
18+
Make sure that the signatures of <code>readObject</code>, <code>readObjectNoData</code> and
19+
<code>writeObject</code> on serializable classes match these expected signatures:
1920
</p>
2021

2122
<sample src="IncorrectSerializableMethodsSig.java" />
2223

2324
</recommendation>
2425
<example>
2526

26-
<p>In the following example, <code>WrongNetRequest</code> defines <code>readObject</code> and
27-
<code>writeObject</code> using the wrong signatures. However, <code>NetRequest</code> defines them
28-
correctly.</p>
27+
<p>In the following example, <code>WrongNetRequest</code> defines <code>readObject</code>,
28+
<code>readObjectNoData</code> and <code>writeObject</code> using the wrong signatures. However,
29+
<code>NetRequest</code> defines them correctly.</p>
2930

3031
<sample src="IncorrectSerializableMethods.java" />
3132

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Serialization methods do not match required signature
3-
* @description A serialized class that implements 'readObject' or 'writeObject' but does not use
4-
* the correct signatures causes the default serialization mechanism to be used.
3+
* @description A serialized class that implements 'readObject', 'readObjectNoData' or 'writeObject' but
4+
* does not use the correct signatures causes the default serialization mechanism to be used.
55
* @kind problem
66
* @problem.severity warning
77
* @precision medium
@@ -13,11 +13,20 @@
1313

1414
import java
1515

16-
from Method m, TypeSerializable serializable
16+
from Method m, TypeSerializable serializable, string reason
1717
where
18+
m.fromSource() and
1819
m.getDeclaringType().hasSupertype+(serializable) and
19-
m.getNumberOfParameters() = 1 and
20-
m.getAParameter().getType().(RefType).hasQualifiedName("java.io", "ObjectOutputStream") and
21-
(m.hasName("readObject") or m.hasName("writeObject")) and
22-
not m.isPrivate()
23-
select m, "readObject and writeObject should be private methods."
20+
(
21+
m.hasStringSignature("readObject(ObjectInputStream)") or
22+
m.hasStringSignature("readObjectNoData()") or
23+
m.hasStringSignature("writeObject(ObjectOutputStream)")
24+
) and
25+
(
26+
not m.isPrivate() and reason = "Method must be private"
27+
or
28+
m.isStatic() and reason = "Method must not be static"
29+
or
30+
not m.getReturnType() instanceof VoidType and reason = "Return type must be void"
31+
)
32+
select m, "Not recognized by Java serialization framework: " + reason
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
private void readObject(java.io.ObjectInputStream in)
22
throws IOException, ClassNotFoundException;
3+
private void readObjectNoData()
4+
throws ObjectStreamException;
35
private void writeObject(java.io.ObjectOutputStream out)
46
throws IOException;

0 commit comments

Comments
 (0)