diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll index b836f12c96f4..76a1299cb536 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll @@ -994,6 +994,18 @@ private module Cached { ) or unary_compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, areEqual, value) + or + exists(BinaryLogicalOperation logical, Expr operand, boolean b | + test.getAnInstruction().getUnconvertedResultExpression() = logical and + op.getDef().getUnconvertedResultExpression() = operand and + logical.impliesValue(operand, b, value.(BooleanValue).getValue()) + | + k = 1 and + areEqual = b + or + k = 0 and + areEqual = b.booleanNot() + ) } /** Rearrange various simple comparisons into `left == right + k` form. */ diff --git a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected index a56d8964c095..48bfb7aaf966 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected @@ -69,3 +69,11 @@ | test.cpp:168:8:168:8 | b | | test.cpp:176:7:176:8 | ! ... | | test.cpp:176:8:176:8 | c | +| test.cpp:182:6:182:16 | ! ... | +| test.cpp:182:8:182:9 | b1 | +| test.cpp:182:8:182:15 | ... && ... | +| test.cpp:182:14:182:15 | b2 | +| test.cpp:193:6:193:16 | ! ... | +| test.cpp:193:8:193:9 | b1 | +| test.cpp:193:8:193:15 | ... \|\| ... | +| test.cpp:193:14:193:15 | b2 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected index f2ce7f611f39..2ff93603a267 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected @@ -545,8 +545,12 @@ | 182 | ! ... == 1 when ... && ... is false | | 182 | ... && ... != 0 when ! ... is false | | 182 | ... && ... != 0 when ... && ... is true | +| 182 | ... && ... != 1 when ! ... is true | +| 182 | ... && ... != 1 when ... && ... is false | | 182 | ... && ... == 0 when ! ... is true | | 182 | ... && ... == 0 when ... && ... is false | +| 182 | ... && ... == 1 when ! ... is false | +| 182 | ... && ... == 1 when ... && ... is true | | 182 | ... < ... != 0 when ... && ... is true | | 182 | ... < ... != 0 when ... < ... is true | | 182 | ... < ... != 1 when ... < ... is false | @@ -559,6 +563,22 @@ | 182 | ... >= ... == 0 when ... >= ... is false | | 182 | ... >= ... == 1 when ... && ... is true | | 182 | ... >= ... == 1 when ... >= ... is true | +| 182 | b1 != 0 when ! ... is false | +| 182 | b1 != 0 when ... && ... is true | +| 182 | b1 != 0 when b1 is true | +| 182 | b1 != 1 when b1 is false | +| 182 | b1 == 0 when b1 is false | +| 182 | b1 == 1 when ! ... is false | +| 182 | b1 == 1 when ... && ... is true | +| 182 | b1 == 1 when b1 is true | +| 182 | b2 != 0 when ! ... is false | +| 182 | b2 != 0 when ... && ... is true | +| 182 | b2 != 0 when b2 is true | +| 182 | b2 != 1 when b2 is false | +| 182 | b2 == 0 when b2 is false | +| 182 | b2 == 1 when ! ... is false | +| 182 | b2 == 1 when ... && ... is true | +| 182 | b2 == 1 when b2 is true | | 182 | foo < 1.0+0 when ... && ... is true | | 182 | foo < 1.0+0 when ... < ... is true | | 182 | foo < 9.999999999999999547e-07+0 when ... >= ... is false | @@ -577,6 +597,38 @@ | 190 | c != 0 when c is true | | 190 | c == 0 when ! ... is true | | 190 | c == 0 when c is false | +| 193 | ! ... != 0 when ! ... is true | +| 193 | ! ... != 0 when ... \|\| ... is false | +| 193 | ! ... != 1 when ! ... is false | +| 193 | ! ... != 1 when ... \|\| ... is true | +| 193 | ! ... == 0 when ! ... is false | +| 193 | ! ... == 0 when ... \|\| ... is true | +| 193 | ! ... == 1 when ! ... is true | +| 193 | ! ... == 1 when ... \|\| ... is false | +| 193 | ... \|\| ... != 0 when ! ... is false | +| 193 | ... \|\| ... != 0 when ... \|\| ... is true | +| 193 | ... \|\| ... != 1 when ! ... is true | +| 193 | ... \|\| ... != 1 when ... \|\| ... is false | +| 193 | ... \|\| ... == 0 when ! ... is true | +| 193 | ... \|\| ... == 0 when ... \|\| ... is false | +| 193 | ... \|\| ... == 1 when ! ... is false | +| 193 | ... \|\| ... == 1 when ... \|\| ... is true | +| 193 | b1 != 0 when b1 is true | +| 193 | b1 != 1 when ! ... is true | +| 193 | b1 != 1 when ... \|\| ... is false | +| 193 | b1 != 1 when b1 is false | +| 193 | b1 == 0 when ! ... is true | +| 193 | b1 == 0 when ... \|\| ... is false | +| 193 | b1 == 0 when b1 is false | +| 193 | b1 == 1 when b1 is true | +| 193 | b2 != 0 when b2 is true | +| 193 | b2 != 1 when ! ... is true | +| 193 | b2 != 1 when ... \|\| ... is false | +| 193 | b2 != 1 when b2 is false | +| 193 | b2 == 0 when ! ... is true | +| 193 | b2 == 0 when ... \|\| ... is false | +| 193 | b2 == 0 when b2 is false | +| 193 | b2 == 1 when b2 is true | | 198 | ! ... != 0 when ! ... is true | | 198 | ! ... != 0 when b is false | | 198 | ! ... != 1 when ! ... is false | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected index 2857bdf511bf..cee020adadd9 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected @@ -130,3 +130,19 @@ | test.cpp:168:8:168:8 | b | false | 168 | 170 | | test.cpp:176:7:176:8 | ! ... | true | 176 | 178 | | test.cpp:176:8:176:8 | c | false | 176 | 178 | +| test.cpp:182:6:182:16 | ! ... | false | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | true | 182 | 184 | +| test.cpp:182:8:182:9 | b1 | true | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | true | 182 | 182 | +| test.cpp:182:8:182:15 | ... && ... | false | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | true | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | true | 185 | 188 | +| test.cpp:182:14:182:15 | b2 | true | 181 | 182 | +| test.cpp:193:6:193:16 | ! ... | false | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | true | 193 | 196 | +| test.cpp:193:8:193:9 | b1 | false | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | false | 193 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | false | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | false | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | true | 197 | 199 | +| test.cpp:193:14:193:15 | b2 | false | 192 | 193 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected index 73a809b3175c..288b49ceb687 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected @@ -636,3 +636,79 @@ unary | test.cpp:176:8:176:8 | c | test.cpp:176:7:176:8 | ! ... | == | 1 | 176 | 178 | | test.cpp:176:8:176:8 | c | test.cpp:176:8:176:8 | c | != | 1 | 176 | 178 | | test.cpp:176:8:176:8 | c | test.cpp:176:8:176:8 | c | == | 0 | 176 | 178 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | != | 0 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 1 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:9 | b1 | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:9 | b1 | == | 1 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 1 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 0 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:14:182:15 | b2 | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:14:182:15 | b2 | == | 1 | 185 | 188 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 182 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | == | 1 | 182 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 0 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 1 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | == | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 1 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 0 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | == | 1 | 185 | 188 | +| test.cpp:182:14:182:15 | b2 | test.cpp:182:14:182:15 | b2 | != | 0 | 181 | 182 | +| test.cpp:182:14:182:15 | b2 | test.cpp:182:14:182:15 | b2 | == | 1 | 181 | 182 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | != | 1 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 0 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 0 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 1 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:14:193:15 | b2 | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:14:193:15 | b2 | == | 0 | 193 | 196 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 1 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 0 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 0 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 1 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | == | 0 | 193 | 196 | +| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | != | 1 | 192 | 193 | +| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | == | 0 | 192 | 193 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/test.cpp b/cpp/ql/test/library-tests/controlflow/guards/test.cpp index 3bdcdcc01ff5..7349671633d4 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/test.cpp +++ b/cpp/ql/test/library-tests/controlflow/guards/test.cpp @@ -176,4 +176,26 @@ void test_with_negated_binary_relational(int a, int b) { if (!c) { } +} + +void test_logical_and(bool b1, bool b2) { + if(!(b1 && b2)) { + use(b1); + use(b2); + } else { + // b1 = true and b2 = true + use(b1); + use(b2); + } +} + +void test_logical_or(bool b1, bool b2) { + if(!(b1 || b2)) { + // b1 = false and b2 = false + use(b1); + use(b2); + } else { + use(b1); + use(b2); + } } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp index 20beabf8c932..a67fa4cdb425 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp @@ -68,3 +68,10 @@ int templateClassContext :: val = MACRO_TEMPLATECLASSCONTEXT_REFERENCED; #define INSTANTIATION templateClassContext tcci; + +#define BAR + +#if defined(BAR) && \ + defined(BAR) +#warning BAR defined +#endif diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h index 288442716b52..780caa66d9ff 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h @@ -4,15 +4,15 @@ //#pragma byte_order(big_endian) #warning "Not in Kansas any more" -//#define MULTILINE \ +#define MULTILINE \ /* Hello */ \ world \ /* from */ \ a long \ /* macro */ -//#undef \ +#undef \ MULTILINE -//#include \ - \ +#include \ + "pp.h" \ \ diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected b/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected index cff0dd489eaa..dd8696b31650 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected @@ -27,6 +27,13 @@ | pp.cpp:0:0:0:0 | pp.cpp | 60 | 3 | 60 | 21 | Macro | IN_TEMPLATE | | | pp.cpp:0:0:0:0 | pp.cpp | 61 | 1 | 61 | 7 | PreprocessorEndif | N/A | N/A | | pp.cpp:0:0:0:0 | pp.cpp | 69 | 1 | 69 | 21 | Macro | INSTANTIATION | | +| pp.cpp:0:0:0:0 | pp.cpp | 72 | 1 | 72 | 11 | Macro | BAR | | +| pp.cpp:0:0:0:0 | pp.cpp | 74 | 1 | 74 | 21 | PreprocessorIf | defined(BAR) && \\ | N/A | +| pp.cpp:0:0:0:0 | pp.cpp | 76 | 1 | 76 | 20 | PreprocessorWarning | BAR defined | N/A | +| pp.cpp:0:0:0:0 | pp.cpp | 77 | 1 | 77 | 6 | PreprocessorEndif | N/A | N/A | | pp.h:0:0:0:0 | pp.h | 1 | 1 | 1 | 12 | PreprocessorPragma | once | N/A | | pp.h:0:0:0:0 | pp.h | 3 | 1 | 3 | 27 | PreprocessorLine | 33 "emerald_city.h" | N/A | | pp.h:0:0:0:0 | pp.h | 5 | 1 | 5 | 33 | PreprocessorWarning | "Not in Kansas any more" | N/A | +| pp.h:0:0:0:0 | pp.h | 7 | 1 | 11 | 8 | Macro | MULTILINE | world a long | +| pp.h:0:0:0:0 | pp.h | 13 | 1 | 14 | 11 | PreprocessorUndef | MULTILINE | N/A | +| pp.h:0:0:0:0 | pp.h | 16 | 1 | 17 | 8 | Include | "pp.h" | N/A | diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 4b584a4c7953..20f4b216b64c 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index eb8f861f9358..e0d5ce240a39 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected index eb8f861f9358..e0d5ce240a39 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | diff --git a/rust/ql/src/queries/summary/CryptographicOperations.ql b/rust/ql/src/queries/summary/CryptographicOperations.ql new file mode 100644 index 000000000000..3b4c03c40fd2 --- /dev/null +++ b/rust/ql/src/queries/summary/CryptographicOperations.ql @@ -0,0 +1,59 @@ +/** + * @name Cryptographic Operations + * @description List all cryptographic operations found in the database. + * @kind problem + * @problem.severity info + * @id rust/summary/cryptographic-operations + * @tags summary + */ + +import rust +import codeql.rust.Concepts +import codeql.rust.security.WeakSensitiveDataHashingExtensions + +/** + * Gets the type of cryptographic algorithm `alg`. + */ +string getAlgorithmType(Cryptography::CryptographicAlgorithm alg) { + alg instanceof Cryptography::EncryptionAlgorithm and result = "EncryptionAlgorithm" + or + alg instanceof Cryptography::HashingAlgorithm and result = "HashingAlgorithm" + or + alg instanceof Cryptography::PasswordHashingAlgorithm and result = "PasswordHashingAlgorithm" +} + +/** + * Gets a feature of cryptographic algorithm `alg`. + */ +string getAlgorithmFeature(Cryptography::CryptographicAlgorithm alg) { + alg.isWeak() and result = "WEAK" +} + +/** + * Gets a description of cryptographic algorithm `alg`. + */ +string describeAlgorithm(Cryptography::CryptographicAlgorithm alg) { + result = + getAlgorithmType(alg) + " " + alg.getName() + " " + concat(getAlgorithmFeature(alg), ", ") +} + +/** + * Gets a feature of cryptographic operation `op`. + */ +string getOperationFeature(Cryptography::CryptographicOperation op) { + result = "inputs:" + strictcount(op.getAnInput()).toString() or + result = "blockmodes:" + strictcount(op.getBlockMode()).toString() +} + +/** + * Gets a description of cryptographic operation `op`. + */ +string describeOperation(Cryptography::CryptographicOperation op) { + result = describeAlgorithm(op.getAlgorithm()) + " " + concat(getOperationFeature(op), ", ") + or + not exists(op.getAlgorithm()) and + result = "(unknown) " + concat(getOperationFeature(op), ", ") +} + +from Cryptography::CryptographicOperation operation +select operation, describeOperation(operation) diff --git a/rust/ql/src/queries/summary/QuerySinkCounts.ql b/rust/ql/src/queries/summary/QuerySinkCounts.ql new file mode 100644 index 000000000000..6525c3263a11 --- /dev/null +++ b/rust/ql/src/queries/summary/QuerySinkCounts.ql @@ -0,0 +1,17 @@ +/** + * @name Query Sink Counts + * @description Lists the number of query sinks of each type found in the database. Query sinks are + * flow sinks that are used as possible locations for query results. Cryptographic + * operations are excluded. + * @kind metric + * @id rust/summary/query-sink-counts + * @tags summary + */ + +import rust +import codeql.rust.dataflow.DataFlow +import Stats + +from string kind, int num +where num = strictcount(DataFlow::Node n | getAQuerySinkKind(n) = kind) +select kind, num diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql new file mode 100644 index 000000000000..09cd7fcb2991 --- /dev/null +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -0,0 +1,17 @@ +/** + * @name Query Sinks + * @description Lists query sinks that are found in the database. Query sinks are flow sinks that + * are used as possible locations for query results. Cryptographic operations are + * excluded (see `rust/summary/cryptographic-operations` instead). + * @kind problem + * @problem.severity info + * @id rust/summary/query-sinks + * @tags summary + */ + +import rust +import codeql.rust.dataflow.DataFlow +import Stats + +from DataFlow::Node n +select n, "Sink for " + strictconcat(getAQuerySinkKind(n), ", ") + "." diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index c2993b47899f..8bdb25381bc6 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -3,11 +3,13 @@ */ import rust +private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.dataflow.internal.TaintTrackingImpl private import codeql.rust.AstConsistency as AstConsistency private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency +private import codeql.rust.security.SqlInjectionExtensions /** * Gets a count of the total number of lines of code in the database. @@ -41,3 +43,25 @@ int getTotalCfgInconsistencies() { int getTotalDataFlowInconsistencies() { result = sum(string type | | DataFlowConsistency::getInconsistencyCounts(type)) } + +/** + * Gets the total number of taint edges in the database. + */ +int getTaintEdgesCount() { + result = + count(DataFlow::Node a, DataFlow::Node b | + RustTaintTracking::defaultAdditionalTaintStep(a, b, _) + ) +} + +/** + * Gets a kind of query for which `n` is a sink (if any). + */ +string getAQuerySinkKind(DataFlow::Node n) { + (n instanceof SqlInjection::Sink and result = "SqlInjection") +} + +/** + * Gets a count of the total number of query sinks in the database. + */ +int getQuerySinksCount() { result = count(DataFlow::Node n | exists(getAQuerySinkKind(n))) } diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 005233f87cf3..4e14045428f2 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -9,8 +9,10 @@ import rust import codeql.rust.Concepts import codeql.rust.security.SensitiveData +import codeql.rust.security.WeakSensitiveDataHashingExtensions import codeql.rust.Diagnostics import Stats +import TaintReach from string key, int value where @@ -54,9 +56,21 @@ where or key = "Macro calls - unresolved" and value = count(MacroCall mc | not mc.hasExpanded()) or - key = "Taint sources - total" and value = count(ThreatModelSource s) - or key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or - key = "Sensitive data" and value = count(SensitiveData d) + key = "Taint sources - disabled" and + value = count(ThreatModelSource s | not s instanceof ActiveThreatModelSource) + or + key = "Taint sources - sensitive data" and value = count(SensitiveData d) + or + key = "Taint edges - number of edges" and value = getTaintEdgesCount() + or + key = "Taint reach - nodes tainted" and value = getTaintedNodesCount() + or + key = "Taint reach - per million nodes" and value = getTaintReach().floor() + or + key = "Taint sinks - query sinks" and value = getQuerySinksCount() + or + key = "Taint sinks - cryptographic operations" and + value = count(Cryptography::CryptographicOperation o) select key, value order by key diff --git a/rust/ql/src/queries/summary/TaintReach.qll b/rust/ql/src/queries/summary/TaintReach.qll new file mode 100644 index 000000000000..0f00fe6f7c6e --- /dev/null +++ b/rust/ql/src/queries/summary/TaintReach.qll @@ -0,0 +1,31 @@ +/** + * Taint reach computation. Taint reach is the proportion of all dataflow nodes that can be reached + * via taint flow from any active thread model source. It's usually expressed per million nodes. + */ + +import rust +private import codeql.rust.Concepts +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.TaintTracking + +/** + * A taint configuration for taint reach (flow to any node from any modeled source). + */ +private module TaintReachConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node instanceof ActiveThreatModelSource } + + predicate isSink(DataFlow::Node node) { any() } +} + +private module TaintReachFlow = TaintTracking::Global; + +/** + * Gets the total number of data flow nodes that taint reaches (from any source). + */ +int getTaintedNodesCount() { result = count(DataFlow::Node n | TaintReachFlow::flowTo(n)) } + +/** + * Gets the proportion of data flow nodes that taint reaches (from any source), + * expressed as a count per million nodes. + */ +float getTaintReach() { result = (getTaintedNodesCount() * 1000000.0) / count(DataFlow::Node n) } diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 78bfeb9322c7..5223601d625f 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 8 | | Macro calls - total | 9 | | Macro calls - unresolved | 1 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 |