@@ -21,6 +21,40 @@ private predicate predictableInstruction(Instruction instr) {
2121 predictableInstruction ( instr .( UnaryInstruction ) .getUnary ( ) )
2222}
2323
24+ /**
25+ * Functions that we should only allow taint to flow through (to the return
26+ * value) if all but the source argument are 'predictable'. This is done to
27+ * emulate the old security library's implementation rather than due to any
28+ * strong belief that this is the right approach.
29+ *
30+ * Note that the list itself is not very principled; it consists of all the
31+ * functions listed in the old security library's [default] `isPureFunction`
32+ * that have more than one argument, but are not in the old taint tracking
33+ * library's `returnArgument` predicate. In addition, `strlen` is included
34+ * because it's also a special case in flow to return values.
35+ */
36+ predicate predictableOnlyFlow ( string name ) {
37+ name = "strcasestr" or
38+ name = "strchnul" or
39+ name = "strchr" or
40+ name = "strchrnul" or
41+ name = "strcmp" or
42+ name = "strcspn" or
43+ name = "strlen" or // special case
44+ name = "strncmp" or
45+ name = "strndup" or
46+ name = "strnlen" or
47+ name = "strrchr" or
48+ name = "strspn" or
49+ name = "strstr" or
50+ name = "strtod" or
51+ name = "strtof" or
52+ name = "strtol" or
53+ name = "strtoll" or
54+ name = "strtoq" or
55+ name = "strtoul"
56+ }
57+
2458private DataFlow:: Node getNodeForSource ( Expr source ) {
2559 isUserInput ( source , _) and
2660 (
@@ -123,15 +157,16 @@ private predicate nodeIsBarrier(DataFlow::Node node) {
123157
124158private predicate instructionTaintStep ( Instruction i1 , Instruction i2 ) {
125159 // Expressions computed from tainted data are also tainted
126- i2 =
127- any ( CallInstruction call |
128- isPureFunction ( call .getStaticCallTarget ( ) .getName ( ) ) and
129- call .getAnArgument ( ) = i1 and
130- forall ( Instruction arg | arg = call .getAnArgument ( ) | arg = i1 or predictableInstruction ( arg ) ) and
131- // flow through `strlen` tends to cause dubious results, if the length is
132- // bounded.
133- not call .getStaticCallTarget ( ) .getName ( ) = "strlen"
134- )
160+ exists ( CallInstruction call , int argIndex | call = i2 |
161+ isPureFunction ( call .getStaticCallTarget ( ) .getName ( ) ) and
162+ i1 = getACallArgumentOrIndirection ( call , argIndex ) and
163+ forall ( Instruction arg | arg = call .getAnArgument ( ) |
164+ arg = getACallArgumentOrIndirection ( call , argIndex ) or predictableInstruction ( arg )
165+ ) and
166+ // flow through `strlen` tends to cause dubious results, if the length is
167+ // bounded.
168+ not call .getStaticCallTarget ( ) .getName ( ) = "strlen"
169+ )
135170 or
136171 // Flow through pointer dereference
137172 i2 .( LoadInstruction ) .getSourceAddress ( ) = i1
@@ -172,7 +207,8 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
172207 any ( CallInstruction call |
173208 exists ( int indexIn |
174209 modelTaintToReturnValue ( call .getStaticCallTarget ( ) , indexIn ) and
175- i1 = getACallArgumentOrIndirection ( call , indexIn )
210+ i1 = getACallArgumentOrIndirection ( call , indexIn ) and
211+ not predictableOnlyFlow ( call .getStaticCallTarget ( ) .getName ( ) )
176212 )
177213 )
178214 or
0 commit comments