From 5a4a63f8a93019119f81cbed3b466b16de338802 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Mon, 30 Jan 2023 18:52:35 -0500 Subject: [PATCH 001/219] Create IfStatementAdditionOverflow.ql --- .../CWE-190/IfStatementAdditionOverflow.ql | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql new file mode 100644 index 00000000000..4763504ca0d --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -0,0 +1,28 @@ +/** + * @name Integer addition may overflow inside if statement + * @description Detects "if (a+b>c) a=c-b", which is incorrect if a+b overflows. + * Should be replaced by "if (a>c-b) a=c-b", which correctly + * implements a = min(a,c-b)". This integer overflow is the root + * cause of the buffer overflow in the SHA-3 reference implementation + * (CVE-2022-37454). + * @kind problem + * @problem.severity warning + * @id cpp/if-statement-addition-overflow + * @tags: experimental + * correctness + * security + * external/cwe/cwe-190 + */ + +import cpp + +from IfStmt ifstmt, GTExpr gtexpr, ExprStmt exprstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr +where ifstmt.getCondition() = gtexpr and + gtexpr.getLeftOperand() = addexpr and + ifstmt.getThen() = exprstmt and + exprstmt.getExpr() = assignexpr and + assignexpr.getRValue() = subexpr and + addexpr.getLeftOperand().toString() = assignexpr.getLValue().toString() and + addexpr.getRightOperand().toString() = subexpr.getRightOperand().toString() and + gtexpr.getRightOperand().toString() = subexpr.getLeftOperand().toString() +select ifstmt, "Integer addition may overflow inside if statement." From f577a04eabd6f8a3f899647298534f445a4f2061 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sat, 18 Feb 2023 21:34:03 -0500 Subject: [PATCH 002/219] Update IfStatementAdditionOverflow.ql --- .../CWE-190/IfStatementAdditionOverflow.ql | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql index 4763504ca0d..cbfc2fc7f90 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -1,10 +1,13 @@ /** - * @name Integer addition may overflow inside if statement - * @description Detects "if (a+b>c) a=c-b", which is incorrect if a+b overflows. - * Should be replaced by "if (a>c-b) a=c-b", which correctly - * implements a = min(a,c-b)". This integer overflow is the root - * cause of the buffer overflow in the SHA-3 reference implementation - * (CVE-2022-37454). + * @name Integer addition may overflow inside condition + * @description Detects "c-b" when the condition "a+b>c" has been imposed, + * which is not the same as the condition "a>b-c" if "a+b" + * overflows. Rewriting improves readability and optimizability + * (CSE elimination). Also detects "b+a>c" (swapped terms in + * addition), "c=", "<", + * "<=" instead of ">" (all operators). This integer overflow + * is the root cause of the buffer overflow in the SHA-3 + * reference implementation (CVE-2022-37454). * @kind problem * @problem.severity warning * @id cpp/if-statement-addition-overflow @@ -15,14 +18,19 @@ */ import cpp +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.commons.Exclusions -from IfStmt ifstmt, GTExpr gtexpr, ExprStmt exprstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr -where ifstmt.getCondition() = gtexpr and - gtexpr.getLeftOperand() = addexpr and - ifstmt.getThen() = exprstmt and - exprstmt.getExpr() = assignexpr and - assignexpr.getRValue() = subexpr and - addexpr.getLeftOperand().toString() = assignexpr.getLValue().toString() and - addexpr.getRightOperand().toString() = subexpr.getRightOperand().toString() and - gtexpr.getRightOperand().toString() = subexpr.getLeftOperand().toString() -select ifstmt, "Integer addition may overflow inside if statement." +from GuardCondition guard, BasicBlock block, RelationalOperation relop, AddExpr addexpr, SubExpr subexpr +where guard.controls(block, _) and + guard.getAChild*() = relop and + pragma[only_bind_into](block) = subexpr.getBasicBlock() and + relop.getAnOperand() = addexpr and + addexpr.getUnspecifiedType() instanceof IntegralType and + not isFromMacroDefinition(relop) and + exprMightOverflowPositively(addexpr) and + globalValueNumber(addexpr.getAnOperand()) = globalValueNumber(subexpr.getRightOperand()) and + globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) +select guard, "Integer addition may overflow inside condition." From ed75172bdd555587fd9b74ebc812c1c347c51ec1 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Tue, 21 Feb 2023 18:11:22 -0500 Subject: [PATCH 003/219] Update IfStatementAdditionOverflow.ql --- .../CWE-190/IfStatementAdditionOverflow.ql | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql index cbfc2fc7f90..5bfa265fca5 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -1,13 +1,13 @@ /** - * @name Integer addition may overflow inside condition - * @description Detects "c-b" when the condition "a+b>c" has been imposed, - * which is not the same as the condition "a>b-c" if "a+b" - * overflows. Rewriting improves readability and optimizability - * (CSE elimination). Also detects "b+a>c" (swapped terms in - * addition), "c=", "<", - * "<=" instead of ">" (all operators). This integer overflow - * is the root cause of the buffer overflow in the SHA-3 - * reference implementation (CVE-2022-37454). + * @name Integer addition may overflow inside if statement + * @description Detects "if (a+b>c) a=c-b", which incorrectly implements + * a = min(a,c-b) if a+b overflows. Should be replaced by + * "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b" + * (swapped terms in addition), if (a+b>c) { a=c-b }" + * (assignment inside block), "c=", "<", "<=" instead of ">" (all operators). This + * integer overflow is the root cause of the buffer overflow + * in the SHA-3 reference implementation (CVE-2022-37454). * @kind problem * @problem.severity warning * @id cpp/if-statement-addition-overflow @@ -18,19 +18,27 @@ */ import cpp -import semmle.code.cpp.controlflow.Guards import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.valuenumbering.HashCons import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.commons.Exclusions -from GuardCondition guard, BasicBlock block, RelationalOperation relop, AddExpr addexpr, SubExpr subexpr -where guard.controls(block, _) and - guard.getAChild*() = relop and - pragma[only_bind_into](block) = subexpr.getBasicBlock() and +from IfStmt ifstmt, RelationalOperation relop, ExprStmt exprstmt, BlockStmt blockstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr +where ifstmt.getCondition() = relop and relop.getAnOperand() = addexpr and addexpr.getUnspecifiedType() instanceof IntegralType and + subexpr.getUnspecifiedType() instanceof IntegralType and not isFromMacroDefinition(relop) and exprMightOverflowPositively(addexpr) and - globalValueNumber(addexpr.getAnOperand()) = globalValueNumber(subexpr.getRightOperand()) and - globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) -select guard, "Integer addition may overflow inside condition." + (ifstmt.getThen() = exprstmt or + (ifstmt.getThen() = blockstmt and + blockstmt.getAStmt() = exprstmt)) and + exprstmt.getExpr() = assignexpr and + assignexpr.getRValue() = subexpr and + ((hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and + globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())) or + (hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and + globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand()))) and + globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) and + not globalValueNumber(addexpr.getAnOperand()) = globalValueNumber(relop.getAnOperand()) +select ifstmt, "Integer addition may overflow inside if statement." From 08f04d53864d461155e536c5e86326864607eb43 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Thu, 23 Feb 2023 17:50:02 -0500 Subject: [PATCH 004/219] Update IfStatementAdditionOverflow.ql --- .../CWE/CWE-190/IfStatementAdditionOverflow.ql | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql index 5bfa265fca5..20e77bb5ec0 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -1,13 +1,8 @@ /** * @name Integer addition may overflow inside if statement - * @description Detects "if (a+b>c) a=c-b", which incorrectly implements - * a = min(a,c-b) if a+b overflows. Should be replaced by - * "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b" - * (swapped terms in addition), if (a+b>c) { a=c-b }" - * (assignment inside block), "c=", "<", "<=" instead of ">" (all operators). This - * integer overflow is the root cause of the buffer overflow - * in the SHA-3 reference implementation (CVE-2022-37454). + * @description "if (a+b>c) a=c-b" was detected where "a+b" may potentially + * produce an integer overflow (or wraparound). The code can be + * rewritten to "if (a>c-b) a=c-b" which avoids the overflow. * @kind problem * @problem.severity warning * @id cpp/if-statement-addition-overflow @@ -27,7 +22,6 @@ from IfStmt ifstmt, RelationalOperation relop, ExprStmt exprstmt, BlockStmt bloc where ifstmt.getCondition() = relop and relop.getAnOperand() = addexpr and addexpr.getUnspecifiedType() instanceof IntegralType and - subexpr.getUnspecifiedType() instanceof IntegralType and not isFromMacroDefinition(relop) and exprMightOverflowPositively(addexpr) and (ifstmt.getThen() = exprstmt or @@ -39,6 +33,5 @@ where ifstmt.getCondition() = relop and globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())) or (hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand()))) and - globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) and - not globalValueNumber(addexpr.getAnOperand()) = globalValueNumber(relop.getAnOperand()) + globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) select ifstmt, "Integer addition may overflow inside if statement." From dc09c9218ebb4bcb3f84797239a4028023804b1e Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 01:05:18 -0500 Subject: [PATCH 005/219] Update IfStatementAdditionOverflow.ql --- .../CWE/CWE-190/IfStatementAdditionOverflow.ql | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql index 20e77bb5ec0..a45ba737bab 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -1,8 +1,13 @@ /** * @name Integer addition may overflow inside if statement - * @description "if (a+b>c) a=c-b" was detected where "a+b" may potentially - * produce an integer overflow (or wraparound). The code can be - * rewritten to "if (a>c-b) a=c-b" which avoids the overflow. + * @description Detects "if (a+b>c) a=c-b", which incorrectly implements + * a = min(a,c-b) if a+b overflows. Should be replaced by + * "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b" + * (swapped terms in addition), if (a+b>c) { a=c-b }" + * (assignment inside block), "c=", "<", "<=" instead of ">" (all operators). This + * integer overflow is the root cause of the buffer overflow + * in the SHA-3 reference implementation (CVE-2022-37454). * @kind problem * @problem.severity warning * @id cpp/if-statement-addition-overflow @@ -34,4 +39,4 @@ where ifstmt.getCondition() = relop and (hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand()))) and globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) -select ifstmt, "Integer addition may overflow inside if statement." +select ifstmt, "\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.", addexpr, "addition" From 91a9a7eb32d3e4a0ea73eeb0d092861a4161f0c7 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 01:13:32 -0500 Subject: [PATCH 006/219] Create test.cpp --- .../IfStatementAdditionOverflow/test.cpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp new file mode 100644 index 00000000000..ca67c5578c7 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp @@ -0,0 +1,59 @@ + +int getAnInt(); +double getADouble(); +unsigned short getAnUnsignedShort(); + +void test() +{ + int a = getAnInt(); + int b = getAnInt(); + int c = getAnInt(); + int x = getAnInt(); + int y = getAnInt(); + int d = getADouble(); + int a1 = getAnUnsignedShort(); + int b1 = getAnUnsignedShort(); + int c1 = getAnUnsignedShort(); + + if (a+b>c) a = c-b; // BAD + if (a+b>c) { a = c-b; } // BAD + if (b+a>c) a = c-b; // BAD + if (b+a>c) { a = c-b; } // BAD + if (c>a+b) a = c-b; // BAD + if (c>a+b) { a = c-b; } // BAD + if (c>b+a) a = c-b; // BAD + if (c>b+a) { a = c-b; } // BAD + + if (a+b>=c) a = c-b; // BAD + if (a+b>=c) { a = c-b; } // BAD + if (b+a>=c) a = c-b; // BAD + if (b+a>=c) { a = c-b; } // BAD + if (c>=a+b) a = c-b; // BAD + if (c>=a+b) { a = c-b; } // BAD + if (c>=b+a) a = c-b; // BAD + if (c>=b+a) { a = c-b; } // BAD + + if (a+bd) a = d-b; // GOOD + if (a+(-x)>c) a = c-(-y); // GOOD + if (a+b>c) { b++; a = c-b; } // GOOD + if (a+d>c) a = c-d; // GOOD + if (a1+b1>c1) a1 = c1-b1; // GOOD +} From 2477c3a1c26d86c3b6c30c45fe8735f264bb5426 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 03:25:52 -0400 Subject: [PATCH 007/219] Update test.cpp --- .../CWE/CWE-190/IfStatementAdditionOverflow/test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp index ca67c5578c7..47c077a3c9b 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp @@ -8,12 +8,12 @@ void test() int a = getAnInt(); int b = getAnInt(); int c = getAnInt(); - int x = getAnInt(); + int x = getAnInt(); int y = getAnInt(); - int d = getADouble(); - int a1 = getAnUnsignedShort(); - int b1 = getAnUnsignedShort(); - int c1 = getAnUnsignedShort(); + double d = getADouble(); + unsigned short a1 = getAnUnsignedShort(); + unsigned short b1 = getAnUnsignedShort(); + unsigned short c1 = getAnUnsignedShort(); if (a+b>c) a = c-b; // BAD if (a+b>c) { a = c-b; } // BAD @@ -51,7 +51,7 @@ void test() if (c<=b+a) a = c-b; // BAD if (c<=b+a) { a = c-b; } // BAD - if (a+b>d) a = d-b; // GOOD + if (a+b>d) a = d-b; // BAD if (a+(-x)>c) a = c-(-y); // GOOD if (a+b>c) { b++; a = c-b; } // GOOD if (a+d>c) a = c-d; // GOOD From 59c1ae7734bb18431006c40841904cf132c95815 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 03:27:10 -0400 Subject: [PATCH 008/219] Update test.cpp --- .../Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp index 47c077a3c9b..5879a7ca2a3 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp @@ -8,7 +8,7 @@ void test() int a = getAnInt(); int b = getAnInt(); int c = getAnInt(); - int x = getAnInt(); + int x = getAnInt(); int y = getAnInt(); double d = getADouble(); unsigned short a1 = getAnUnsignedShort(); From 66710ad5a03fa6b1d60f08f6a90c297aa7835299 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 03:30:26 -0400 Subject: [PATCH 009/219] Create IfStatementAdditionOverflow.qlref --- .../IfStatementAdditionOverflow.qlref | 1 + 1 file changed, 1 insertion(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.qlref diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.qlref new file mode 100644 index 00000000000..0873051581d --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql From a2b5fbf24c72f9b810f2ede79ba997c4b047aa17 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Sun, 12 Mar 2023 03:31:48 -0400 Subject: [PATCH 010/219] Create IfStatementAdditionOverflow.expected --- .../IfStatementAdditionOverflow.expected | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected new file mode 100644 index 00000000000..12dbde04790 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected @@ -0,0 +1,33 @@ +| test.cpp:18:2:18:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition | +| test.cpp:19:2:19:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition | +| test.cpp:20:2:20:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition | +| test.cpp:21:2:21:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition | +| test.cpp:22:2:22:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition | +| test.cpp:23:2:23:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition | +| test.cpp:24:2:24:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition | +| test.cpp:25:2:25:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition | +| test.cpp:27:2:27:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition | +| test.cpp:28:2:28:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition | +| test.cpp:29:2:29:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition | +| test.cpp:30:2:30:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition | +| test.cpp:31:2:31:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition | +| test.cpp:32:2:32:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition | +| test.cpp:33:2:33:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition | +| test.cpp:34:2:34:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition | +| test.cpp:36:2:36:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition | +| test.cpp:37:2:37:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition | +| test.cpp:38:2:38:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition | +| test.cpp:39:2:39:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition | +| test.cpp:40:2:40:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition | +| test.cpp:41:2:41:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition | +| test.cpp:42:2:42:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition | +| test.cpp:43:2:43:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition | +| test.cpp:45:2:45:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition | +| test.cpp:46:2:46:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition | +| test.cpp:47:2:47:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition | +| test.cpp:48:2:48:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition | +| test.cpp:49:2:49:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition | +| test.cpp:50:2:50:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition | +| test.cpp:51:2:51:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition | +| test.cpp:52:2:52:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition | +| test.cpp:54:2:54:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition | From 2de0e2209edde14d3fb930e44eb1d879e499fc80 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Thu, 16 Mar 2023 02:34:40 -0400 Subject: [PATCH 011/219] Update test.cpp --- .../Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp index 5879a7ca2a3..f1aac83122b 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp @@ -52,6 +52,7 @@ void test() if (c<=b+a) { a = c-b; } // BAD if (a+b>d) a = d-b; // BAD + if (a+(double)b>c) a = c-b; // GOOD if (a+(-x)>c) a = c-(-y); // GOOD if (a+b>c) { b++; a = c-b; } // GOOD if (a+d>c) a = c-d; // GOOD From 6a3d995b357ff0a39c65fd5c3b534dc0da268f89 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Sat, 6 May 2023 12:25:25 +0200 Subject: [PATCH 012/219] Add Mysql2 as SQL Injection Sink --- ruby/ql/lib/change-notes/2023-05-06-mysql2.md | 4 ++ ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll | 49 +++++++++++++++++++ .../security/SqlInjectionCustomizations.qll | 22 ++++++++- .../frameworks/mysql2/Mysql2.expected | 5 ++ .../library-tests/frameworks/mysql2/Mysql2.ql | 5 ++ .../library-tests/frameworks/mysql2/Mysql2.rb | 30 ++++++++++++ 6 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 ruby/ql/lib/change-notes/2023-05-06-mysql2.md create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll create mode 100644 ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.expected create mode 100644 ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.ql create mode 100644 ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb diff --git a/ruby/ql/lib/change-notes/2023-05-06-mysql2.md b/ruby/ql/lib/change-notes/2023-05-06-mysql2.md new file mode 100644 index 00000000000..d8fa92dd394 --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-05-06-mysql2.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Support for the `mysql2` gem has been added. Method calls that execute queries against an MySQL database that may be vulnerable to injection attacks will now be recognized. \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll new file mode 100644 index 00000000000..efea7383a4c --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll @@ -0,0 +1,49 @@ +/** + * Provides modeling for mysql2, a Ruby library (gem) for interacting with MySql databases. + */ + +private import codeql.ruby.ApiGraphs +private import codeql.ruby.dataflow.FlowSummary +private import codeql.ruby.Concepts + +/** + * Provides modeling for mysql2, a Ruby library (gem) for interacting with MySql databases. + */ +module Mysql2 { + /** + * Flow summary for `Mysql2::Client.new()`. + */ + private class SqlSummary extends SummarizedCallable { + SqlSummary() { this = "Mysql2::Client.new()" } + + override MethodCall getACall() { result = any(Mysql2Connection c).asExpr().getExpr() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and output = "ReturnValue" and preservesValue = false + } + } + + /** A call to Mysql2::Client.new() is used to establish a connection to a MySql database. */ + private class Mysql2Connection extends DataFlow::CallNode { + Mysql2Connection() { + this = API::getTopLevelMember("Mysql2").getMember("Client").getAnInstantiation() + } + } + + /** A call that executes SQL statements against a MySQL database. */ + private class Mysql2Execution extends SqlExecution::Range, DataFlow::CallNode { + private DataFlow::Node query; + + Mysql2Execution() { + exists(Mysql2Connection mysql2Connection, DataFlow::CallNode prepareCall | + this = mysql2Connection.getAMethodCall("query") and query = this.getArgument(0) + or + prepareCall = mysql2Connection.getAMethodCall("prepare") and + query = prepareCall.getArgument(0) and + this = prepareCall.getAMethodCall("execute") + ) + } + + override DataFlow::Node getSql() { result = query } + } +} diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index c82b44d4349..546e84e023b 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -7,6 +7,7 @@ private import codeql.ruby.Concepts private import codeql.ruby.DataFlow private import codeql.ruby.dataflow.BarrierGuards private import codeql.ruby.dataflow.RemoteFlowSources +private import codeql.ruby.ApiGraphs /** * Provides default sources, sinks and sanitizers for detecting SQL injection @@ -51,6 +52,23 @@ module SqlInjection { * sanitizer-guard. */ class StringConstArrayInclusionCallAsSanitizer extends Sanitizer, - StringConstArrayInclusionCallBarrier - { } + StringConstArrayInclusionCallBarrier { } + + /** + * A call to `Mysql2::Client.escape`, considered as a sanitizer. + */ + class Mysql2EscapeSanitization extends Sanitizer { + Mysql2EscapeSanitization() { + this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") + } + } + + /** + * A call to `SQLite3::Database.quote`, considered as a sanitizer. + */ + class SQLite3EscapeSanitization extends Sanitizer { + SQLite3EscapeSanitization() { + this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") + } + } } diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.expected b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.expected new file mode 100644 index 00000000000..cc87a7d3403 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.expected @@ -0,0 +1,5 @@ +| Mysql2.rb:10:16:10:48 | call to query | Mysql2.rb:10:27:10:47 | "SELECT * FROM users" | +| Mysql2.rb:13:16:13:73 | call to query | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | +| Mysql2.rb:17:16:17:76 | call to query | Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | +| Mysql2.rb:21:16:21:57 | call to execute | Mysql2.rb:20:31:20:82 | "SELECT * FROM users WHERE id ..." | +| Mysql2.rb:25:16:25:60 | call to execute | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.ql b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.ql new file mode 100644 index 00000000000..c019bf0751b --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.ql @@ -0,0 +1,5 @@ +private import codeql.ruby.DataFlow +private import codeql.ruby.Concepts +private import codeql.ruby.frameworks.Mysql2 + +query predicate mysql2SqlExecution(SqlExecution e, DataFlow::Node sql) { sql = e.getSql() } diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb new file mode 100644 index 00000000000..b9b3b5a7b57 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb @@ -0,0 +1,30 @@ +class UsersController < ActionController::Base + def mysql2_handler(event:, context:) + name = params[:user_name] + + conn = Mysql2::Client.new( + host: "127.0.0.1", + username: "root" + ) + # GOOD: SQL statement is not constructed from user input + results1 = conn.query("SELECT * FROM users") + + # BAD: SQL statement constructed from user input + results2 = conn.query("SELECT * FROM users WHERE username='#{name}'") + + # GOOD: user input is escaped + escaped = Mysql2::Client.escape(name) + results3 = conn.query("SELECT * FROM users WHERE username='#{escaped}'") + + # GOOD: user input is escaped + statement1 = conn.prepare("SELECT * FROM users WHERE id >= ? AND username = ?") + results4 = statement1.execute(1, name, :as => :array) + + # BAD: SQL statement constructed from user input + statement2 = conn.prepare("SELECT * FROM users WHERE username='#{name}' AND password = ?") + results4 = statement2.execute("password", :as => :array) + + # NOT EXECUTED + statement3 = conn.prepare("SELECT * FROM users WHERE username = ?") + end +end \ No newline at end of file From f46620c455b76b49381fbde233c70431fafd8f8d Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 15 May 2023 15:09:44 +0200 Subject: [PATCH 013/219] Var only used in one side of disjunct --- ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll index efea7383a4c..c1c74813b75 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll @@ -35,12 +35,14 @@ module Mysql2 { private DataFlow::Node query; Mysql2Execution() { - exists(Mysql2Connection mysql2Connection, DataFlow::CallNode prepareCall | + exists(Mysql2Connection mysql2Connection | this = mysql2Connection.getAMethodCall("query") and query = this.getArgument(0) or - prepareCall = mysql2Connection.getAMethodCall("prepare") and - query = prepareCall.getArgument(0) and - this = prepareCall.getAMethodCall("execute") + exists(DataFlow::CallNode prepareCall | + prepareCall = mysql2Connection.getAMethodCall("prepare") and + query = prepareCall.getArgument(0) and + this = prepareCall.getAMethodCall("execute") + ) ) } From 3c002353755bb8af5d26770d6e01b07bd1d65020 Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Mon, 15 May 2023 15:56:52 +0200 Subject: [PATCH 014/219] Add SqlSanitization to `Concepts` and turn private --- ruby/ql/lib/codeql/ruby/Concepts.qll | 13 +++++++++++++ ruby/ql/lib/codeql/ruby/Frameworks.qll | 1 + .../ruby/security/SqlInjectionCustomizations.qll | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index ec27694581f..0a403734512 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -78,6 +78,19 @@ module SqlExecution { } } + /** + * A data-flow node that performs SQL sanitization. + */ + class SqlSanitization extends DataFlow::Node instanceof SqlSanitization::Range { } + + /** Provides a class for modeling new SQL sanitization APIs. */ + module SqlSanitization { + /** + * A data-flow node that performs SQL sanitization. + */ + abstract class Range extends DataFlow::Node { } + } + /** * A data-flow node that executes a regular expression. * diff --git a/ruby/ql/lib/codeql/ruby/Frameworks.qll b/ruby/ql/lib/codeql/ruby/Frameworks.qll index e61ac723e7e..7da37077df9 100644 --- a/ruby/ql/lib/codeql/ruby/Frameworks.qll +++ b/ruby/ql/lib/codeql/ruby/Frameworks.qll @@ -32,3 +32,4 @@ private import codeql.ruby.frameworks.Slim private import codeql.ruby.frameworks.Sinatra private import codeql.ruby.frameworks.Twirp private import codeql.ruby.frameworks.Sqlite3 +private import codeql.ruby.frameworks.Mysql2 \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index 546e84e023b..e1e1b630d9d 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -57,7 +57,7 @@ module SqlInjection { /** * A call to `Mysql2::Client.escape`, considered as a sanitizer. */ - class Mysql2EscapeSanitization extends Sanitizer { + private class Mysql2EscapeSanitization extends Sanitizer { Mysql2EscapeSanitization() { this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") } @@ -66,7 +66,7 @@ module SqlInjection { /** * A call to `SQLite3::Database.quote`, considered as a sanitizer. */ - class SQLite3EscapeSanitization extends Sanitizer { + private class SQLite3EscapeSanitization extends Sanitizer { SQLite3EscapeSanitization() { this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") } From cc72bfbbbb4e1738396350f8265cea0b0a4ba7c6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 May 2023 13:52:54 +0100 Subject: [PATCH 015/219] Swift: Add the shared SensitiveDataHeuristics.qll to Swift. --- config/identical-files.json | 5 +- .../internal/SensitiveDataHeuristics.qll | 124 ++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll diff --git a/config/identical-files.json b/config/identical-files.json index 3a9ef5173aa..4991f92d93c 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -512,7 +512,8 @@ "SensitiveDataHeuristics Python/JS": [ "javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll", "python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll", - "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll" + "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll", + "swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll" ], "CFG": [ "csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll", @@ -599,4 +600,4 @@ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ] -} \ No newline at end of file +} diff --git a/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll b/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll new file mode 100644 index 00000000000..7bc61ee2aee --- /dev/null +++ b/swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll @@ -0,0 +1,124 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes and predicates for identifying strings that may indicate the presence of sensitive data. + * Such that we can share this logic across our CodeQL analysis of different languages. + * + * 'Sensitive' data in general is anything that should not be sent around in unencrypted form. + */ + +/** + * A classification of different kinds of sensitive data: + * + * - secret: generic secret or trusted data; + * - id: a user name or other account information; + * - password: a password or authorization key; + * - certificate: a certificate. + * + * While classifications are represented as strings, this should not be relied upon. + * Instead, use the predicates in `SensitiveDataClassification::` to work with + * classifications. + */ +class SensitiveDataClassification extends string { + SensitiveDataClassification() { this in ["secret", "id", "password", "certificate"] } +} + +/** + * Provides predicates to select the different kinds of sensitive data we support. + */ +module SensitiveDataClassification { + /** Gets the classification for secret or trusted data. */ + SensitiveDataClassification secret() { result = "secret" } + + /** Gets the classification for user names or other account information. */ + SensitiveDataClassification id() { result = "id" } + + /** Gets the classification for passwords or authorization keys. */ + SensitiveDataClassification password() { result = "password" } + + /** Gets the classification for certificates. */ + SensitiveDataClassification certificate() { result = "certificate" } +} + +/** + * INTERNAL: Do not use. + * + * Provides heuristics for identifying names related to sensitive information. + */ +module HeuristicNames { + /** + * Gets a regular expression that identifies strings that may indicate the presence of secret + * or trusted data. + */ + string maybeSecret() { result = "(?is).*((? Date: Thu, 11 May 2023 16:50:58 +0100 Subject: [PATCH 016/219] Swift: Use SensitiveDataHeuristics.qll in regexpProbablySafe. --- .../codeql/swift/security/SensitiveExprs.qll | 3 ++- .../CWE-311/CleartextStorageDatabase.expected | 17 +++++++++++++---- .../Security/CWE-311/SensitiveExprs.expected | 5 +++-- .../CWE-312/CleartextLoggingTest.expected | 1 + .../CleartextStoragePreferences.expected | 8 -------- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 91f824aa5f2..8dd55d00259 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -5,6 +5,7 @@ */ import swift +import internal.SensitiveDataHeuristics private newtype TSensitiveDataType = TCredential() or @@ -69,7 +70,7 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { * contain hashed or encrypted data, or are only a reference to data that is * actually stored elsewhere. */ -private string regexpProbablySafe() { result = ".*(hash|crypt|file|path|url|invalid).*" } +private string regexpProbablySafe() { result = HeuristicNames::notSensitiveRegexp() } /** * A `VarDecl` that might be used to contain sensitive data. diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected index 320f4873d08..caad0df3190 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected @@ -110,11 +110,14 @@ edges | testCoreData.swift:18:19:18:26 | value | testCoreData.swift:19:12:19:12 | value | | testCoreData.swift:31:3:31:3 | newValue | testCoreData.swift:32:13:32:13 | newValue | | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:18:19:18:26 | value | +| testCoreData.swift:62:25:62:25 | password_file | testCoreData.swift:18:19:18:26 | value | | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | testCoreData.swift:64:2:64:2 | [post] obj | | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:31:3:31:3 | newValue | | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | +| testCoreData.swift:65:2:65:2 | [post] obj [myValue] | testCoreData.swift:65:2:65:2 | [post] obj | +| testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:31:3:31:3 | newValue | +| testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj [myValue] | | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | -| testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | | testCoreData.swift:93:10:93:10 | passwd | testCoreData.swift:97:15:97:15 | z | @@ -311,14 +314,17 @@ nodes | testCoreData.swift:48:15:48:15 | password | semmle.label | password | | testCoreData.swift:51:24:51:24 | password | semmle.label | password | | testCoreData.swift:58:15:58:15 | password | semmle.label | password | +| testCoreData.swift:59:15:59:15 | password_file | semmle.label | password_file | | testCoreData.swift:61:25:61:25 | password | semmle.label | password | +| testCoreData.swift:62:25:62:25 | password_file | semmle.label | password_file | | testCoreData.swift:64:2:64:2 | [post] obj | semmle.label | [post] obj | | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | | testCoreData.swift:64:16:64:16 | password | semmle.label | password | +| testCoreData.swift:65:2:65:2 | [post] obj | semmle.label | [post] obj | +| testCoreData.swift:65:2:65:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | +| testCoreData.swift:65:16:65:16 | password_file | semmle.label | password_file | | testCoreData.swift:77:24:77:24 | x | semmle.label | x | | testCoreData.swift:78:15:78:15 | x | semmle.label | x | -| testCoreData.swift:80:10:80:22 | call to getPassword() | semmle.label | call to getPassword() | -| testCoreData.swift:81:15:81:15 | y | semmle.label | y | | testCoreData.swift:85:15:85:17 | .password | semmle.label | .password | | testCoreData.swift:91:10:91:10 | passwd | semmle.label | passwd | | testCoreData.swift:92:10:92:10 | passwd | semmle.label | passwd | @@ -492,13 +498,16 @@ subpaths | testCoreData2.swift:104:2:104:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:104:2:104:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | | testCoreData2.swift:105:2:105:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:105:2:105:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | | testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password | password | +| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:62:25:62:25 | password_file | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:62:25:62:25 | password_file | password_file | | testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | +| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:65:16:65:16 | password_file | password_file | | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:48:15:48:15 | password | password | | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:51:24:51:24 | password | password | | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:58:15:58:15 | password | password | +| testCoreData.swift:59:15:59:15 | password_file | testCoreData.swift:59:15:59:15 | password_file | testCoreData.swift:59:15:59:15 | password_file | This operation stores 'password_file' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:59:15:59:15 | password_file | password_file | | testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | +| testCoreData.swift:65:2:65:2 | obj | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:65:16:65:16 | password_file | password_file | | testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x | x | -| testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() | call to getPassword() | | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password | | testCoreData.swift:95:15:95:15 | x | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:91:10:91:10 | passwd | passwd | | testCoreData.swift:96:15:96:15 | y | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:92:10:92:10 | passwd | passwd | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 20e1757c132..0960d1983a1 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -51,11 +51,12 @@ | testCoreData.swift:48:15:48:15 | password | label:password, type:credential | | testCoreData.swift:51:24:51:24 | password | label:password, type:credential | | testCoreData.swift:58:15:58:15 | password | label:password, type:credential | +| testCoreData.swift:59:15:59:15 | password_file | label:password_file, type:credential | | testCoreData.swift:61:25:61:25 | password | label:password, type:credential | +| testCoreData.swift:62:25:62:25 | password_file | label:password_file, type:credential | | testCoreData.swift:64:16:64:16 | password | label:password, type:credential | -| testCoreData.swift:77:2:77:25 | call to doSomething(password:) | label:doSomething(password:), type:credential | +| testCoreData.swift:65:16:65:16 | password_file | label:password_file, type:credential | | testCoreData.swift:77:24:77:24 | x | label:password, type:credential | -| testCoreData.swift:80:10:80:22 | call to getPassword() | label:getPassword(), type:credential | | testCoreData.swift:85:15:85:17 | .password | label:password, type:credential | | testCoreData.swift:91:10:91:10 | passwd | label:passwd, type:credential | | testCoreData.swift:92:10:92:10 | passwd | label:passwd, type:credential | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected b/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected index e69de29bb2d..967f34d486e 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected @@ -0,0 +1 @@ +| cleartextLoggingTest.swift:153:11:154:1 | // $ hasCleartextLogging=152\n | Missing result:hasCleartextLogging=152 | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected index 823733bb3ab..72c382d2331 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected @@ -1,11 +1,9 @@ edges | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | -| testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | -| testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | | testUserDefaults.swift:57:10:57:10 | passwd | testUserDefaults.swift:61:28:61:28 | z | @@ -13,8 +11,6 @@ nodes | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | semmle.label | password | | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | semmle.label | x | | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | semmle.label | x | -| testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | semmle.label | call to getPassword() | -| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | semmle.label | y | | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | semmle.label | .password | | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | semmle.label | passwd | | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | semmle.label | passwd | @@ -25,8 +21,6 @@ nodes | testUserDefaults.swift:28:15:28:15 | password | semmle.label | password | | testUserDefaults.swift:41:24:41:24 | x | semmle.label | x | | testUserDefaults.swift:42:28:42:28 | x | semmle.label | x | -| testUserDefaults.swift:44:10:44:22 | call to getPassword() | semmle.label | call to getPassword() | -| testUserDefaults.swift:45:28:45:28 | y | semmle.label | y | | testUserDefaults.swift:49:28:49:30 | .password | semmle.label | .password | | testUserDefaults.swift:55:10:55:10 | passwd | semmle.label | passwd | | testUserDefaults.swift:56:10:56:10 | passwd | semmle.label | passwd | @@ -38,14 +32,12 @@ subpaths #select | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | This operation stores 'password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | password | | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | x | -| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | call to getPassword() | | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | This operation stores '.password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | .password | | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | passwd | | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | passwd | | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | This operation stores 'z' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | passwd | | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | This operation stores 'password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:28:15:28:15 | password | password | | testUserDefaults.swift:42:28:42:28 | x | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:41:24:41:24 | x | x | -| testUserDefaults.swift:45:28:45:28 | y | testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:44:10:44:22 | call to getPassword() | call to getPassword() | | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | This operation stores '.password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:49:28:49:30 | .password | .password | | testUserDefaults.swift:59:28:59:28 | x | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:55:10:55:10 | passwd | passwd | | testUserDefaults.swift:60:28:60:28 | y | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:56:10:56:10 | passwd | passwd | From e2080c5d007a7e285c6d3de6191cdec8178fb4c5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 May 2023 17:52:47 +0100 Subject: [PATCH 017/219] Swift: SensitiveDataHeuristics.qll expects function names without an (argument:list:). --- swift/ql/lib/codeql/swift/security/SensitiveExprs.qll | 8 ++++++-- .../Security/CWE-311/CleartextStorageDatabase.expected | 4 ++++ .../query-tests/Security/CWE-311/SensitiveExprs.expected | 1 + .../Security/CWE-312/CleartextLoggingTest.expected | 1 - .../Security/CWE-312/CleartextStoragePreferences.expected | 8 ++++++++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 8dd55d00259..ffb3796b9cf 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -91,11 +91,15 @@ private class SensitiveVarDecl extends VarDecl { */ private class SensitiveFunction extends Function { SensitiveDataType sensitiveType; + string name; // name of the function, not including the argument list. - SensitiveFunction() { this.getName().toLowerCase().regexpMatch(sensitiveType.getRegexp()) } + SensitiveFunction() { + name = this.getName().splitAt("(", 0) and + name.toLowerCase().regexpMatch(sensitiveType.getRegexp()) + } predicate hasInfo(string label, SensitiveDataType type) { - label = this.getName() and + label = name and sensitiveType = type } } diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected index caad0df3190..9f0a34d5bb1 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected @@ -118,6 +118,7 @@ edges | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:31:3:31:3 | newValue | | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj [myValue] | | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | +| testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | | testCoreData.swift:93:10:93:10 | passwd | testCoreData.swift:97:15:97:15 | z | @@ -325,6 +326,8 @@ nodes | testCoreData.swift:65:16:65:16 | password_file | semmle.label | password_file | | testCoreData.swift:77:24:77:24 | x | semmle.label | x | | testCoreData.swift:78:15:78:15 | x | semmle.label | x | +| testCoreData.swift:80:10:80:22 | call to getPassword() | semmle.label | call to getPassword() | +| testCoreData.swift:81:15:81:15 | y | semmle.label | y | | testCoreData.swift:85:15:85:17 | .password | semmle.label | .password | | testCoreData.swift:91:10:91:10 | passwd | semmle.label | passwd | | testCoreData.swift:92:10:92:10 | passwd | semmle.label | passwd | @@ -508,6 +511,7 @@ subpaths | testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | | testCoreData.swift:65:2:65:2 | obj | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:65:16:65:16 | password_file | password_file | | testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x | x | +| testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() | call to getPassword() | | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password | | testCoreData.swift:95:15:95:15 | x | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:91:10:91:10 | passwd | passwd | | testCoreData.swift:96:15:96:15 | y | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:92:10:92:10 | passwd | passwd | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 0960d1983a1..59bf4abeec3 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -57,6 +57,7 @@ | testCoreData.swift:64:16:64:16 | password | label:password, type:credential | | testCoreData.swift:65:16:65:16 | password_file | label:password_file, type:credential | | testCoreData.swift:77:24:77:24 | x | label:password, type:credential | +| testCoreData.swift:80:10:80:22 | call to getPassword() | label:getPassword, type:credential | | testCoreData.swift:85:15:85:17 | .password | label:password, type:credential | | testCoreData.swift:91:10:91:10 | passwd | label:passwd, type:credential | | testCoreData.swift:92:10:92:10 | passwd | label:passwd, type:credential | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected b/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected index 967f34d486e..e69de29bb2d 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected @@ -1 +0,0 @@ -| cleartextLoggingTest.swift:153:11:154:1 | // $ hasCleartextLogging=152\n | Missing result:hasCleartextLogging=152 | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected index 72c382d2331..823733bb3ab 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected @@ -1,9 +1,11 @@ edges | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | +| testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | +| testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | | testUserDefaults.swift:57:10:57:10 | passwd | testUserDefaults.swift:61:28:61:28 | z | @@ -11,6 +13,8 @@ nodes | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | semmle.label | password | | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | semmle.label | x | | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | semmle.label | x | +| testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | semmle.label | call to getPassword() | +| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | semmle.label | y | | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | semmle.label | .password | | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | semmle.label | passwd | | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | semmle.label | passwd | @@ -21,6 +25,8 @@ nodes | testUserDefaults.swift:28:15:28:15 | password | semmle.label | password | | testUserDefaults.swift:41:24:41:24 | x | semmle.label | x | | testUserDefaults.swift:42:28:42:28 | x | semmle.label | x | +| testUserDefaults.swift:44:10:44:22 | call to getPassword() | semmle.label | call to getPassword() | +| testUserDefaults.swift:45:28:45:28 | y | semmle.label | y | | testUserDefaults.swift:49:28:49:30 | .password | semmle.label | .password | | testUserDefaults.swift:55:10:55:10 | passwd | semmle.label | passwd | | testUserDefaults.swift:56:10:56:10 | passwd | semmle.label | passwd | @@ -32,12 +38,14 @@ subpaths #select | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | This operation stores 'password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | password | | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | x | +| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | call to getPassword() | | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | This operation stores '.password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | .password | | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | passwd | | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | passwd | | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | This operation stores 'z' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | passwd | | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | This operation stores 'password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:28:15:28:15 | password | password | | testUserDefaults.swift:42:28:42:28 | x | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:41:24:41:24 | x | x | +| testUserDefaults.swift:45:28:45:28 | y | testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:44:10:44:22 | call to getPassword() | call to getPassword() | | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | This operation stores '.password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:49:28:49:30 | .password | .password | | testUserDefaults.swift:59:28:59:28 | x | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:55:10:55:10 | passwd | passwd | | testUserDefaults.swift:60:28:60:28 | y | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:56:10:56:10 | passwd | passwd | From a91c45049e9b8a68b57c37cd6d83b9b337a66eca Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 May 2023 12:02:22 +0100 Subject: [PATCH 018/219] Swift: Add some special cases to preserve (for now) result quality. --- .../ql/lib/codeql/swift/security/SensitiveExprs.qll | 5 ++++- .../CWE-311/CleartextStorageDatabase.expected | 13 ------------- .../Security/CWE-311/SensitiveExprs.expected | 3 --- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index ffb3796b9cf..d644da9e776 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -70,7 +70,10 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { * contain hashed or encrypted data, or are only a reference to data that is * actually stored elsewhere. */ -private string regexpProbablySafe() { result = HeuristicNames::notSensitiveRegexp() } +private string regexpProbablySafe() { + result = HeuristicNames::notSensitiveRegexp() or + result = "(?is).*(file|path|url|invalid).*" +} /** * A `VarDecl` that might be used to contain sensitive data. diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected index 9f0a34d5bb1..320f4873d08 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected @@ -110,13 +110,9 @@ edges | testCoreData.swift:18:19:18:26 | value | testCoreData.swift:19:12:19:12 | value | | testCoreData.swift:31:3:31:3 | newValue | testCoreData.swift:32:13:32:13 | newValue | | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:18:19:18:26 | value | -| testCoreData.swift:62:25:62:25 | password_file | testCoreData.swift:18:19:18:26 | value | | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | testCoreData.swift:64:2:64:2 | [post] obj | | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:31:3:31:3 | newValue | | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | -| testCoreData.swift:65:2:65:2 | [post] obj [myValue] | testCoreData.swift:65:2:65:2 | [post] obj | -| testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:31:3:31:3 | newValue | -| testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj [myValue] | | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | @@ -315,15 +311,10 @@ nodes | testCoreData.swift:48:15:48:15 | password | semmle.label | password | | testCoreData.swift:51:24:51:24 | password | semmle.label | password | | testCoreData.swift:58:15:58:15 | password | semmle.label | password | -| testCoreData.swift:59:15:59:15 | password_file | semmle.label | password_file | | testCoreData.swift:61:25:61:25 | password | semmle.label | password | -| testCoreData.swift:62:25:62:25 | password_file | semmle.label | password_file | | testCoreData.swift:64:2:64:2 | [post] obj | semmle.label | [post] obj | | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | | testCoreData.swift:64:16:64:16 | password | semmle.label | password | -| testCoreData.swift:65:2:65:2 | [post] obj | semmle.label | [post] obj | -| testCoreData.swift:65:2:65:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | -| testCoreData.swift:65:16:65:16 | password_file | semmle.label | password_file | | testCoreData.swift:77:24:77:24 | x | semmle.label | x | | testCoreData.swift:78:15:78:15 | x | semmle.label | x | | testCoreData.swift:80:10:80:22 | call to getPassword() | semmle.label | call to getPassword() | @@ -501,15 +492,11 @@ subpaths | testCoreData2.swift:104:2:104:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:104:2:104:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | | testCoreData2.swift:105:2:105:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:105:2:105:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | | testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password | password | -| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:62:25:62:25 | password_file | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:62:25:62:25 | password_file | password_file | | testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | -| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:65:16:65:16 | password_file | password_file | | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:48:15:48:15 | password | password | | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:51:24:51:24 | password | password | | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:58:15:58:15 | password | password | -| testCoreData.swift:59:15:59:15 | password_file | testCoreData.swift:59:15:59:15 | password_file | testCoreData.swift:59:15:59:15 | password_file | This operation stores 'password_file' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:59:15:59:15 | password_file | password_file | | testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | -| testCoreData.swift:65:2:65:2 | obj | testCoreData.swift:65:16:65:16 | password_file | testCoreData.swift:65:2:65:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:65:16:65:16 | password_file | password_file | | testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x | x | | testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() | call to getPassword() | | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 59bf4abeec3..89b8d36ccdf 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -51,11 +51,8 @@ | testCoreData.swift:48:15:48:15 | password | label:password, type:credential | | testCoreData.swift:51:24:51:24 | password | label:password, type:credential | | testCoreData.swift:58:15:58:15 | password | label:password, type:credential | -| testCoreData.swift:59:15:59:15 | password_file | label:password_file, type:credential | | testCoreData.swift:61:25:61:25 | password | label:password, type:credential | -| testCoreData.swift:62:25:62:25 | password_file | label:password_file, type:credential | | testCoreData.swift:64:16:64:16 | password | label:password, type:credential | -| testCoreData.swift:65:16:65:16 | password_file | label:password_file, type:credential | | testCoreData.swift:77:24:77:24 | x | label:password, type:credential | | testCoreData.swift:80:10:80:22 | call to getPassword() | label:getPassword, type:credential | | testCoreData.swift:85:15:85:17 | .password | label:password, type:credential | From 245e8fbc920155d0c3c45349b647eb0f578fbba4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 May 2023 22:22:01 +0100 Subject: [PATCH 019/219] Swift: Use SensitiveDataHeuristics.qll in SensitiveCredential. --- .../codeql/swift/security/SensitiveExprs.qll | 4 +- .../CWE-311/CleartextTransmission.expected | 6 +- .../Security/CWE-311/SensitiveExprs.expected | 86 ++++++++++--------- .../CWE-328/WeakSensitiveDataHashing.expected | 24 ++++++ 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index d644da9e776..093caaaa0cf 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -29,9 +29,7 @@ abstract class SensitiveDataType extends TSensitiveDataType { class SensitiveCredential extends SensitiveDataType, TCredential { override string toString() { result = "credential" } - override string getRegexp() { - result = ".*(password|passwd|accountid|account.?key|accnt.?key|license.?key|trusted).*" - } + override string getRegexp() { result = HeuristicNames::maybeSensitiveRegexp(_) } } /** diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index 94272faf6d0..816ef16e076 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -13,6 +13,7 @@ edges | testSend.swift:54:17:54:17 | password | testSend.swift:41:10:41:18 | data | | testSend.swift:54:17:54:17 | password | testSend.swift:54:13:54:25 | call to pad(_:) | | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | +| testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | nodes | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | @@ -36,10 +37,11 @@ nodes | testSend.swift:59:27:59:27 | str1 | semmle.label | str1 | | testSend.swift:60:27:60:27 | str2 | semmle.label | str2 | | testSend.swift:61:27:61:27 | str3 | semmle.label | str3 | -| testSend.swift:65:27:65:27 | license_key | semmle.label | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | semmle.label | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:13:54:13:54 | passwd | semmle.label | passwd | +| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| testURL.swift:15:55:15:55 | account_no | semmle.label | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | semmle.label | credit_card_no | | testURL.swift:20:22:20:22 | passwd | semmle.label | passwd | @@ -55,8 +57,8 @@ subpaths | testSend.swift:59:27:59:27 | str1 | testSend.swift:52:13:52:13 | password | testSend.swift:59:27:59:27 | str1 | This operation transmits 'str1', which may contain unencrypted sensitive data from $@. | testSend.swift:52:13:52:13 | password | password | | testSend.swift:60:27:60:27 | str2 | testSend.swift:53:13:53:13 | password | testSend.swift:60:27:60:27 | str2 | This operation transmits 'str2', which may contain unencrypted sensitive data from $@. | testSend.swift:53:13:53:13 | password | password | | testSend.swift:61:27:61:27 | str3 | testSend.swift:54:17:54:17 | password | testSend.swift:61:27:61:27 | str3 | This operation transmits 'str3', which may contain unencrypted sensitive data from $@. | testSend.swift:54:17:54:17 | password | password | -| testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | This operation transmits 'license_key', which may contain unencrypted sensitive data from $@. | testSend.swift:65:27:65:27 | license_key | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | This operation transmits '.mobileNumber', which may contain unencrypted sensitive data from $@. | testSend.swift:66:27:66:30 | .mobileNumber | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:13:54:13:54 | passwd | passwd | +| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:15:55:15:55 | account_no | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:16:55:16:55 | credit_card_no | credit_card_no | | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | This operation transmits 'passwd', which may contain unencrypted sensitive data from $@. | testURL.swift:20:22:20:22 | passwd | passwd | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 89b8d36ccdf..1c22f1e0bb9 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -4,50 +4,54 @@ | testAlamofire.swift:159:26:159:26 | email | label:email, type:private information | | testAlamofire.swift:171:35:171:35 | email | label:email, type:private information | | testAlamofire.swift:177:35:177:35 | email | label:email, type:private information | +| testAlamofire.swift:187:48:187:48 | username | label:username, type:credential | | testAlamofire.swift:187:65:187:65 | password | label:password, type:credential | +| testAlamofire.swift:195:47:195:47 | username | label:username, type:credential | | testAlamofire.swift:195:64:195:64 | password | label:password, type:credential | +| testAlamofire.swift:205:45:205:45 | username | label:username, type:credential | | testAlamofire.swift:205:62:205:62 | password | label:password, type:credential | +| testAlamofire.swift:213:48:213:48 | username | label:username, type:credential | | testAlamofire.swift:213:65:213:65 | password | label:password, type:credential | -| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | -| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | -| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | -| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | -| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | -| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | -| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | -| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | -| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | -| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:private information | -| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:private information | -| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:private information | -| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:private information | -| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:private information | -| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | +| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | +| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | +| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | +| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | +| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | +| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | +| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | +| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | +| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | | testCoreData.swift:48:15:48:15 | password | label:password, type:credential | | testCoreData.swift:51:24:51:24 | password | label:password, type:credential | | testCoreData.swift:58:15:58:15 | password | label:password, type:credential | @@ -125,9 +129,9 @@ | testSend.swift:55:23:55:23 | password | label:password, type:credential | | testSend.swift:56:27:56:27 | password | label:password, type:credential | | testSend.swift:57:27:57:27 | password | label:password, type:credential | -| testSend.swift:65:27:65:27 | license_key | label:license_key, type:credential | | testSend.swift:66:27:66:30 | .mobileNumber | label:mobileNumber, type:private information | | testSend.swift:69:27:69:30 | .passwordFeatureEnabled | label:passwordFeatureEnabled, type:credential | | testURL.swift:13:54:13:54 | passwd | label:passwd, type:credential | +| testURL.swift:15:55:15:55 | account_no | label:account_no, type:credential | | testURL.swift:16:55:16:55 | credit_card_no | label:credit_card_no, type:private information | | testURL.swift:20:22:20:22 | passwd | label:passwd, type:credential | diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected index 1a3d8a15f8a..16fc67d4a6f 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected @@ -1,17 +1,29 @@ edges nodes | testCryptoKit.swift:56:47:56:47 | passwd | semmle.label | passwd | +| testCryptoKit.swift:57:43:57:43 | cert | semmle.label | cert | +| testCryptoKit.swift:59:43:59:43 | account_no | semmle.label | account_no | | testCryptoKit.swift:60:43:60:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:61:43:61:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:63:44:63:44 | passwd | semmle.label | passwd | +| testCryptoKit.swift:64:44:64:44 | cert | semmle.label | cert | +| testCryptoKit.swift:66:44:66:44 | account_no | semmle.label | account_no | | testCryptoKit.swift:67:44:67:44 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:90:23:90:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:91:23:91:23 | cert | semmle.label | cert | +| testCryptoKit.swift:93:23:93:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:94:23:94:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:99:23:99:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:100:23:100:23 | cert | semmle.label | cert | +| testCryptoKit.swift:102:23:102:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:103:23:103:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:132:32:132:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:133:32:133:32 | cert | semmle.label | cert | +| testCryptoKit.swift:135:32:135:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:136:32:136:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:141:32:141:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:142:32:142:32 | cert | semmle.label | cert | +| testCryptoKit.swift:144:32:144:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:145:32:145:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoSwift.swift:113:30:113:30 | passwdArray | semmle.label | passwdArray | | testCryptoSwift.swift:115:31:115:31 | passwdArray | semmle.label | passwdArray | @@ -26,17 +38,29 @@ nodes subpaths #select | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:56:47:56:47 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:57:43:57:43 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:59:43:59:43 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:60:43:60:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:61:43:61:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:63:44:63:44 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:64:44:64:44 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:66:44:66:44 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:67:44:67:44 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:90:23:90:23 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:91:23:91:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:93:23:93:23 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:94:23:94:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:99:23:99:23 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:100:23:100:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:102:23:102:23 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:103:23:103:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:132:32:132:32 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:133:32:133:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:135:32:135:32 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:136:32:136:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:141:32:141:32 | passwd | sensitive data (credential passwd) | +| testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:142:32:142:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:144:32:144:32 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:145:32:145:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:113:30:113:30 | passwdArray | sensitive data (credential passwdArray) | | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:115:31:115:31 | passwdArray | sensitive data (credential passwdArray) | From 252b72b5731be19f3c5c5ea97f3e9b8182622240 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 May 2023 12:18:32 +0100 Subject: [PATCH 020/219] Swift: Add some special cases to preserve (for now) result quality. --- swift/ql/lib/codeql/swift/security/SensitiveExprs.qll | 5 ++++- .../Security/CWE-311/CleartextTransmission.expected | 2 ++ .../query-tests/Security/CWE-311/SensitiveExprs.expected | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 093caaaa0cf..a742974710d 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -29,7 +29,10 @@ abstract class SensitiveDataType extends TSensitiveDataType { class SensitiveCredential extends SensitiveDataType, TCredential { override string toString() { result = "credential" } - override string getRegexp() { result = HeuristicNames::maybeSensitiveRegexp(_) } + override string getRegexp() { + result = HeuristicNames::maybeSensitiveRegexp(_) or + result = "(?is).*(license.?key).*" + } } /** diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index 816ef16e076..c832cf51a15 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -37,6 +37,7 @@ nodes | testSend.swift:59:27:59:27 | str1 | semmle.label | str1 | | testSend.swift:60:27:60:27 | str2 | semmle.label | str2 | | testSend.swift:61:27:61:27 | str3 | semmle.label | str3 | +| testSend.swift:65:27:65:27 | license_key | semmle.label | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | semmle.label | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:13:54:13:54 | passwd | semmle.label | passwd | @@ -57,6 +58,7 @@ subpaths | testSend.swift:59:27:59:27 | str1 | testSend.swift:52:13:52:13 | password | testSend.swift:59:27:59:27 | str1 | This operation transmits 'str1', which may contain unencrypted sensitive data from $@. | testSend.swift:52:13:52:13 | password | password | | testSend.swift:60:27:60:27 | str2 | testSend.swift:53:13:53:13 | password | testSend.swift:60:27:60:27 | str2 | This operation transmits 'str2', which may contain unencrypted sensitive data from $@. | testSend.swift:53:13:53:13 | password | password | | testSend.swift:61:27:61:27 | str3 | testSend.swift:54:17:54:17 | password | testSend.swift:61:27:61:27 | str3 | This operation transmits 'str3', which may contain unencrypted sensitive data from $@. | testSend.swift:54:17:54:17 | password | password | +| testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | This operation transmits 'license_key', which may contain unencrypted sensitive data from $@. | testSend.swift:65:27:65:27 | license_key | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | This operation transmits '.mobileNumber', which may contain unencrypted sensitive data from $@. | testSend.swift:66:27:66:30 | .mobileNumber | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:13:54:13:54 | passwd | passwd | | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:15:55:15:55 | account_no | account_no | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 1c22f1e0bb9..812581cfb87 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -129,6 +129,7 @@ | testSend.swift:55:23:55:23 | password | label:password, type:credential | | testSend.swift:56:27:56:27 | password | label:password, type:credential | | testSend.swift:57:27:57:27 | password | label:password, type:credential | +| testSend.swift:65:27:65:27 | license_key | label:license_key, type:credential | | testSend.swift:66:27:66:30 | .mobileNumber | label:mobileNumber, type:private information | | testSend.swift:69:27:69:30 | .passwordFeatureEnabled | label:passwordFeatureEnabled, type:credential | | testURL.swift:13:54:13:54 | passwd | label:passwd, type:credential | From 047494dc95b61d085583559e93a09c87d0c782cd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 May 2023 15:38:17 +0100 Subject: [PATCH 021/219] Swift: Bank account numbers are a credential now, I guess they don't need to be private data as well. --- .../codeql/swift/security/SensitiveExprs.qll | 2 +- .../Security/CWE-311/SensitiveExprs.expected | 80 +++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index a742974710d..3de43524294 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -54,7 +54,7 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { // Geographic location - where the user is (or was) "latitude|longitude|" + // Financial data - such as credit card numbers, salary, bank accounts, and debts - "credit.?card|debit.?card|salary|bank.?account|" + + "credit.?card|debit.?card|salary|" + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. "email|" + // Health - medical conditions, insurance status, prescription records diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 812581cfb87..708d68a05e9 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -12,46 +12,46 @@ | testAlamofire.swift:205:62:205:62 | password | label:password, type:credential | | testAlamofire.swift:213:48:213:48 | username | label:username, type:credential | | testAlamofire.swift:213:65:213:65 | password | label:password, type:credential | -| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | -| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | -| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | -| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential, type:private information | -| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential, type:private information | -| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | -| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | -| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | -| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:credential, type:private information | -| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | -| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:credential, type:private information | +| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | +| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | +| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | +| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | +| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | +| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | +| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | +| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | +| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | +| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:credential | +| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:credential | +| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:credential | +| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:credential | +| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:credential | | testCoreData.swift:48:15:48:15 | password | label:password, type:credential | | testCoreData.swift:51:24:51:24 | password | label:password, type:credential | | testCoreData.swift:58:15:58:15 | password | label:password, type:credential | From 3f206cce003095b4135d6f6601e1ca2ea78a926a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 May 2023 09:50:38 +0100 Subject: [PATCH 022/219] Swift: Simplify out toLowerCase(). --- .../ql/lib/codeql/swift/security/SensitiveExprs.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 3de43524294..c3432fa58e4 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -43,7 +43,7 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { override string getRegexp() { result = - ".*(" + + "(?is).*(" + // Inspired by the list on https://cwe.mitre.org/data/definitions/359.html // Government identifiers, such as Social Security Numbers "social.?security|national.?insurance|" + @@ -82,7 +82,7 @@ private string regexpProbablySafe() { private class SensitiveVarDecl extends VarDecl { SensitiveDataType sensitiveType; - SensitiveVarDecl() { this.getName().toLowerCase().regexpMatch(sensitiveType.getRegexp()) } + SensitiveVarDecl() { this.getName().regexpMatch(sensitiveType.getRegexp()) } predicate hasInfo(string label, SensitiveDataType type) { label = this.getName() and @@ -99,7 +99,7 @@ private class SensitiveFunction extends Function { SensitiveFunction() { name = this.getName().splitAt("(", 0) and - name.toLowerCase().regexpMatch(sensitiveType.getRegexp()) + name.regexpMatch(sensitiveType.getRegexp()) } predicate hasInfo(string label, SensitiveDataType type) { @@ -114,7 +114,7 @@ private class SensitiveFunction extends Function { private class SensitiveArgument extends Argument { SensitiveDataType sensitiveType; - SensitiveArgument() { this.getLabel().toLowerCase().regexpMatch(sensitiveType.getRegexp()) } + SensitiveArgument() { this.getLabel().regexpMatch(sensitiveType.getRegexp()) } predicate hasInfo(string label, SensitiveDataType type) { label = this.getLabel() and @@ -147,7 +147,7 @@ class SensitiveExpr extends Expr { ) ) and // do not mark as sensitive it if it is probably safe - not label.toLowerCase().regexpMatch(regexpProbablySafe()) + not label.regexpMatch(regexpProbablySafe()) } /** @@ -165,7 +165,7 @@ class SensitiveExpr extends Expr { * A function that is likely used to encrypt or hash data. */ private class EncryptionFunction extends Function { - EncryptionFunction() { this.getName().regexpMatch(".*(crypt|hash|encode|protect).*") } + EncryptionFunction() { this.getName().regexpMatch("(?is).*(crypt|hash|encode|protect).*") } } /** From 5019d3befa7963b9854b0be325849d95d2e1b0b8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 May 2023 15:30:14 +0100 Subject: [PATCH 023/219] Swift: Update test annotations. --- .../Security/CWE-311/testURL.swift | 2 +- .../Security/CWE-328/testCryptoKit.swift | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift index 48ae815232f..7f9b64ff4f6 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift @@ -12,7 +12,7 @@ struct URL func test1(passwd : String, encrypted_passwd : String, account_no : String, credit_card_no : String) { let a = URL(string: "http://example.com/login?p=" + passwd); // BAD let b = URL(string: "http://example.com/login?p=" + encrypted_passwd); // GOOD (not sensitive) - let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD [NOT DETECTED] + let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD let d = URL(string: "http://example.com/login?cc=" + credit_card_no); // BAD let base = URL(string: "http://example.com/"); // GOOD (not sensitive) diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index a97eab7501d..55fb9284fa6 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -54,16 +54,16 @@ enum Insecure { func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.Insecure.MD5.hash(data: passwd) // BAD - hash = Crypto.Insecure.MD5.hash(data: cert) // BAD [NOT DETECTED] + hash = Crypto.Insecure.MD5.hash(data: cert) // BAD hash = Crypto.Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD [NOT DETECTED] + hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD - hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD [NOT DETECTED] + hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD hash = Crypto.Insecure.SHA1.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD [NOT DETECTED] + hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: credit_card_no) // BAD hash = Crypto.SHA256.hash(data: passwd) // BAD [NOT DETECTED] not a computationally expensive hash @@ -88,18 +88,18 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa func testMD5UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.Insecure.MD5() hash.update(data: passwd) // BAD - hash.update(data: cert) // BAD [NOT DETECTED] + hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD [NOT DETECTED] + hash.update(data: account_no) // BAD hash.update(data: credit_card_no) // BAD } func testSHA1UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.Insecure.SHA1() hash.update(data: passwd) // BAD - hash.update(data: cert) // BAD [NOT DETECTED] + hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD [NOT DETECTED] + hash.update(data: account_no) // BAD hash.update(data: credit_card_no) // BAD } @@ -130,18 +130,18 @@ func testSHA512UpdateWithData(passwd : String, cert: String, encrypted_passwd : func testMD5UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.Insecure.MD5() hash.update(bufferPointer: passwd) // BAD - hash.update(bufferPointer: cert) // BAD [NOT DETECTED] + hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] + hash.update(bufferPointer: account_no) // BAD hash.update(bufferPointer: credit_card_no) // BAD } func testSHA1UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.Insecure.SHA1() hash.update(bufferPointer: passwd) // BAD - hash.update(bufferPointer: cert) // BAD [NOT DETECTED] + hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] + hash.update(bufferPointer: account_no) // BAD hash.update(bufferPointer: credit_card_no) // BAD } From 5c6fc2ff019a8da08d0b08afccb085ab19cc2851 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Wed, 17 May 2023 15:18:52 -0400 Subject: [PATCH 024/219] Update IfStatementAdditionOverflow.ql --- .../CWE-190/IfStatementAdditionOverflow.ql | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql index a45ba737bab..3667f068a25 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql @@ -1,12 +1,8 @@ /** * @name Integer addition may overflow inside if statement - * @description Detects "if (a+b>c) a=c-b", which incorrectly implements - * a = min(a,c-b) if a+b overflows. Should be replaced by - * "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b" - * (swapped terms in addition), if (a+b>c) { a=c-b }" - * (assignment inside block), "c=", "<", "<=" instead of ">" (all operators). This - * integer overflow is the root cause of the buffer overflow + * @description Writing 'if (a+b>c) a=c-b' incorrectly implements + * 'a = min(a,c-b)' if 'a+b' overflows. This integer + * overflow is the root cause of the buffer overflow * in the SHA-3 reference implementation (CVE-2022-37454). * @kind problem * @problem.severity warning @@ -21,22 +17,26 @@ import cpp import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.HashCons import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -import semmle.code.cpp.commons.Exclusions +import semmle.code.cpp.controlflow.Guards -from IfStmt ifstmt, RelationalOperation relop, ExprStmt exprstmt, BlockStmt blockstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr -where ifstmt.getCondition() = relop and - relop.getAnOperand() = addexpr and +from + GuardCondition guard, Expr expr, ExprStmt exprstmt, BasicBlock block, AssignExpr assignexpr, + AddExpr addexpr, SubExpr subexpr +where + (guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) and addexpr.getUnspecifiedType() instanceof IntegralType and - not isFromMacroDefinition(relop) and exprMightOverflowPositively(addexpr) and - (ifstmt.getThen() = exprstmt or - (ifstmt.getThen() = blockstmt and - blockstmt.getAStmt() = exprstmt)) and + block.getANode() = exprstmt and exprstmt.getExpr() = assignexpr and assignexpr.getRValue() = subexpr and - ((hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and - globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())) or - (hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and - globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand()))) and - globalValueNumber(relop.getAnOperand()) = globalValueNumber(subexpr.getLeftOperand()) -select ifstmt, "\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.", addexpr, "addition" + ( + hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and + globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand()) + or + hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and + globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand()) + ) and + globalValueNumber(expr) = globalValueNumber(subexpr.getLeftOperand()) +select guard, + "\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.", + addexpr, "addition" From ef578617892e241545db4e0298c3b148d1558e74 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Wed, 17 May 2023 15:19:52 -0400 Subject: [PATCH 025/219] Update IfStatementAdditionOverflow.expected --- .../IfStatementAdditionOverflow.expected | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected index 12dbde04790..2e31f173faa 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/IfStatementAdditionOverflow.expected @@ -1,33 +1,35 @@ -| test.cpp:18:2:18:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition | -| test.cpp:19:2:19:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition | -| test.cpp:20:2:20:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition | -| test.cpp:21:2:21:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition | -| test.cpp:22:2:22:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition | -| test.cpp:23:2:23:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition | -| test.cpp:24:2:24:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition | -| test.cpp:25:2:25:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition | -| test.cpp:27:2:27:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition | -| test.cpp:28:2:28:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition | -| test.cpp:29:2:29:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition | -| test.cpp:30:2:30:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition | -| test.cpp:31:2:31:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition | -| test.cpp:32:2:32:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition | -| test.cpp:33:2:33:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition | -| test.cpp:34:2:34:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition | -| test.cpp:36:2:36:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition | -| test.cpp:37:2:37:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition | -| test.cpp:38:2:38:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition | -| test.cpp:39:2:39:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition | -| test.cpp:40:2:40:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition | -| test.cpp:41:2:41:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition | -| test.cpp:42:2:42:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition | -| test.cpp:43:2:43:24 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition | -| test.cpp:45:2:45:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition | -| test.cpp:46:2:46:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition | -| test.cpp:47:2:47:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition | -| test.cpp:48:2:48:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition | -| test.cpp:49:2:49:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition | -| test.cpp:50:2:50:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition | -| test.cpp:51:2:51:21 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition | -| test.cpp:52:2:52:25 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition | -| test.cpp:54:2:54:20 | if (...) ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition | +| test.cpp:18:6:18:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition | +| test.cpp:19:6:19:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition | +| test.cpp:20:6:20:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition | +| test.cpp:21:6:21:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition | +| test.cpp:22:6:22:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition | +| test.cpp:23:6:23:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition | +| test.cpp:24:6:24:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition | +| test.cpp:25:6:25:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition | +| test.cpp:27:6:27:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition | +| test.cpp:28:6:28:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition | +| test.cpp:29:6:29:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition | +| test.cpp:30:6:30:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition | +| test.cpp:31:6:31:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition | +| test.cpp:32:6:32:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition | +| test.cpp:33:6:33:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition | +| test.cpp:34:6:34:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition | +| test.cpp:36:6:36:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition | +| test.cpp:37:6:37:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition | +| test.cpp:38:6:38:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition | +| test.cpp:39:6:39:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition | +| test.cpp:40:6:40:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition | +| test.cpp:41:6:41:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition | +| test.cpp:42:6:42:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition | +| test.cpp:43:6:43:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition | +| test.cpp:45:6:45:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition | +| test.cpp:46:6:46:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition | +| test.cpp:47:6:47:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition | +| test.cpp:48:6:48:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition | +| test.cpp:49:6:49:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition | +| test.cpp:50:6:50:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition | +| test.cpp:51:6:51:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition | +| test.cpp:52:6:52:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition | +| test.cpp:54:6:54:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition | +| test.cpp:61:6:61:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:61:6:61:8 | ... + ... | addition | +| test.cpp:62:6:62:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:62:6:62:8 | ... + ... | addition | From 187299fcaf283f06e664d894f10cddea039483fe Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Wed, 17 May 2023 15:20:54 -0400 Subject: [PATCH 026/219] Update test.cpp --- .../Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp index f1aac83122b..7c5ab91832e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/IfStatementAdditionOverflow/test.cpp @@ -57,4 +57,7 @@ void test() if (a+b>c) { b++; a = c-b; } // GOOD if (a+d>c) a = c-d; // GOOD if (a1+b1>c1) a1 = c1-b1; // GOOD + + if (a+b<=c) { /* ... */ } else { a = c-b; } // BAD + if (a+b<=c) { return; } a = c-b; // BAD } From 27519ce3ea4e4917e14ee5b917696400ab9370b8 Mon Sep 17 00:00:00 2001 From: Nicky Mouha Date: Wed, 17 May 2023 15:27:19 -0400 Subject: [PATCH 027/219] Create IfStatementAdditionOverflow.qhelp --- .../CWE-190/IfStatementAdditionOverflow.qhelp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.qhelp diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.qhelp new file mode 100644 index 00000000000..72491838fd2 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.qhelp @@ -0,0 +1,33 @@ + + + + +

+Detects if (a+b>c) a=c-b, which incorrectly implements +a = min(a,c-b) if a+b overflows. +

+

+Also detects variants such as if (b+a>c) a=c-b (swapped +terms in addition), if (a+b>c) { a=c-b } (assignment +inside block), c<a+b (swapped operands), and +>=, <, <= instead of +> (all operators). +

+

+This integer overflow is the root cause of the buffer overflow in +the SHA-3 reference implementation (CVE-2022-37454). +

+
+ +

+Replace by if (a>c-b) a=c-b. This avoids the overflow +and makes it easy to see that a = min(a,c-b). +

+
+ +
  • CVE-2022-37454: The Keccak XKCP SHA-3 reference implementation before fdc6fef has an integer overflow and resultant buffer overflow that allows attackers to execute arbitrary code or eliminate expected cryptographic properties. This occurs in the sponge function interface.
  • +
  • GitHub Advisory Database: CVE-2022-37454: Buffer overflow in sponge queue functions
  • +
    +
    From 708a99528fcf41c2e4743b2e4fcbdc3f25c2308e Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 22 May 2023 10:11:32 +0200 Subject: [PATCH 028/219] initial implementation of TS 5.1 --- docs/codeql/reusables/supported-versions-compilers.rst | 2 +- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/src/main.ts | 1 - javascript/extractor/lib/typescript/yarn.lock | 8 ++++---- .../extractor/src/com/semmle/js/extractor/Main.java | 2 +- .../ql/lib/change-notes/2023-04-19-typescript-5-1.md | 4 ++++ 6 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 93b826a94dd..1ac892c01c2 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -25,7 +25,7 @@ Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11",Not applicable,``.py`` Ruby [9]_,"up to 3.2",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" Swift [10]_,"Swift 5.4-5.7","Swift compiler","``.swift``" - TypeScript [11]_,"2.6-5.0",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" + TypeScript [11]_,"2.6-5.1",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" .. container:: footnote-group diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 0c8de4f1bbc..cb053bb0e6f 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "5.0.2" + "typescript": "5.1.1-rc" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 2e9f26b6953..2594f4e35f5 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -579,7 +579,6 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { // inverse mapping, nor a way to enumerate all known module names. So we discover all // modules on the type roots (usually "node_modules/@types" but this is configurable). let typeRoots = ts.getEffectiveTypeRoots(config.options, { - directoryExists: (path) => ts.sys.directoryExists(path), getCurrentDirectory: () => basePath, }); diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 88d32ae6b3a..3b0a9476df6 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== -typescript@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.2.tgz#891e1a90c5189d8506af64b9ef929fca99ba1ee5" - integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw== +typescript@5.1.1-rc: + version "5.1.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.1-rc.tgz#7be6e85bb4ad36e07e0125e501eb08ed3a6e3769" + integrity sha512-+yHTPe5QCxw5cgN+B81z+k65xTHcwNCRwJN7OGVUe3srPULTZHF7J9QCgrptL7F8mrO7gmsert7XrMksAjutRw== diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 4f8bb2c1ced..2a188676924 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -41,7 +41,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2023-03-16"; + public static final String EXTRACTOR_VERSION = "2023-04-19"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md b/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md new file mode 100644 index 00000000000..7260bd3d389 --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Added support for TypeScript 5.1. \ No newline at end of file From 36147e7afc27cf6cbfb72aa60a4fb62b90d036b8 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 11 May 2023 13:47:58 +0200 Subject: [PATCH 029/219] revert the better super-linear algorith, --- .../regex/nfa/SuperlinearBackTracking.qll | 407 +++++++----------- 1 file changed, 159 insertions(+), 248 deletions(-) diff --git a/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll b/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll index 3f16431e165..d06170502b4 100644 --- a/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll +++ b/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll @@ -9,16 +9,16 @@ * Theorem 3 from the paper describes the basic idea. * * The following explains the idea using variables and predicate names that are used in the implementation: - * We consider a pair of repetitions, which we will call `pivot` and `pumpEnd`. + * We consider a pair of repetitions, which we will call `pivot` and `succ`. * * We create a product automaton of 3-tuples of states (see `StateTuple`). * There exists a transition `(a,b,c) -> (d,e,f)` in the product automaton * iff there exists three transitions in the NFA `a->d, b->e, c->f` where those three * transitions all match a shared character `char`. (see `getAThreewayIntersect`) * - * We start a search in the product automaton at `(pivot, pivot, pumpEnd)`, + * We start a search in the product automaton at `(pivot, pivot, succ)`, * and search for a series of transitions (a `Trace`), such that we end - * at `(pivot, pumpEnd, pumpEnd)` (see `isReachableFromStartTuple`). + * at `(pivot, succ, succ)` (see `isReachableFromStartTuple`). * * For example, consider the regular expression `/^\d*5\w*$/`. * The search will start at the tuple `(\d*, \d*, \w*)` and search @@ -51,30 +51,20 @@ module Make { private State getRootState() { result = mkMatch(any(RegExpRoot r)) } private newtype TStateTuple = - /** - * A tuple of states `(q1, q2, q3)` in the product automaton that is reachable from `(pivot, pivot, pumpEnd)`. - */ - MkStateTuple(State pivot, State pumpEnd, State q1, State q2, State q3) { - // starts at (pivot, pivot, pumpEnd) - isStartLoops(q1, q3) and - q1 = q2 and - pivot = q1 and - pumpEnd = q3 + MkStateTuple(State q1, State q2, State q3) { + // starts at (pivot, pivot, succ) + isStartLoops(q1, q3) and q1 = q2 or - // recurse: any transition out where all 3 edges share a char (and the resulting tuple isn't obviously infeasible) - exists(StateTuple prev | - prev = MkStateTuple(pivot, pumpEnd, _, _, _) and - hasCommonStep(prev, _, _, _, q1, q2, q3) and - FeasibleTuple::isFeasibleTuple(pivot, pumpEnd, q1, q2, q3) - ) + step(_, _, _, _, q1, q2, q3) and FeasibleTuple::isFeasibleTuple(q1, q2, q3) } /** - * A state `(q1, q2, q3)` in the product automaton, that is reachable from `(pivot, pivot, pumpEnd)`. + * A state in the product automaton. + * The product automaton contains 3-tuples of states. * * We lazily only construct those states that we are actually * going to need. - * Either a start state `(pivot, pivot, pumpEnd)`, or a state + * Either a start state `(pivot, pivot, succ)`, or a state * where there exists a transition from an already existing state. * * The exponential variant of this query (`js/redos`) uses an optimization @@ -82,13 +72,11 @@ module Make { * of the elements matter. */ class StateTuple extends TStateTuple { - State pivot; - State pumpEnd; State q1; State q2; State q3; - StateTuple() { this = MkStateTuple(pivot, pumpEnd, q1, q2, q3) } + StateTuple() { this = MkStateTuple(q1, q2, q3) } /** * Gest a string representation of this tuple. @@ -100,39 +88,6 @@ module Make { */ pragma[noinline] predicate isTuple(State r1, State r2, State r3) { r1 = q1 and r2 = q2 and r3 = q3 } - - /** - * Gets the first state of the tuple. - */ - State getFirst() { result = q1 } - - /** - * Gets the second state of the tuple. - */ - State getSecond() { result = q2 } - - /** - * Gets the third state of the tuple. - */ - State getThird() { result = q3 } - - /** - * Gets the pivot state. - */ - State getPivot() { result = pivot } - - /** - * Gets the pumpEnd state. - */ - State getPumpEnd() { result = pumpEnd } - - /** - * Holds if the pivot state has the specified location. - * This location has been chosen arbitrarily, and is only useful for debugging. - */ - predicate hasLocationInfo(string file, int line, int column, int endLine, int endColumn) { - pivot.hasLocationInfo(file, line, column, endLine, endColumn) - } } /** @@ -142,36 +97,21 @@ module Make { */ private module FeasibleTuple { /** - * Holds if the tuple `(r1, r2, r3)` might be on path from a start-state `(pivot, pivot, pumpEnd)` to an end-state `(pivot, pumpEnd, pumpEnd)` in the product automaton. + * Holds if the tuple `(r1, r2, r3)` might be on path from a start-state to an end-state in the product automaton. */ - bindingset[pivot, pumpEnd, r1, r2, r3] - pragma[inline_late] - predicate isFeasibleTuple(State pivot, State pumpEnd, State r1, State r2, State r3) { - isStartLoops(pivot, pumpEnd) and - // r1 can reach the pivot state - reachesBeginning(r1, pivot) and - // r2 and r3 can reach the pumpEnd state - reachesEnd(r2, pumpEnd) and - reachesEnd(r3, pumpEnd) and + pragma[inline] + predicate isFeasibleTuple(State r1, State r2, State r3) { // The first element is either inside a repetition (or the start state itself) isRepetitionOrStart(r1) and // The last element is inside a repetition stateInsideRepetition(r3) and // The states are reachable in the NFA in the order r1 -> r2 -> r3 delta+(r1) = r2 and - delta+(r2) = r3 - } - - pragma[noinline] - private predicate reachesBeginning(State s, State pivot) { - isStartLoops(pivot, _) and - delta+(s) = pivot - } - - pragma[noinline] - private predicate reachesEnd(State s, State pumpEnd) { - isStartLoops(_, pumpEnd) and - delta+(s) = pumpEnd + delta+(r2) = r3 and + // The first element can reach a beginning (the "pivot" state in a `(pivot, succ)` pair). + canReachABeginning(r1) and + // The last element can reach a target (the "succ" state in a `(pivot, succ)` pair). + canReachATarget(r3) } /** @@ -189,18 +129,36 @@ module Make { private predicate stateInsideRepetition(State s) { s.getRepr().getParent*() instanceof InfiniteRepetitionQuantifier } + + /** + * Holds if there exists a path in the NFA from `s` to a "pivot" state + * (from a `(pivot, succ)` pair that starts the search). + */ + pragma[noinline] + private predicate canReachABeginning(State s) { + delta+(s) = any(State pivot | isStartLoops(pivot, _)) + } + + /** + * Holds if there exists a path in the NFA from `s` to a "succ" state + * (from a `(pivot, succ)` pair that starts the search). + */ + pragma[noinline] + private predicate canReachATarget(State s) { + delta+(s) = any(State succ | isStartLoops(_, succ)) + } } /** - * Holds if `pivot` and `pumpEnd` are a pair of loops that could be the beginning of a quadratic blowup. + * Holds if `pivot` and `succ` are a pair of loops that could be the beginning of a quadratic blowup. * - * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != pumpEnd`. - * The case where `pivot = pumpEnd` causes exponential backtracking and is handled by the `js/redos` query. + * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != succ`. + * The case where `pivot = succ` causes exponential backtracking and is handled by the `js/redos` query. */ - predicate isStartLoops(State pivot, State pumpEnd) { - pivot != pumpEnd and - pumpEnd.getRepr() instanceof InfiniteRepetitionQuantifier and - delta+(pivot) = pumpEnd and + predicate isStartLoops(State pivot, State succ) { + pivot != succ and + succ.getRepr() instanceof InfiniteRepetitionQuantifier and + delta+(pivot) = succ and ( pivot.getRepr() instanceof InfiniteRepetitionQuantifier or @@ -216,25 +174,62 @@ module Make { /** * Holds if there are transitions from the components of `q` to the corresponding * components of `r` labelled with `s1`, `s2`, and `s3`, respectively. - * Where the edges `s1`, `s2`, and `s3` all share at least one character. */ pragma[nomagic] - private predicate step(StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r) { + private predicate stepHelper( + StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r + ) { exists(State r1, State r2, State r3 | - hasCommonStep(q, s1, s2, s3, r1, r2, r3) and - r = - MkStateTuple(pragma[only_bind_out](q.getPivot()), pragma[only_bind_out](q.getPumpEnd()), - pragma[only_bind_out](r1), pragma[only_bind_out](r2), pragma[only_bind_out](r3)) + step(q, s1, s2, s3, r1, r2, r3) and r = MkStateTuple(r1, r2, r3) ) } + /** + * Holds if there are transitions from the components of `q` to the corresponding + * components of `r` labelled with `s1`, `s2`, and `s3`, respectively. + * + * Additionally, a heuristic is used to avoid blowups in the case of complex regexps. + * For regular expressions with more than 100 states, we only look at all the characters + * for the transitions out of `q` and only consider transitions that use the lexicographically + * smallest character. + */ + pragma[noinline] + predicate step(StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r) { + stepHelper(q, s1, s2, s3, r) and + ( + countStates(any(State s | q.isTuple(s, _, _)).getRepr().getRootTerm()) < 100 + or + // arbitrarily pick an edge out of `q` for complex regexps. This is a heuristic to avoid potential blowups. + exists(string char | + char = + min(string str, InputSymbol x1, InputSymbol x2, InputSymbol x3 | + stepHelper(q, x1, x2, x3, _) and str = getAStepChar(x1, x2, x3) + | + str + ) and + char = getAStepChar(s1, s2, s3) + ) + ) + } + + // specialized version of `getAThreewayIntersect` to be used in `step` above. + pragma[noinline] + private string getAStepChar(InputSymbol s1, InputSymbol s2, InputSymbol s3) { + stepHelper(_, s1, s2, s3, _) and result = getAThreewayIntersect(s1, s2, s3) + } + + /** Gets the number of states in the NFA for `root`. This is used to determine a complexity metric used in the `step` predicate above. */ + private int countStates(RegExpTerm root) { + root.isRootTerm() and + result = count(State s | s.getRepr().getRootTerm() = root) + } + /** * Holds if there are transitions from the components of `q` to `r1`, `r2`, and `r3 * labelled with `s1`, `s2`, and `s3`, respectively. - * Where `s1`, `s2`, and `s3` all share at least one character. */ pragma[noopt] - predicate hasCommonStep( + predicate step( StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, State r1, State r2, State r3 ) { exists(State q1, State q2, State q3 | q.isTuple(q1, q2, q3) | @@ -269,59 +264,41 @@ module Make { result = [min(intersect(a, b)), max(intersect(a, b))] } - /** Gets a tuple reachable in a forwards exploratory search from the start state `(pivot, pivot, pivot)`. */ - private StateTuple getReachableFromStartStateForwards(State pivot, State pumpEnd) { - // base case. - isStartLoops(pivot, pumpEnd) and - result = MkStateTuple(pivot, pumpEnd, pivot, pivot, pumpEnd) - or - // recursive case - exists(StateTuple p | - p = getReachableFromStartStateForwards(pivot, pumpEnd) and - step(p, _, _, _, result) - ) - } + private newtype TTrace = + Nil() or + Step(InputSymbol s1, InputSymbol s2, InputSymbol s3, TTrace t) { + isReachableFromStartTuple(_, _, t, s1, s2, s3, _, _) + } /** - * Gets a state tuple that can reach the end state `(pivot, pumpEnd, pumpEnd)`, found via a backwards exploratory search. - * Where the end state was reachable from a forwards search from the start state `(pivot, pivot, pumpEnd)`. - * The resulting tuples are exactly those that are on a path from the start state to the end state. + * A list of tuples of input symbols that describe a path in the product automaton + * starting from some start state. */ - private StateTuple getARelevantStateTuple(State pivot, State pumpEnd) { - // base case. - isStartLoops(pivot, pumpEnd) and - result = MkStateTuple(pivot, pumpEnd, pivot, pumpEnd, pumpEnd) and - result = getReachableFromStartStateForwards(pivot, pumpEnd) - or - // recursive case - exists(StateTuple p | - p = getARelevantStateTuple(pivot, pumpEnd) and - step(result, _, _, _, p) and - pragma[only_bind_out](result) = getReachableFromStartStateForwards(pivot, pumpEnd) // was reachable in the forwards pass. - ) + class Trace extends TTrace { + /** + * Gets a string representation of this Trace that can be used for debug purposes. + */ + string toString() { + this = Nil() and result = "Nil()" + or + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace t | this = Step(s1, s2, s3, t) | + result = "Step(" + s1 + ", " + s2 + ", " + s3 + ", " + t + ")" + ) + } } /** - * Holds if there exists a transition from `src` to `dst` in the product automaton. - * Where `src` and `dst` are both on a path from a start state to an end state. + * Holds if there exists a transition from `r` to `q` in the product automaton. * Notice that the arguments are flipped, and thus the direction is backwards. */ pragma[noinline] - predicate tupleDeltaBackwards(StateTuple dst, StateTuple src) { - step(src, _, _, _, dst) and - // `step` ensures that `src` and `dst` have the same pivot and pumpEnd. - src = getARelevantStateTuple(_, _) and - dst = getARelevantStateTuple(_, _) - } + predicate tupleDeltaBackwards(StateTuple q, StateTuple r) { step(r, _, _, _, q) } /** - * Holds if `tuple` is an end state in our search, and `tuple` is on a path from a start state to an end state. - * That means there exists a pair of loops `(pivot, pumpEnd)` such that `tuple = (pivot, pumpEnd, pumpEnd)`. + * Holds if `tuple` is an end state in our search. + * That means there exists a pair of loops `(pivot, succ)` such that `tuple = (pivot, succ, succ)`. */ - predicate isEndTuple(StateTuple tuple) { - tuple = getEndTuple(_, _) and - tuple = getARelevantStateTuple(_, _) - } + predicate isEndTuple(StateTuple tuple) { tuple = getAnEndTuple(_, _) } /** * Gets the minimum length of a path from `r` to some an end state `end`. @@ -334,138 +311,72 @@ module Make { shortestDistances(isEndTuple/1, tupleDeltaBackwards/2)(end, r, result) /** - * Holds if there is a step from `q` to `r` in the product automaton labeled with `s1`, `s2`, and `s3`. - * Where the step is on a path from a start state to an end state. + * Holds if there exists a pair of repetitions `(pivot, succ)` in the regular expression such that: + * `tuple` is reachable from `(pivot, pivot, succ)` in the product automaton, + * and there is a distance of `dist` from `tuple` to the nearest end-tuple `(pivot, succ, succ)`, + * and a path from a start-state to `tuple` follows the transitions in `trace`. */ - private predicate isStepOnPath( - StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r + private predicate isReachableFromStartTuple( + State pivot, State succ, StateTuple tuple, Trace trace, int dist ) { - step(q, s1, s2, s3, r) and - exists(State pivot, State pumpEnd, StateTuple end | - end = MkStateTuple(pivot, pumpEnd, pivot, pumpEnd, pumpEnd) and - pragma[only_bind_out](distBackFromEnd(q, end)) = - pragma[only_bind_out](distBackFromEnd(r, end)) + 1 + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace v | + isReachableFromStartTuple(pivot, succ, v, s1, s2, s3, tuple, dist) and + trace = Step(s1, s2, s3, v) + ) + } + + private predicate isReachableFromStartTuple( + State pivot, State succ, Trace trace, InputSymbol s1, InputSymbol s2, InputSymbol s3, + StateTuple tuple, int dist + ) { + // base case. + isStartLoops(pivot, succ) and + step(MkStateTuple(pivot, pivot, succ), s1, s2, s3, tuple) and + tuple = MkStateTuple(_, _, _) and + trace = Nil() and + dist = distBackFromEnd(tuple, MkStateTuple(pivot, succ, succ)) + or + // recursive case + exists(StateTuple p | + isReachableFromStartTuple(pivot, succ, p, trace, dist + 1) and + dist = distBackFromEnd(tuple, MkStateTuple(pivot, succ, succ)) and + step(p, s1, s2, s3, tuple) ) } /** - * Gets a unique number for a `state`. - * Is used to create an ordering of states and tuples of states. + * Gets the tuple `(pivot, succ, succ)` from the product automaton. */ - private int rankState(State state) { - state = - rank[result](State s, int startLine, int endLine, int startColumn, int endColumn | - exists(StateTuple tuple | tuple = getARelevantStateTuple(_, _) | - s = [tuple.getFirst(), tuple.getSecond(), tuple.getThird()] and - s.getRepr().hasLocationInfo(_, startLine, startColumn, endLine, endColumn) - ) - | - s order by startLine, startColumn, endLine, endColumn - ) - } - - /** - * Holds if there is a step from `q` to `r` in the product automaton labeled with `s1`, `s2`, and `s3`. - * Where the step is on a path from a start state to an end state. - * And the step is a uniquely chosen step from out of `q`. - */ - pragma[nomagic] - private predicate isUniqueMinStepOnPath( - StateTuple q, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple r - ) { - isStepOnPath(q, s1, s2, s3, r) and - r = - min(StateTuple cand | - isStepOnPath(q, _, _, _, cand) - | - cand - order by - rankState(cand.getFirst()), rankState(cand.getSecond()), rankState(cand.getThird()) - ) - } - - private newtype TTrace = - Nil(State pivot, State pumpEnd) { - isStartLoops(pivot, pumpEnd) and - getStartTuple(pivot, pumpEnd) = getARelevantStateTuple(pivot, pumpEnd) - } or - Step(TTrace prev, StateTuple nextTuple) { - exists(StateTuple prevTuple | - exists(State pivot, State pumpEnd | - prev = Nil(pivot, pumpEnd) and - prevTuple = getStartTuple(pivot, pumpEnd) - ) - or - prev = Step(_, prevTuple) - | - isUniqueMinStepOnPath(prevTuple, _, _, _, nextTuple) - ) - } - - /** - * A list of tuples of input symbols that describe a path in the product automaton - * starting from a start state `(pivot, pivot, pumpEnd)`. - */ - class Trace extends TTrace { - /** - * Gets a string representation of this Trace that can be used for debug purposes. - */ - string toString() { result = "a trace" } - - /** Gets a trace where the head has been removed. */ - Trace getPrev() { this = Step(result, _) } - - /** Gets the tuple at the head of this trace. */ - StateTuple getTuple() { - this = Step(_, result) - or - exists(State prev, State pumpEnd | - this = Nil(prev, pumpEnd) and - result = getStartTuple(prev, pumpEnd) - ) - } - } - - /** - * Gets the tuple `(pivot, pumpEnd, pumpEnd)` from the product automaton. - */ - StateTuple getEndTuple(State pivot, State pumpEnd) { - isStartLoops(pivot, pumpEnd) and - result = MkStateTuple(pivot, pumpEnd, pivot, pumpEnd, pumpEnd) - } - - /** - * Gets the tuple `(pivot, pivot, pumpEnd)` from the product automaton. - */ - StateTuple getStartTuple(State pivot, State pumpEnd) { - isStartLoops(pivot, pumpEnd) and - result = MkStateTuple(pivot, pumpEnd, pivot, pivot, pumpEnd) + StateTuple getAnEndTuple(State pivot, State succ) { + isStartLoops(pivot, succ) and + result = MkStateTuple(pivot, succ, succ) } /** An implementation of a chain containing chars for use by `Concretizer`. */ private module CharTreeImpl implements CharTree { class CharNode = Trace; - CharNode getPrev(CharNode t) { result = t.getPrev() } + CharNode getPrev(CharNode t) { t = Step(_, _, _, result) } - predicate isARelevantEnd(CharNode n) { n.getTuple() = getEndTuple(_, _) } + /** Holds if `n` is used in `isPumpable`. */ + predicate isARelevantEnd(CharNode n) { + exists(State pivot, State succ | + isReachableFromStartTuple(pivot, succ, getAnEndTuple(pivot, succ), n, _) + ) + } string getChar(CharNode t) { - result = - min(string c, InputSymbol s1, InputSymbol s2, InputSymbol s3 | - isUniqueMinStepOnPath(t.getPrev().getTuple(), s1, s2, s3, t.getTuple()) and - c = getAThreewayIntersect(s1, s2, s3) - | - c - ) + exists(InputSymbol s1, InputSymbol s2, InputSymbol s3 | t = Step(s1, s2, s3, _) | + result = getAThreewayIntersect(s1, s2, s3) + ) } } /** * Holds if matching repetitions of `pump` can: * 1) Transition from `pivot` back to `pivot`. - * 2) Transition from `pivot` to `pumpEnd`. - * 3) Transition from `pumpEnd` to `pumpEnd`. + * 2) Transition from `pivot` to `succ`. + * 3) Transition from `succ` to `succ`. * * From theorem 3 in the paper linked in the top of this file we can therefore conclude that * the regular expression has polynomial backtracking - if a rejecting suffix exists. @@ -473,10 +384,10 @@ module Make { * This predicate is used by `SuperLinearReDoSConfiguration`, and the final results are * available in the `hasReDoSResult` predicate. */ - predicate isPumpable(State pivot, State pumpEnd, string pump) { + predicate isPumpable(State pivot, State succ, string pump) { exists(StateTuple q, Trace t | - q = getEndTuple(pivot, pumpEnd) and - q = t.getTuple() and + isReachableFromStartTuple(pivot, succ, q, t, _) and + q = getAnEndTuple(pivot, succ) and pump = Concretizer::concretize(t) ) } From efa53d21faaa54cb38217fe837826e79f467b4ba Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 11 May 2023 13:49:18 +0200 Subject: [PATCH 030/219] rename `succ` to `pumpEnd` --- .../regex/nfa/SuperlinearBackTracking.qll | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll b/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll index d06170502b4..43d8e8a73db 100644 --- a/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll +++ b/shared/regex/codeql/regex/nfa/SuperlinearBackTracking.qll @@ -9,16 +9,16 @@ * Theorem 3 from the paper describes the basic idea. * * The following explains the idea using variables and predicate names that are used in the implementation: - * We consider a pair of repetitions, which we will call `pivot` and `succ`. + * We consider a pair of repetitions, which we will call `pivot` and `pumpEnd`. * * We create a product automaton of 3-tuples of states (see `StateTuple`). * There exists a transition `(a,b,c) -> (d,e,f)` in the product automaton * iff there exists three transitions in the NFA `a->d, b->e, c->f` where those three * transitions all match a shared character `char`. (see `getAThreewayIntersect`) * - * We start a search in the product automaton at `(pivot, pivot, succ)`, + * We start a search in the product automaton at `(pivot, pivot, pumpEnd)`, * and search for a series of transitions (a `Trace`), such that we end - * at `(pivot, succ, succ)` (see `isReachableFromStartTuple`). + * at `(pivot, pumpEnd, pumpEnd)` (see `isReachableFromStartTuple`). * * For example, consider the regular expression `/^\d*5\w*$/`. * The search will start at the tuple `(\d*, \d*, \w*)` and search @@ -52,7 +52,7 @@ module Make { private newtype TStateTuple = MkStateTuple(State q1, State q2, State q3) { - // starts at (pivot, pivot, succ) + // starts at (pivot, pivot, pumpEnd) isStartLoops(q1, q3) and q1 = q2 or step(_, _, _, _, q1, q2, q3) and FeasibleTuple::isFeasibleTuple(q1, q2, q3) @@ -64,7 +64,7 @@ module Make { * * We lazily only construct those states that we are actually * going to need. - * Either a start state `(pivot, pivot, succ)`, or a state + * Either a start state `(pivot, pivot, pumpEnd)`, or a state * where there exists a transition from an already existing state. * * The exponential variant of this query (`js/redos`) uses an optimization @@ -108,9 +108,9 @@ module Make { // The states are reachable in the NFA in the order r1 -> r2 -> r3 delta+(r1) = r2 and delta+(r2) = r3 and - // The first element can reach a beginning (the "pivot" state in a `(pivot, succ)` pair). + // The first element can reach a beginning (the "pivot" state in a `(pivot, pumpEnd)` pair). canReachABeginning(r1) and - // The last element can reach a target (the "succ" state in a `(pivot, succ)` pair). + // The last element can reach a target (the "pumpEnd" state in a `(pivot, pumpEnd)` pair). canReachATarget(r3) } @@ -132,7 +132,7 @@ module Make { /** * Holds if there exists a path in the NFA from `s` to a "pivot" state - * (from a `(pivot, succ)` pair that starts the search). + * (from a `(pivot, pumpEnd)` pair that starts the search). */ pragma[noinline] private predicate canReachABeginning(State s) { @@ -140,25 +140,25 @@ module Make { } /** - * Holds if there exists a path in the NFA from `s` to a "succ" state - * (from a `(pivot, succ)` pair that starts the search). + * Holds if there exists a path in the NFA from `s` to a "pumpEnd" state + * (from a `(pivot, pumpEnd)` pair that starts the search). */ pragma[noinline] private predicate canReachATarget(State s) { - delta+(s) = any(State succ | isStartLoops(_, succ)) + delta+(s) = any(State pumpEnd | isStartLoops(_, pumpEnd)) } } /** - * Holds if `pivot` and `succ` are a pair of loops that could be the beginning of a quadratic blowup. + * Holds if `pivot` and `pumpEnd` are a pair of loops that could be the beginning of a quadratic blowup. * - * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != succ`. - * The case where `pivot = succ` causes exponential backtracking and is handled by the `js/redos` query. + * There is a slight implementation difference compared to the paper: this predicate requires that `pivot != pumpEnd`. + * The case where `pivot = pumpEnd` causes exponential backtracking and is handled by the `js/redos` query. */ - predicate isStartLoops(State pivot, State succ) { - pivot != succ and - succ.getRepr() instanceof InfiniteRepetitionQuantifier and - delta+(pivot) = succ and + predicate isStartLoops(State pivot, State pumpEnd) { + pivot != pumpEnd and + pumpEnd.getRepr() instanceof InfiniteRepetitionQuantifier and + delta+(pivot) = pumpEnd and ( pivot.getRepr() instanceof InfiniteRepetitionQuantifier or @@ -296,7 +296,7 @@ module Make { /** * Holds if `tuple` is an end state in our search. - * That means there exists a pair of loops `(pivot, succ)` such that `tuple = (pivot, succ, succ)`. + * That means there exists a pair of loops `(pivot, pumpEnd)` such that `tuple = (pivot, pumpEnd, pumpEnd)`. */ predicate isEndTuple(StateTuple tuple) { tuple = getAnEndTuple(_, _) } @@ -311,45 +311,45 @@ module Make { shortestDistances(isEndTuple/1, tupleDeltaBackwards/2)(end, r, result) /** - * Holds if there exists a pair of repetitions `(pivot, succ)` in the regular expression such that: - * `tuple` is reachable from `(pivot, pivot, succ)` in the product automaton, - * and there is a distance of `dist` from `tuple` to the nearest end-tuple `(pivot, succ, succ)`, + * Holds if there exists a pair of repetitions `(pivot, pumpEnd)` in the regular expression such that: + * `tuple` is reachable from `(pivot, pivot, pumpEnd)` in the product automaton, + * and there is a distance of `dist` from `tuple` to the nearest end-tuple `(pivot, pumpEnd, pumpEnd)`, * and a path from a start-state to `tuple` follows the transitions in `trace`. */ private predicate isReachableFromStartTuple( - State pivot, State succ, StateTuple tuple, Trace trace, int dist + State pivot, State pumpEnd, StateTuple tuple, Trace trace, int dist ) { exists(InputSymbol s1, InputSymbol s2, InputSymbol s3, Trace v | - isReachableFromStartTuple(pivot, succ, v, s1, s2, s3, tuple, dist) and + isReachableFromStartTuple(pivot, pumpEnd, v, s1, s2, s3, tuple, dist) and trace = Step(s1, s2, s3, v) ) } private predicate isReachableFromStartTuple( - State pivot, State succ, Trace trace, InputSymbol s1, InputSymbol s2, InputSymbol s3, + State pivot, State pumpEnd, Trace trace, InputSymbol s1, InputSymbol s2, InputSymbol s3, StateTuple tuple, int dist ) { // base case. - isStartLoops(pivot, succ) and - step(MkStateTuple(pivot, pivot, succ), s1, s2, s3, tuple) and + isStartLoops(pivot, pumpEnd) and + step(MkStateTuple(pivot, pivot, pumpEnd), s1, s2, s3, tuple) and tuple = MkStateTuple(_, _, _) and trace = Nil() and - dist = distBackFromEnd(tuple, MkStateTuple(pivot, succ, succ)) + dist = distBackFromEnd(tuple, MkStateTuple(pivot, pumpEnd, pumpEnd)) or // recursive case exists(StateTuple p | - isReachableFromStartTuple(pivot, succ, p, trace, dist + 1) and - dist = distBackFromEnd(tuple, MkStateTuple(pivot, succ, succ)) and + isReachableFromStartTuple(pivot, pumpEnd, p, trace, dist + 1) and + dist = distBackFromEnd(tuple, MkStateTuple(pivot, pumpEnd, pumpEnd)) and step(p, s1, s2, s3, tuple) ) } /** - * Gets the tuple `(pivot, succ, succ)` from the product automaton. + * Gets the tuple `(pivot, pumpEnd, pumpEnd)` from the product automaton. */ - StateTuple getAnEndTuple(State pivot, State succ) { - isStartLoops(pivot, succ) and - result = MkStateTuple(pivot, succ, succ) + StateTuple getAnEndTuple(State pivot, State pumpEnd) { + isStartLoops(pivot, pumpEnd) and + result = MkStateTuple(pivot, pumpEnd, pumpEnd) } /** An implementation of a chain containing chars for use by `Concretizer`. */ @@ -360,8 +360,8 @@ module Make { /** Holds if `n` is used in `isPumpable`. */ predicate isARelevantEnd(CharNode n) { - exists(State pivot, State succ | - isReachableFromStartTuple(pivot, succ, getAnEndTuple(pivot, succ), n, _) + exists(State pivot, State pumpEnd | + isReachableFromStartTuple(pivot, pumpEnd, getAnEndTuple(pivot, pumpEnd), n, _) ) } @@ -375,8 +375,8 @@ module Make { /** * Holds if matching repetitions of `pump` can: * 1) Transition from `pivot` back to `pivot`. - * 2) Transition from `pivot` to `succ`. - * 3) Transition from `succ` to `succ`. + * 2) Transition from `pivot` to `pumpEnd`. + * 3) Transition from `pumpEnd` to `pumpEnd`. * * From theorem 3 in the paper linked in the top of this file we can therefore conclude that * the regular expression has polynomial backtracking - if a rejecting suffix exists. @@ -384,10 +384,10 @@ module Make { * This predicate is used by `SuperLinearReDoSConfiguration`, and the final results are * available in the `hasReDoSResult` predicate. */ - predicate isPumpable(State pivot, State succ, string pump) { + predicate isPumpable(State pivot, State pumpEnd, string pump) { exists(StateTuple q, Trace t | - isReachableFromStartTuple(pivot, succ, q, t, _) and - q = getAnEndTuple(pivot, succ) and + isReachableFromStartTuple(pivot, pumpEnd, q, t, _) and + q = getAnEndTuple(pivot, pumpEnd) and pump = Concretizer::concretize(t) ) } @@ -439,8 +439,8 @@ module Make { * Holds if all non-empty successors to the polynomial backtracking term matches the end of the line. */ predicate isAtEndLine() { - forall(RegExpTerm succ | super.getSuccessor+() = succ and not matchesEpsilon(succ) | - succ instanceof RegExpDollar + forall(RegExpTerm pumpEnd | super.getSuccessor+() = pumpEnd and not matchesEpsilon(pumpEnd) | + pumpEnd instanceof RegExpDollar ) } From f85b3e13c2326fe515c71f9587bb38ff229f0ae4 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 11 May 2023 13:53:16 +0200 Subject: [PATCH 031/219] update expected output --- .../Security/CWE-400/ReDoS/PolynomialReDoS.expected | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected index 0ec4c40fd2c..4c534fffe13 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected @@ -163,6 +163,8 @@ nodes | polynomial-redos.js:65:24:65:30 | tainted | | polynomial-redos.js:66:19:66:25 | tainted | | polynomial-redos.js:66:19:66:25 | tainted | +| polynomial-redos.js:67:18:67:24 | tainted | +| polynomial-redos.js:67:18:67:24 | tainted | | polynomial-redos.js:68:18:68:24 | req.url | | polynomial-redos.js:68:18:68:24 | req.url | | polynomial-redos.js:68:18:68:24 | req.url | @@ -219,6 +221,8 @@ nodes | polynomial-redos.js:112:2:112:8 | tainted | | polynomial-redos.js:114:2:114:8 | tainted | | polynomial-redos.js:114:2:114:8 | tainted | +| polynomial-redos.js:116:2:116:8 | tainted | +| polynomial-redos.js:116:2:116:8 | tainted | | polynomial-redos.js:118:2:118:8 | tainted | | polynomial-redos.js:118:2:118:8 | tainted | | polynomial-redos.js:121:7:121:55 | replaced | @@ -403,6 +407,8 @@ edges | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:65:24:65:30 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:66:19:66:25 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:66:19:66:25 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:67:18:67:24 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:67:18:67:24 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:71:2:71:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:71:2:71:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:73:2:73:8 | tainted | @@ -453,6 +459,8 @@ edges | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:112:2:112:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:114:2:114:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:114:2:114:8 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:116:2:116:8 | tainted | +| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:116:2:116:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:118:2:118:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:118:2:118:8 | tainted | | polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:121:18:121:24 | tainted | @@ -547,6 +555,7 @@ edges | polynomial-redos.js:64:3:64:31 | /^foo(K ... ainted) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:64:24:64:30 | tainted | This $@ that depends on $@ may run slow on strings starting with 'fooY' and with many repetitions of 'Y'. | polynomial-redos.js:64:14:64:15 | Y* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:65:3:65:31 | /^foo(K ... ainted) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:65:24:65:30 | tainted | This $@ that depends on $@ may run slow on strings starting with 'fooY' and with many repetitions of 'K'. | polynomial-redos.js:65:14:65:15 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:66:3:66:26 | /(K\|Y). ... ainted) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:66:19:66:25 | tainted | This $@ that depends on $@ may run slow on strings starting with 'K' and with many repetitions of 'K'. | polynomial-redos.js:66:9:66:10 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | +| polynomial-redos.js:67:3:67:25 | /[^Y].* ... ainted) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:67:18:67:24 | tainted | This $@ that depends on $@ may run slow on strings starting with 'X' and with many repetitions of 'Z'. | polynomial-redos.js:67:8:67:9 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:69:3:69:26 | /[^Y].* ... q.body) | polynomial-redos.js:69:18:69:25 | req.body | polynomial-redos.js:69:18:69:25 | req.body | This $@ that depends on $@ may run slow on strings starting with 'X' and with many repetitions of 'X'. | polynomial-redos.js:69:8:69:9 | .* | regular expression | polynomial-redos.js:69:18:69:25 | req.body | a user-provided value | | polynomial-redos.js:71:2:71:67 | tainted ... E]*)$/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:71:2:71:8 | tainted | This $@ that depends on $@ may run slow on strings starting with ',-+' and with many repetitions of '++'. | polynomial-redos.js:71:51:71:63 | [?\\x21-\\x7E]* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:73:2:73:60 | tainted ... LWP7")) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:73:2:73:8 | tainted | This $@ that depends on $@ may run slow on strings starting with 'MSIE 0.0' and with many repetitions of '0'. | polynomial-redos.js:73:50:73:51 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | @@ -574,6 +583,7 @@ edges | polynomial-redos.js:111:2:111:22 | tainted ... /\\s*$/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:111:2:111:8 | tainted | This $@ that depends on $@ may run slow on strings with many repetitions of '\\t'. | polynomial-redos.js:111:17:111:19 | \\s* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:112:2:112:22 | tainted ... /\\s+$/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:112:2:112:8 | tainted | This $@ that depends on $@ may run slow on strings with many repetitions of '\\t'. | polynomial-redos.js:112:17:112:19 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:114:2:114:27 | tainted ... 5\\w*$/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:114:2:114:8 | tainted | This $@ that depends on $@ may run slow on strings starting with '5' and with many repetitions of '5'. | polynomial-redos.js:114:22:114:24 | \\w* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | +| polynomial-redos.js:116:2:116:35 | tainted ... \\*\\//g) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:116:2:116:8 | tainted | This $@ that depends on $@ may run slow on strings starting with '/*' and with many repetitions of 'a/*'. | polynomial-redos.js:116:21:116:28 | [\\d\\D]*? | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:118:2:118:25 | tainted ... \\d+)+/) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:118:2:118:8 | tainted | This $@ that depends on $@ may run slow on strings with many repetitions of '0'. | polynomial-redos.js:118:17:118:23 | (#\\d+)+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:124:12:124:43 | result. ... /g, '') | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:124:12:124:17 | result | This $@ that depends on $@ may run slow on strings with many repetitions of '\\t'. | polynomial-redos.js:124:33:124:35 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | | polynomial-redos.js:130:2:130:31 | modifie ... g, "b") | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:130:2:130:9 | modified | This $@ that depends on $@ may run slow on strings starting with 'c' and with many repetitions of 'c'. | polynomial-redos.js:130:21:130:22 | c+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value | From c7e21ee9aef8b90d723a1277df951775066f2c8e Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 11 May 2023 13:57:16 +0200 Subject: [PATCH 032/219] add really long regex as a test-case --- .../PolynomialReDoS.expected | 9 ++++++ .../PolynomialReDoS.rb | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.expected b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.expected index 97de9e92184..ec079020695 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.expected +++ b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.expected @@ -40,6 +40,9 @@ edges | PolynomialReDoS.rb:70:12:70:24 | ...[...] | PolynomialReDoS.rb:70:5:70:8 | name | | PolynomialReDoS.rb:73:32:73:35 | name | PolynomialReDoS.rb:76:35:76:39 | input | | PolynomialReDoS.rb:76:35:76:39 | input | PolynomialReDoS.rb:77:5:77:9 | input | +| PolynomialReDoS.rb:103:5:103:8 | name | PolynomialReDoS.rb:105:5:105:8 | name | +| PolynomialReDoS.rb:103:12:103:17 | call to params | PolynomialReDoS.rb:103:12:103:24 | ...[...] | +| PolynomialReDoS.rb:103:12:103:24 | ...[...] | PolynomialReDoS.rb:103:5:103:8 | name | | lib/index.rb:2:11:2:11 | x | lib/index.rb:4:13:4:13 | x | | lib/index.rb:8:13:8:13 | x | lib/index.rb:9:15:9:15 | x | | lib/index.rb:8:13:8:13 | x | lib/index.rb:11:16:11:16 | x | @@ -91,6 +94,10 @@ nodes | PolynomialReDoS.rb:73:32:73:35 | name | semmle.label | name | | PolynomialReDoS.rb:76:35:76:39 | input | semmle.label | input | | PolynomialReDoS.rb:77:5:77:9 | input | semmle.label | input | +| PolynomialReDoS.rb:103:5:103:8 | name | semmle.label | name | +| PolynomialReDoS.rb:103:12:103:17 | call to params | semmle.label | call to params | +| PolynomialReDoS.rb:103:12:103:24 | ...[...] | semmle.label | ...[...] | +| PolynomialReDoS.rb:105:5:105:8 | name | semmle.label | name | | lib/index.rb:2:11:2:11 | x | semmle.label | x | | lib/index.rb:4:13:4:13 | x | semmle.label | x | | lib/index.rb:8:13:8:13 | x | semmle.label | x | @@ -121,6 +128,8 @@ subpaths | PolynomialReDoS.rb:62:5:62:22 | call to gsub | PolynomialReDoS.rb:54:12:54:17 | call to params | PolynomialReDoS.rb:62:5:62:9 | input | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | PolynomialReDoS.rb:56:31:56:33 | \\s+ | regular expression | PolynomialReDoS.rb:54:12:54:17 | call to params | user-provided value | | PolynomialReDoS.rb:66:5:66:34 | call to match? | PolynomialReDoS.rb:54:12:54:17 | call to params | PolynomialReDoS.rb:66:5:66:9 | input | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | PolynomialReDoS.rb:58:30:58:32 | \\s+ | regular expression | PolynomialReDoS.rb:54:12:54:17 | call to params | user-provided value | | PolynomialReDoS.rb:77:5:77:22 | call to gsub | PolynomialReDoS.rb:70:12:70:17 | call to params | PolynomialReDoS.rb:77:5:77:9 | input | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | PolynomialReDoS.rb:72:28:72:30 | \\s+ | regular expression | PolynomialReDoS.rb:70:12:70:17 | call to params | user-provided value | +| PolynomialReDoS.rb:105:5:105:23 | ... =~ ... | PolynomialReDoS.rb:103:12:103:17 | call to params | PolynomialReDoS.rb:105:5:105:8 | name | This $@ that depends on a $@ may run slow on strings starting with '''' and with many repetitions of ' '. | PolynomialReDoS.rb:100:397:100:399 | \\s* | regular expression | PolynomialReDoS.rb:103:12:103:17 | call to params | user-provided value | +| PolynomialReDoS.rb:105:5:105:23 | ... =~ ... | PolynomialReDoS.rb:103:12:103:17 | call to params | PolynomialReDoS.rb:105:5:105:8 | name | This $@ that depends on a $@ may run slow on strings starting with '''' and with many repetitions of ' '. | PolynomialReDoS.rb:100:405:100:407 | \\s* | regular expression | PolynomialReDoS.rb:103:12:103:17 | call to params | user-provided value | | lib/index.rb:4:13:4:26 | call to match | lib/index.rb:2:11:2:11 | x | lib/index.rb:4:13:4:13 | x | This $@ that depends on a $@ may run slow on strings with many repetitions of 'a'. | lib/index.rb:4:22:4:23 | a+ | regular expression | lib/index.rb:2:11:2:11 | x | library input | | lib/index.rb:9:15:9:28 | call to match | lib/index.rb:8:13:8:13 | x | lib/index.rb:9:15:9:15 | x | This $@ that depends on a $@ may run slow on strings with many repetitions of 'a'. | lib/index.rb:9:24:9:25 | a+ | regular expression | lib/index.rb:8:13:8:13 | x | library input | | lib/index.rb:11:16:11:276 | call to match | lib/index.rb:8:13:8:13 | x | lib/index.rb:11:16:11:16 | x | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | lib/index.rb:11:271:11:272 | .* | regular expression | lib/index.rb:8:13:8:13 | x | library input | diff --git a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb index d97f7413f82..2f73209321f 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb @@ -76,4 +76,32 @@ class FooController < ActionController::Base def re_compile_indirect_2 (reg, input) input.gsub reg, '' # NOT GOOD end + + # See https://github.com/dependabot/dependabot-core/blob/37dc1767fde9b7184020763f4d0c1434f93d11d6/python/lib/dependabot/python/requirement_parser.rb#L6-L25 + NAME = /[a-zA-Z0-9](?:[a-zA-Z0-9\-_\.]*[a-zA-Z0-9])?/ + EXTRA = /[a-zA-Z0-9\-_\.]+/ + COMPARISON = /===|==|>=|<=|<|>|~=|!=/ + VERSION = /([1-9][0-9]*!)?[0-9]+[a-zA-Z0-9\-_.*]*(\+[0-9a-zA-Z]+(\.[0-9a-zA-Z]+)*)?/ + + REQUIREMENT = /(?#{COMPARISON})\s*\\?\s*(?#{VERSION})/ + HASH = /--hash=(?.*?):(?.*?)(?=\s|\\|$)/ + REQUIREMENTS = /#{REQUIREMENT}(\s*,\s*\\?\s*#{REQUIREMENT})*/ + HASHES = /#{HASH}(\s*\\?\s*#{HASH})*/ + MARKER_OP = /\s*(#{COMPARISON}|(\s*in)|(\s*not\s*in))/ + PYTHON_STR_C = %r{[a-zA-Z0-9\s\(\)\.\{\}\-_\*#:;/\?\[\]!~`@\$%\^&=\+\|<>]} + PYTHON_STR = /('(#{PYTHON_STR_C}|")*'|"(#{PYTHON_STR_C}|')*")/ + ENV_VAR = + /python_version|python_full_version|os_name|sys_platform| + platform_release|platform_system|platform_version|platform_machine| + platform_python_implementation|implementation_name| + implementation_version/ + MARKER_VAR = /\s*(#{ENV_VAR}|#{PYTHON_STR})/ + MARKER_EXPR_ONE = /#{MARKER_VAR}#{MARKER_OP}#{MARKER_VAR}/ + MARKER_EXPR = /(#{MARKER_EXPR_ONE}|\(\s*|\s*\)|\s+and\s+|\s+or\s+)+/ + + def use_marker_expr + name = params[:name] # source + + name =~ MARKER_EXPR + end end From f7419c92501593bc187fe56319a54efc62f9f0e6 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Fri, 12 May 2023 09:26:03 +0200 Subject: [PATCH 033/219] add expected output --- .../ReDoS/PolynomialBackTracking.expected | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialBackTracking.expected index db29a305639..d8bac89a913 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialBackTracking.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialBackTracking.expected @@ -1,5 +1,5 @@ -| highlight.js:2:26:2:979 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | -| highlight.js:3:27:3:971 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'ip\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | +| highlight.js:2:26:2:979 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'aaa\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firewall\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | +| highlight.js:3:27:3:971 | ((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+ | Strings starting with '/' and with many repetitions of 'aaa\\t' can start matching anywhere after the start of the preceeding (\\.\\.\\/\|\\/\|\\s)((traffic-flow\|traffic-generator\|firewall\|scheduler\|aaa\|accounting\|address-list\|address\|align\|area\|bandwidth-server\|bfd\|bgp\|bridge\|client\|clock\|community\|config\|connection\|console\|customer\|default\|dhcp-client\|dhcp-server\|discovery\|dns\|e-mail\|ethernet\|filter\|firmware\|gps\|graphing\|group\|hardware\|health\|hotspot\|identity\|igmp-proxy\|incoming\|instance\|interface\|ip\|ipsec\|ipv6\|irq\|l2tp-server\|lcd\|ldp\|logging\|mac-server\|mac-winbox\|mangle\|manual\|mirror\|mme\|mpls\|nat\|nd\|neighbor\|network\|note\|ntp\|ospf\|ospf-v3\|ovpn-server\|page\|peer\|pim\|ping\|policy\|pool\|port\|ppp\|pppoe-client\|pptp-server\|prefix\|profile\|proposal\|proxy\|queue\|radius\|resource\|rip\|ripng\|route\|routing\|screen\|script\|security-profiles\|server\|service\|service-port\|settings\|shares\|smb\|sms\|sniffer\|snmp\|snooper\|socks\|sstp-server\|system\|tool\|tracking\|type\|upgrade\|upnp\|user-manager\|users\|user\|vlan\|secret\|vrrp\|watchdog\|web-access\|wireless\|pptp\|pppoe\|lan\|wan\|layer7-protocol\|lease\|simple\|raw);?\\s)+X | | highlight.js:6:12:6:695 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|New\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ | | highlight.js:7:13:7:692 | (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+ | Strings with many repetitions of 'Add' can start matching anywhere after the start of the preceeding (Add\|Clear\|Close\|Copy\|Enter\|Exit\|Find\|Format\|Get\|Hide\|Join\|Lock\|Move\|New\|Open\|Optimize\|Pop\|Push\|Redo\|Remove\|Rename\|Reset\|Resize\|Search\|Select\|Set\|Show\|Skip\|Split\|Step\|Switch\|Undo\|Unlock\|Watch\|Backup\|Checkpoint\|Compare\|Compress\|Convert\|ConvertFrom\|ConvertTo\|Dismount\|Edit\|Expand\|Export\|Group\|Import\|Initialize\|Limit\|Merge\|Out\|Publish\|Restore\|Save\|Sync\|Unpublish\|Update\|Approve\|Assert\|Complete\|Confirm\|Deny\|Disable\|Enable\|Install\|Invoke\|Register\|Request\|Restart\|Resume\|Start\|Stop\|Submit\|Suspend\|Uninstall\|Unregister\|Wait\|Debug\|Measure\|Ping\|Repair\|Resolve\|Test\|Trace\|Connect\|Disconnect\|Read\|Receive\|Send\|Write\|Block\|Grant\|Protect\|Revoke\|Unblock\|Unprotect\|Use\|ForEach\|Sort\|Tee\|Where)+(-)[\\w\\d]+ | | highlight.js:14:17:14:52 | [a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ([ ]*[a-z0-9&#*=?@\\\\><:,()$[\\]_.{}!+%^-]+)+ | @@ -7,8 +7,7 @@ | highlight.js:18:20:18:22 | .*? | Strings starting with '"' and with many repetitions of '"' can start matching anywhere after the start of the preceeding .*? | | highlight.js:18:27:18:29 | .*? | Strings starting with '[' and with many repetitions of '[' can start matching anywhere after the start of the preceeding .*? | | highlight.js:18:33:18:69 | [^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+ | Strings with many repetitions of '$' can start matching anywhere after the start of the preceeding .*? | -| highlight.js:19:56:19:61 | [^\\]]+ | Strings starting with '[' and with many repetitions of '[' can start matching anywhere after the start of the preceeding (\\.\|\\.\\/\|\\/)?(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+)((\\.\|\\/)(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+))* | -| highlight.js:19:141:19:146 | [^\\]]+ | Strings starting with '"".[' and with many repetitions of '$.[' can start matching anywhere after the start of the preceeding (\\.\|\\.\\/\|\\/)?(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+)((\\.\|\\/)(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+))* | +| highlight.js:19:56:19:61 | [^\\]]+ | Strings starting with '[' and with many repetitions of '.[' can start matching anywhere after the start of the preceeding (\\.\|\\.\\/\|\\/)?(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+)((\\.\|\\/)(""\|"[^"]+"\|''\|'[^']+'\|\\[\\]\|\\[[^\\]]+\\]\|[^\\s!"#%&'()*+,.\\/;<=>@\\[\\\\\\]^`{\|}~]+))* | | highlight.js:22:12:22:82 | ((decltype\\(auto\\)\|(?:[a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(?:<.*?>)?)[\\*&\\s]+)+ | Strings with many repetitions of 'A\\t' can start matching anywhere after the start of the preceeding .*? | | highlight.js:22:43:22:45 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding .*? | | highlight.js:22:66:22:68 | .*? | Strings starting with 'A<' and with many repetitions of 'A<' can start matching anywhere after the start of the preceeding \\w* | @@ -17,8 +16,8 @@ | highlight.js:23:42:23:44 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( | | highlight.js:23:63:23:68 | [^<>]+ | Strings starting with 'A<' and with many repetitions of ';>\\tA<' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( | | highlight.js:23:73:23:80 | [\\*&\\s]+ | Strings starting with 'A' and with many repetitions of '\\tA\\t' can start matching anywhere after the start of the preceeding ((decltype\\(auto\\)\|([a-zA-Z_]\\w*::)?[a-zA-Z_]\\w*(<[^<>]+>)?)[\\*&\\s]+)+([a-zA-Z_]\\w*::)?[a-zA-Z]\\w*\\s*\\( | -| highlight.js:26:14:26:34 | (([\\/.])[\\w\\-.\\/=]+)+ | Strings with many repetitions of '..' can start matching anywhere after the start of the preceeding [\\w\\-.\\/=]+ | -| highlight.js:26:22:26:32 | [\\w\\-.\\/=]+ | Strings with many repetitions of '..' can start matching anywhere after the start of the preceeding (([\\/.])[\\w\\-.\\/=]+)+ | +| highlight.js:26:14:26:34 | (([\\/.])[\\w\\-.\\/=]+)+ | Strings with many repetitions of '.-' can start matching anywhere after the start of the preceeding [\\w\\-.\\/=]+ | +| highlight.js:26:22:26:32 | [\\w\\-.\\/=]+ | Strings with many repetitions of '.-' can start matching anywhere after the start of the preceeding (([\\/.])[\\w\\-.\\/=]+)+ | | highlight.js:31:14:31:28 | (?:\\\\.\|[^`\\\\])+ | Strings starting with '`' and with many repetitions of '\\\\`' can start matching anywhere after the start of the preceeding `(?:\\\\.\|[^`\\\\])+` | | highlight.js:38:21:38:23 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding [a-zA-Z_]\\w*\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*\\{ | | highlight.js:38:54:38:59 | [^()]* | Strings starting with 'A((' and with many repetitions of ''' can start matching anywhere after the start of the preceeding [^()]* | @@ -94,6 +93,7 @@ | polynomial-redos.js:64:14:64:15 | Y* | Strings starting with 'fooY' and with many repetitions of 'Y' can start matching anywhere after the start of the preceeding (K\|Y)+ | | polynomial-redos.js:65:14:65:15 | .* | Strings starting with 'fooY' and with many repetitions of 'K' can start matching anywhere after the start of the preceeding (K\|Y)+ | | polynomial-redos.js:66:9:66:10 | .* | Strings starting with 'K' and with many repetitions of 'K' can start matching anywhere after the start of the preceeding (K\|Y).*X | +| polynomial-redos.js:67:8:67:9 | .* | Strings starting with 'X' and with many repetitions of 'Z' can start matching anywhere after the start of the preceeding [^Y].*X | | polynomial-redos.js:68:8:68:9 | .* | Strings starting with 'X' and with many repetitions of 'X' can start matching anywhere after the start of the preceeding [^Y].*$ | | polynomial-redos.js:69:8:69:9 | .* | Strings starting with 'X' and with many repetitions of 'X' can start matching anywhere after the start of the preceeding [^Y].*$ | | polynomial-redos.js:71:51:71:63 | [?\\x21-\\x7E]* | Strings starting with ',-+' and with many repetitions of '++' can start matching anywhere after the start of the preceeding [A-Za-z0-9+/]+ | @@ -123,6 +123,7 @@ | polynomial-redos.js:111:17:111:19 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s*$ | | polynomial-redos.js:112:17:112:19 | \\s+ | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s+$ | | polynomial-redos.js:114:22:114:24 | \\w* | Strings starting with '5' and with many repetitions of '5' can start matching anywhere after the start of the preceeding \\d* | +| polynomial-redos.js:116:21:116:28 | [\\d\\D]*? | Strings starting with '/*' and with many repetitions of 'a/*' can start matching anywhere after the start of the preceeding \\/\\*[\\d\\D]*?\\*\\/ | | polynomial-redos.js:118:17:118:23 | (#\\d+)+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\d+ | | polynomial-redos.js:124:33:124:35 | \\s+ | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding \\s+$ | | polynomial-redos.js:130:21:130:22 | c+ | Strings starting with 'c' and with many repetitions of 'c' can start matching anywhere after the start of the preceeding cc+D | @@ -134,26 +135,22 @@ | regexplib/address.js:27:93:27:95 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*(7\|8)(\\d{7}\|\\d{3}(\\-\|\\s{1})\\d{4})\\s*) | | regexplib/address.js:38:39:38:45 | [ 0-9]* | Strings starting with 'po' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding [ \|\\.]* | | regexplib/address.js:51:220:51:222 | \\w+ | Strings starting with 'C/O ' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:51:331:51:344 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0#' and with many repetitions of 'FL0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/address.js:51:399:51:401 | \\s+ | Strings starting with 'C/O 0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\x20* | +| regexplib/address.js:51:331:51:344 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0#' and with many repetitions of '0APT0' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:51:415:51:419 | \\x20+ | Strings starting with 'C/O 0\\t0' and with many repetitions of ' 0 ' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:51:420:51:422 | \\w+ | Strings starting with 'C/O 0\\t0 ' and with many repetitions of '0 0 ' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:51:616:51:618 | \\w+ | Strings starting with 'C/O 0\\tC/O ' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:51:727:51:740 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0\\t0 0#' and with many repetitions of 'FL0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/address.js:51:796:51:798 | \\s+ | Strings starting with 'C/O 0\\t' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+ | +| regexplib/address.js:51:727:51:740 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0\\t0 0#' and with many repetitions of '0APT0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/address.js:51:796:51:798 | \\s+ | Strings starting with 'C/O 0\\t' and with many repetitions of '\\t\\t' can start matching anywhere after the start of the preceeding \\s+ | | regexplib/address.js:51:803:51:811 | [A-Za-z]+ | Strings starting with 'C/O 0\\t\\t' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:67:379:67:755 | [a-zA-Z0-9ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿ\\.\\,\\-\\/\\' ]+ | Strings starting with '#' and with many repetitions of '#' can start matching anywhere after the start of the preceeding [a-zA-Z0-9ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿ\\.\\,\\-\\/\\']+ | | regexplib/address.js:69:3:69:5 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{3}\\s*) | | regexplib/address.js:69:48:69:50 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{4}\\s*) | | regexplib/address.js:69:93:69:95 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*(7\|8)(\\d{7}\|\\d{3}(\\-\|\\s{1})\\d{4})\\s*) | | regexplib/address.js:75:220:75:222 | \\w+ | Strings starting with 'C/O ' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:75:331:75:344 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0#' and with many repetitions of 'FL0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/address.js:75:399:75:401 | \\s+ | Strings starting with 'C/O 0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\x20* | +| regexplib/address.js:75:331:75:344 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0#' and with many repetitions of '0APT0' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:75:415:75:419 | \\x20+ | Strings starting with 'C/O 0\\t0' and with many repetitions of ' 0 ' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:75:420:75:422 | \\w+ | Strings starting with 'C/O 0\\t0 ' and with many repetitions of '0 0 ' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:75:616:75:618 | \\w+ | Strings starting with 'C/O 0\\tC/O ' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\x20* | -| regexplib/address.js:75:727:75:740 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0\\t0 0#' and with many repetitions of 'FL0' can start matching anywhere after the start of the preceeding \\w+ | -| regexplib/address.js:75:796:75:798 | \\s+ | Strings starting with 'C/O 0\\t' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+ | +| regexplib/address.js:75:727:75:740 | [a-zA-Z0-9\\-]+ | Strings starting with 'C/O 0\\t0 0#' and with many repetitions of '0APT0' can start matching anywhere after the start of the preceeding \\w+ | +| regexplib/address.js:75:796:75:798 | \\s+ | Strings starting with 'C/O 0\\t' and with many repetitions of '\\t\\t' can start matching anywhere after the start of the preceeding \\s+ | | regexplib/address.js:75:803:75:811 | [A-Za-z]+ | Strings starting with 'C/O 0\\t\\t' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding \\w+ | | regexplib/address.js:85:15:85:49 | ([0-9]\|[ ]\|[-]\|[\\(]\|[\\)]\|ext.\|[,])+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (?([0-9]\|[ ]\|[-]\|[\\(]\|[\\)]\|ext.\|[,])+)([ ]\|[:]\|\\t\|[-])*(?Home\|Office\|Work\|Away\|Fax\|FAX\|Phone) | | regexplib/address.js:85:51:85:67 | ([ ]\|[:]\|\\t\|[-])* | Strings starting with '0' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding ([0-9]\|[ ]\|[-]\|[\\(]\|[\\)]\|ext.\|[,])+ | @@ -167,10 +164,8 @@ | regexplib/email.js:5:24:5:35 | [a-zA-Z0-9]+ | Strings starting with '0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding ([_\\.\\-]?[a-zA-Z0-9]+)* | | regexplib/email.js:5:63:5:74 | [a-zA-Z0-9]+ | Strings starting with '0@0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [A-Za-z0-9]+ | | regexplib/email.js:8:16:8:49 | [^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | -| regexplib/email.js:8:57:8:84 | (?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))* | Strings starting with '"' and with many repetitions of '\\\\"' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | | regexplib/email.js:8:89:8:174 | (?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))* | Strings starting with '!' and with many repetitions of '.!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | | regexplib/email.js:8:100:8:133 | [^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+ | Strings starting with '!.' and with many repetitions of '!.!' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | -| regexplib/email.js:8:141:8:168 | (?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))* | Strings starting with '!."' and with many repetitions of '".!."' can start matching anywhere after the start of the preceeding (?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\"))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\"(?:(?:[^\\"\\\\\\r\\n])\|(?:\\\\.))*\\")))*)@(?(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\]))(?:\\.(?:(?:[^ \\t\\(\\)\\<\\>@,;\\:\\\\\\"\\.\\[\\]\\r\\n]+)\|(?:\\[(?:(?:[^\\[\\]\\\\\\r\\n])\|(?:\\\\.))*\\])))*) | | regexplib/email.js:12:2:12:4 | \\w+ | Strings with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | | regexplib/email.js:12:5:12:15 | ([-+.]\\w+)* | Strings starting with '0' and with many repetitions of '+0' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | | regexplib/email.js:12:11:12:13 | \\w+ | Strings starting with '0+' and with many repetitions of '0+' can start matching anywhere after the start of the preceeding \\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)* | @@ -201,16 +196,12 @@ | regexplib/markup.js:2:3:2:7 | [^>]* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*> | | regexplib/markup.js:3:440:3:456 | (\\s(?.+?))* | Strings starting with '.+?))* | -| regexplib/markup.js:5:1525:5:1527 | \\s* | Strings starting with '?'DateLiteral' ?# Per the VB Spec : DateLiteral ::= '#' DateOrTime '#' # ?'DateOrTime' DateValue ?# TimeValue ::= HourValue : MinuteValue 10 ?# Hour 01 - 24 : 60 ?# Minute 01 - 60 : ?# Optional Minute :01 - :60 ' and with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s* | -| regexplib/markup.js:6:11:6:25 | [\\w\\*\\)\\(\\,\\s]+ | Strings starting with 'SELECT\\t' and with many repetitions of 'SELECT\\t' can start matching anywhere after the start of the preceeding (SELECT\\s[\\w\\*\\)\\(\\,\\s]+\\sFROM\\s[\\w]+) | | regexplib/markup.js:6:99:6:113 | [\\s\\w\\d\\)\\(\\,]* | Strings starting with ' INSERT\\tINTO\\t0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [\\d\\w]+ | | regexplib/markup.js:7:8:7:23 | (?:\\\\.\|[^\\\\"]*)* | Strings starting with '"!' and with many repetitions of '\\\\"!\\\\a' can start matching anywhere after the start of the preceeding "([^"](?:\\\\.\|[^\\\\"]*)*)" | | regexplib/markup.js:9:6:9:13 | [\\s\\S]*? | Strings starting with ' | | regexplib/markup.js:12:40:12:42 | .*? | Strings starting with ') | | regexplib/markup.js:12:117:12:121 | [^>]* | Strings starting with ']*>) | -| regexplib/markup.js:12:149:12:153 | [^>]* | Strings starting with 'font-family:' and with many repetitions of 'font-family:' can start matching anywhere after the start of the preceeding (font-family:[^>]*[;']) | -| regexplib/markup.js:12:171:12:175 | [^>]* | Strings starting with 'font-size:' and with many repetitions of 'font-size:' can start matching anywhere after the start of the preceeding (font-size:[^>]*[;'])(?-s) | | regexplib/markup.js:13:6:13:12 | [^"']+? | Strings starting with '<' and with many repetitions of '!' can start matching anywhere after the start of the preceeding .*? | | regexplib/markup.js:13:14:13:16 | .+? | Strings starting with '<' and with many repetitions of '!' can start matching anywhere after the start of the preceeding .*? | | regexplib/markup.js:14:13:14:14 | .* | Strings starting with '<' and with many repetitions of 'a' can start matching anywhere after the start of the preceeding .* | @@ -226,8 +217,7 @@ | regexplib/markup.js:20:52:20:53 | .* | Strings with many repetitions of '=color' can start matching anywhere after the start of the preceeding [^>]+ | | regexplib/markup.js:20:155:20:156 | '+ | Strings with many repetitions of '''' can start matching anywhere after the start of the preceeding '+ | | regexplib/markup.js:20:197:20:198 | "+ | Strings with many repetitions of '""' can start matching anywhere after the start of the preceeding "+ | -| regexplib/markup.js:20:245:20:247 | .*? | Strings with many repetitions of 'color: # IF found THEN move ahead "" # single or double # or no quotes\\t' can start matching anywhere after the start of the preceeding .*? | -| regexplib/markup.js:20:274:20:276 | .*? | Strings starting with ']+color.*>) #IF\\/THEN lookahead color in tag (.*?color\\s*?[=\|:]\\s*?) # IF found THEN move ahead ('+\\#*?[\\w\\s]*'+ # CAPTURE ColorName\\/Hex \|"+\\#*?[\\w\\s]*"+ # single or double \|\\#*\\w*\\b) # or no quotes\t.*?> # & move to end of tag \|.*?> # ELSE move to end of Tag ) # Close the If\\/Then lookahead # Use Multiline and IgnoreCase # Replace the matches from RE with MatchEvaluator below: # if m.Groups(1).Value<>"" then # Return "" # else # Return "" # end if | +| regexplib/markup.js:20:274:20:276 | .*? | Strings starting with ']+color.*>) #IF\\/THEN lookahead color in tag (.*?color\\s*?[=\|:]\\s*?) # IF found THEN move ahead ('+\\#*?[\\w\\s]*'+ # CAPTURE ColorName\\/Hex \|"+\\#*?[\\w\\s]*"+ # single or double \|\\#*\\w*\\b) # or no quotes\t.*?> # & move to end of tag \|.*?> # ELSE move to end of Tag ) # Close the If\\/Then lookahead # Use Multiline and IgnoreCase # Replace the matches from RE with MatchEvaluator below: # if m.Groups(1).Value<>"" then # Return "" # else # Return "" # end if | | regexplib/markup.js:24:39:24:41 | \\s+ | Strings starting with '<A' and with many repetitions of '\\t-\\t!=\\t' can start matching anywhere after the start of the preceeding \\s* | | regexplib/markup.js:24:43:24:45 | \\S+ | Strings starting with '<A\\t' and with many repetitions of '-\\t!=' can start matching anywhere after the start of the preceeding \\s* | | regexplib/markup.js:24:48:24:50 | \\s* | Strings starting with '<A\\t!' and with many repetitions of '\\t=-\\t!\\t' can start matching anywhere after the start of the preceeding \\s+ | @@ -236,6 +226,7 @@ | regexplib/markup.js:25:45:25:49 | [^>]* | Strings starting with ']* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*name[\\s]*=[\\s]*"?[^\\w_]*"?[^>]*> | | regexplib/markup.js:27:34:27:38 | [^>]* | Strings starting with ']* | Strings starting with '<' and with many repetitions of ']*)(\\s[^<]*)> | | regexplib/markup.js:37:15:37:19 | [\\w]* | Strings starting with '[0' and with many repetitions of '0' can start matching anywhere after the start of the preceeding \\w+ | @@ -245,6 +236,7 @@ | regexplib/markup.js:43:45:43:49 | [^>]* | Strings starting with ']* | Strings starting with '<' and with many repetitions of '<' can start matching anywhere after the start of the preceeding <[^>]*name[\\s]*=[\\s]*"?[^\\w_]*"?[^>]*> | | regexplib/markup.js:44:34:44:38 | [^>]* | Strings starting with '' and with many repetitions of '' can start matching anywhere after the start of the preceeding [^']*? | | regexplib/markup.js:62:9:62:14 | [^>]*? | Strings starting with '' and with many repetitions of '>;' can start matching anywhere after the start of the preceeding .*? | | regexplib/markup.js:62:57:62:59 | .*? | Strings starting with '' and with many repetitions of '>a' can start matching anywhere after the start of the preceeding .*? | +| regexplib/markup.js:63:70:63:77 | [\\w\\W]*? | Strings with many repetitions of 'a/*' can start matching anywhere after the start of the preceeding (?((?m:^[\\t ]*\\/{2}[^\\n\\r\\v\\f]+[\\n\\r\\v\\f]*){2,})\|(\\/\\*[\\w\\W]*?\\*\\/)) | | regexplib/misc.js:4:36:4:44 | [a-zA-Z]* | Strings starting with 'A' and with many repetitions of 'AA' can start matching anywhere after the start of the preceeding [a-zA-Z]+ | | regexplib/misc.js:76:2:76:27 | (AUX\|PRN\|NUL\|COM\\d\|LPT\\d)+ | Strings with many repetitions of 'AUX' can start matching anywhere after the start of the preceeding (AUX\|PRN\|NUL\|COM\\d\|LPT\\d)+\\s*$ | | regexplib/misc.js:81:31:81:45 | [^a-z\\:\\,\\(\\)]* | Strings starting with '#' and with many repetitions of '#' can start matching anywhere after the start of the preceeding ([A-Zäöü0-9\\/][^a-z\\:\\,\\(\\)]*[A-Zäöü0-9])($\|[\\.\\:\\,\\;\\)\\-\\ \\+]\|s\\b) | @@ -279,7 +271,7 @@ | regexplib/misc.js:95:25:95:26 | .+ | Strings starting with 'at\\t' and with many repetitions of 'at\\ta' can start matching anywhere after the start of the preceeding (at\\s)(?.+)(\\.)(?[^\\.]*)(\\()(?[^\\)]*)(\\))((\\sin\\s)(?.+)(:line )(?[\\d]*))? | | regexplib/misc.js:95:71:95:76 | [^\\)]* | Strings starting with 'at\\ta.(' and with many repetitions of '((' can start matching anywhere after the start of the preceeding .+ | | regexplib/misc.js:95:103:95:104 | .+ | Strings starting with 'at\\ta.()\\tin\\t' and with many repetitions of '()\\tin\\t-' can start matching anywhere after the start of the preceeding .+ | -| regexplib/misc.js:101:52:101:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.htm' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | +| regexplib/misc.js:101:52:101:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.asp' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | | regexplib/misc.js:112:3:112:5 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?\\s*\\d{6}\\s*) | | regexplib/misc.js:112:32:112:34 | \\s* | Strings with many repetitions of '\\t' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?\\s*\\d{3}\\s*\\d{4}\\s*) | | regexplib/misc.js:114:6:114:8 | \\\|+ | Strings starting with 'a' and with many repetitions of '\|' can start matching anywhere after the start of the preceeding .+ | @@ -290,7 +282,7 @@ | regexplib/misc.js:123:36:123:38 | .*? | Strings starting with '?se[A' and with many repetitions of '?se[Aa' can start matching anywhere after the start of the preceeding (?s)(?:\\e\\[(?:(\\d+);?)*([A-Za-z])(.*?))(?=\\e\\[\|\\z) | | regexplib/misc.js:126:15:126:20 | [a-z]+ | Strings starting with 'a' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding [a-z]+ | | regexplib/misc.js:141:15:141:19 | [^;]+ | Strings starting with '{\\\\f\\\\' and with many repetitions of '{\\\\f\\\\:' can start matching anywhere after the start of the preceeding (\\{\\\\f\\d*)\\\\([^;]+;) | -| regexplib/misc.js:144:52:144:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.htm' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | +| regexplib/misc.js:144:52:144:70 | [a-z0-9\\/\\.\\?\\=\\&]* | Strings starting with '".htm' and with many repetitions of '.asp' can start matching anywhere after the start of the preceeding [a-z0-9\\/\\.\\?\\=\\&]* | | regexplib/misc.js:148:12:148:18 | [^\\s>]+ | Strings starting with '<' and with many repetitions of ']+(\\s+[^"'=]+(=("[^"]*")\|('[^\\']*')\|([^\\s"'>]*))?)*\\s*\\/?> | | regexplib/misc.js:148:20:148:22 | \\s+ | Strings starting with '' and with many repetitions of 'href="">;' can start matching anywhere after the start of the preceeding href\\s*=\\s*(?:(?:\\"(?[^\\"]*)\\")\|(?[^\\s*] ))>(?[^<]+)<\\/\\w> | +| regexplib/uri.js:29:2:29:45 | ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+ | Strings with many repetitions of 'ftp://' can start matching anywhere after the start of the preceeding ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+(([a-zA-Z0-9\\.-]+\\.[a-zA-Z]{2,4})\|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(\\/[a-zA-Z0-9%:/-_\\?\\.'~]*)? | +| regexplib/uri.js:31:65:31:69 | [^<]+ | Strings starting with 'href=! >' and with many repetitions of 'href=! >;' can start matching anywhere after the start of the preceeding href\\s*=\\s*(?:(?:\\"(?<url>[^\\"]*)\\")\|(?<url>[^\\s*] ))>(?<title>[^<]+)<\\/\\w> | | regexplib/uri.js:34:3:34:9 | [^\\=&]+ | Strings with many repetitions of '%' can start matching anywhere after the start of the preceeding ([^\\=&]+)(?<!param1\|param2\|param3)\\=([^\\=&]+)(&)? | | regexplib/uri.js:36:40:36:42 | \\d* | Strings starting with '$1' and with many repetitions of '1' can start matching anywhere after the start of the preceeding [1-9]+ | | regexplib/uri.js:38:20:38:28 | [a-z0-9]+ | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [a-z]+ | @@ -406,8 +394,7 @@ | regexplib/uri.js:55:20:55:28 | [a-z0-9]+ | Strings starting with 'a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [a-z]+ | | regexplib/uri.js:55:35:55:40 | [a-z]+ | Strings starting with 'a.' and with many repetitions of 'aa' can start matching anywhere after the start of the preceeding [a-z0-9]+ | | regexplib/uri.js:55:52:55:60 | [a-z0-9]+ | Strings starting with 'a.a' and with many repetitions of '0' can start matching anywhere after the start of the preceeding [a-z]+ | -| regexplib/uri.js:58:2:58:45 | ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+ | Strings with many repetitions of 'wwwa' can start matching anywhere after the start of the preceeding ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+(([a-zA-Z0-9\\.-]+\\.[a-zA-Z]{2,4})\|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(\\/[a-zA-Z0-9%:/-_\\?\\.'~]*)? | -| regexplib/uri.js:58:48:58:62 | [a-zA-Z0-9\\.-]+ | Strings starting with 'wwwa' and with many repetitions of 'www--' can start matching anywhere after the start of the preceeding ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+ | +| regexplib/uri.js:58:2:58:45 | ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+ | Strings with many repetitions of 'ftp://' can start matching anywhere after the start of the preceeding ((http\\:\\/\\/\|https\\:\\/\\/\|ftp\\:\\/\\/)\|(www.))+(([a-zA-Z0-9\\.-]+\\.[a-zA-Z]{2,4})\|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(\\/[a-zA-Z0-9%:/-_\\?\\.'~]*)? | | regexplib/uri.js:64:31:64:36 | [\\w-]+ | Strings with many repetitions of '-' can start matching anywhere after the start of the preceeding [\\w-\\s]* | | regexplib/uri.js:70:16:70:31 | [a-zA-Z0-9\\-\\.]+ | Strings starting with '0' and with many repetitions of '00' can start matching anywhere after the start of the preceeding [a-zA-Z0-9]+ | | regexplib/uri.js:71:75:71:89 | [^\\/\\\\:*?"<>\|]+ | Strings starting with 'A:\\\\!.' and with many repetitions of '!.' can start matching anywhere after the start of the preceeding [^\\/\\\\:*?"<>\|]+ | @@ -489,10 +476,10 @@ | tst.js:254:51:254:53 | \\w* | Strings starting with 'foobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:63:254:65 | \\s* | Strings starting with 'foobarbazfoobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' can start matching anywhere after the start of the preceeding \\d* | | tst.js:254:75:254:77 | \\d* | Strings starting with 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' and with many repetitions of 'foobarbazfoobarbazfoobarbazfoobarbazfoobarbazfoobarbaz' can start matching anywhere after the start of the preceeding \\s* | -| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | Strings with many repetitions of 'athisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)*- | +| tst.js:257:14:257:116 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | Strings with many repetitions of '\\tthisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)*- | | tst.js:260:14:260:77 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | Strings with many repetitions of 'this0query' can start matching anywhere after the start of the preceeding \\w+ | | tst.js:260:68:260:70 | \\w+ | Strings starting with 'this' and with many repetitions of 'this' can start matching anywhere after the start of the preceeding (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | -| tst.js:263:15:263:117 | (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)* | Strings with many repetitions of 'thisisagoddamnlongstringforstresstestingthequery' can start matching anywhere after the start of the preceeding (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)*- | +| tst.js:263:15:263:117 | (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)* | Strings with many repetitions of 'imanotherbutunrelatedstringcomparedtotheotherstring' can start matching anywhere after the start of the preceeding (thisisagoddamnlongstringforstresstestingthequery\|imanotherbutunrelatedstringcomparedtotheotherstring)*- | | tst.js:272:21:272:22 | b+ | Strings with many repetitions of 'b' can start matching anywhere after the start of the preceeding (b+)+ | | tst.js:275:25:275:27 | \\s+ | Strings starting with '<0' and with many repetitions of '\\t0="\\t0="\\t' can start matching anywhere after the start of the preceeding [^"]* | | tst.js:275:28:275:30 | \\w+ | Strings starting with '<0\\t' and with many repetitions of '0="\\t0="\\t' can start matching anywhere after the start of the preceeding [^"]* | @@ -535,7 +522,7 @@ | tst.js:375:15:375:16 | x* | Strings with many repetitions of 'x' can start matching anywhere after the start of the preceeding (x*)+(?=$\|y) | | tst.js:378:16:378:22 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$) | | tst.js:379:16:379:22 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$\|y) | -| tst.js:381:15:381:24 | (foo\|FOO)* | Strings with many repetitions of 'foo' can start matching anywhere after the start of the preceeding (foo\|FOO)*bar | +| tst.js:381:15:381:24 | (foo\|FOO)* | Strings with many repetitions of 'FOO' can start matching anywhere after the start of the preceeding (foo\|FOO)*bar | | tst.js:382:14:382:23 | (foo\|FOO)* | Strings with many repetitions of 'foo' can start matching anywhere after the start of the preceeding (foo\|FOO)*bar | | tst.js:384:15:384:26 | ([AB]\|[ab])* | Strings with many repetitions of 'A' can start matching anywhere after the start of the preceeding ([AB]\|[ab])*C | | tst.js:385:14:385:25 | ([DE]\|[de])* | Strings with many repetitions of 'd' can start matching anywhere after the start of the preceeding ([DE]\|[de])*F | From 9b4914c3f6c3e4c90021ad9c54974ca8623e4be1 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 13:47:23 +0100 Subject: [PATCH 034/219] Ruby: split ActionDispatch modelling into multiple component files --- .../codeql/ruby/frameworks/ActionDispatch.qll | 1003 +---------------- .../ruby/frameworks/actiondispatch/Mime.qll | 46 + .../frameworks/actiondispatch/Routing.qll | 961 ++++++++++++++++ 3 files changed, 1010 insertions(+), 1000 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll index cc898abe034..c8720d5f1dc 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll @@ -3,1010 +3,13 @@ * Version: 7.1.0. */ -private import codeql.ruby.AST -private import codeql.ruby.Concepts -private import codeql.ruby.DataFlow -private import codeql.ruby.Regexp as RE -private import codeql.ruby.dataflow.FlowSummary -private import codeql.ruby.frameworks.data.ModelsAsData - /** * Models the `ActionDispatch` HTTP library, which is part of Rails. * Version: 7.1.0. */ module ActionDispatch { - /** - * Type summaries for the `Mime::Type` class, i.e. method calls that produce new - * `Mime::Type` instances. - */ - private class MimeTypeTypeSummary extends ModelInput::TypeModelCsv { - override predicate row(string row) { - // type1;type2;path - row = - [ - // Mime[type] : Mime::Type (omitted) - // Method names with brackets like [] cannot be represented in MaD. - // Mime.fetch(type) : Mime::Type - "Mime::Type;Mime!;Method[fetch].ReturnValue", - // Mime::Type.lookup(str) : Mime::Type - "Mime::Type;Mime::Type!;Method[lookup].ReturnValue", - // Mime::Type.lookup_by_extension(str) : Mime::Type - "Mime::Type;Mime::Type!;Method[lookup_by_extension].ReturnValue", - // Mime::Type.register(str) : Mime::Type - "Mime::Type;Mime::Type!;Method[register].ReturnValue", - // Mime::Type.register_alias(str) : Mime::Type - "Mime::Type;Mime::Type!;Method[register_alias].ReturnValue", - ] - } - } + private import actiondispatch.Mime + import actiondispatch.Routing - /** - * An argument to `Mime::Type#match?`, which is converted to a RegExp via - * `Regexp.new`. - */ - class MimeTypeMatchRegExpInterpretation extends RE::RegExpInterpretation::Range { - MimeTypeMatchRegExpInterpretation() { - this = ModelOutput::getATypeNode("Mime::Type").getAMethodCall(["match?", "=~"]).getArgument(0) - } - } - - /** - * Models routing configuration specified using the `ActionDispatch` library, which is part of Rails. - */ - module Routing { - /** - * A block that defines some routes. - * Route blocks can contribute to the path or controller namespace of their child routes. - * For example, in the block below - * ```rb - * scope path: "/admin" do - * get "/dashboard", to: "admin_dashboard#show" - * end - * ``` - * the route defined by the call to `get` has the full path `/admin/dashboard`. - * We track these contributions via `getPathComponent` and `getControllerComponent`. - */ - abstract private class RouteBlock extends TRouteBlock { - /** - * Gets the name of a primary CodeQL class to which this route block belongs. - */ - string getAPrimaryQlClass() { result = "RouteBlock" } - - /** - * Gets a string representation of this route block. - */ - string toString() { none() } - - /** - * Gets a `Stmt` within this route block. - */ - abstract Stmt getAStmt(); - - /** - * Gets the parent of this route block, if one exists. - */ - abstract RouteBlock getParent(); - - /** - * Gets the `n`th parent of this route block. - * The zeroth parent is this block, the first parent is the direct parent of this block, etc. - */ - RouteBlock getParent(int n) { - if n = 0 then result = this else result = this.getParent().getParent(n - 1) - } - - /** - * Gets the component of the path defined by this block, if it exists. - */ - abstract string getPathComponent(); - - /** - * Gets the component of the controller namespace defined by this block, if it exists. - */ - abstract string getControllerComponent(); - - /** - * Gets the location of this route block. - */ - abstract Location getLocation(); - } - - /** - * A route block that is not the top-level block. - * This block will always have a parent. - */ - abstract private class NestedRouteBlock extends RouteBlock { - RouteBlock parent; - - override RouteBlock getParent() { result = parent } - - override string getAPrimaryQlClass() { result = "NestedRouteBlock" } - } - - /** - * A top-level routes block. - * ```rb - * Rails.application.routes.draw do - * ... - * end - * ``` - */ - private class TopLevelRouteBlock extends RouteBlock, TTopLevelRouteBlock { - MethodCall call; - // Routing blocks create scopes which define the namespace for controllers and paths, - // though they can be overridden in various ways. - // The namespaces can differ, so we track them separately. - Block block; - - TopLevelRouteBlock() { this = TTopLevelRouteBlock(_, call, block) } - - override string getAPrimaryQlClass() { result = "TopLevelRouteBlock" } - - Block getBlock() { result = block } - - override Stmt getAStmt() { result = block.getAStmt() } - - override RouteBlock getParent() { none() } - - override string toString() { result = call.toString() } - - override Location getLocation() { result = call.getLocation() } - - override string getPathComponent() { none() } - - override string getControllerComponent() { none() } - } - - /** - * A route block defined by a call to `constraints`. - * ```rb - * constraints(foo: /some_regex/) do - * get "/posts/:foo", to "posts#something" - * end - * ``` - * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-constraints - */ - private class ConstraintsRouteBlock extends NestedRouteBlock, TConstraintsRouteBlock { - private Block block; - private MethodCall call; - - ConstraintsRouteBlock() { this = TConstraintsRouteBlock(parent, call, block) } - - override string getAPrimaryQlClass() { result = "ConstraintsRouteBlock" } - - override Stmt getAStmt() { result = block.getAStmt() } - - override string getPathComponent() { result = "" } - - override string getControllerComponent() { result = "" } - - override string toString() { result = call.toString() } - - override Location getLocation() { result = call.getLocation() } - } - - /** - * A route block defined by a call to `scope`. - * ```rb - * scope(path: "/some_path", module: "some_module") do - * get "/posts/:foo", to "posts#something" - * end - * ``` - * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope - */ - private class ScopeRouteBlock extends NestedRouteBlock, TScopeRouteBlock { - private MethodCall call; - private Block block; - - ScopeRouteBlock() { this = TScopeRouteBlock(parent, call, block) } - - override string getAPrimaryQlClass() { result = "ScopeRouteBlock" } - - override Stmt getAStmt() { result = block.getAStmt() } - - override string toString() { result = call.toString() } - - override Location getLocation() { result = call.getLocation() } - - override string getPathComponent() { - call.getKeywordArgument("path").getConstantValue().isStringlikeValue(result) - or - not exists(call.getKeywordArgument("path")) and - call.getArgument(0).getConstantValue().isStringlikeValue(result) - } - - override string getControllerComponent() { - call.getKeywordArgument(["controller", "module"]) - .getConstantValue() - .isStringlikeValue(result) - } - } - - /** - * A route block defined by a call to `resources`. - * ```rb - * resources :articles do - * get "/comments", to "comments#index" - * end - * ``` - * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources - */ - private class ResourcesRouteBlock extends NestedRouteBlock, TResourcesRouteBlock { - private MethodCall call; - private Block block; - - ResourcesRouteBlock() { this = TResourcesRouteBlock(parent, call, block) } - - override string getAPrimaryQlClass() { result = "ResourcesRouteBlock" } - - override Stmt getAStmt() { result = block.getAStmt() } - - /** - * Gets the `resources` call that gives rise to this route block. - */ - MethodCall getDefiningMethodCall() { result = call } - - override string getPathComponent() { - exists(string resource | - call.getArgument(0).getConstantValue().isStringlikeValue(resource) - | - result = resource + "/:" + singularize(resource) + "_id" - ) - } - - override string getControllerComponent() { result = "" } - - override string toString() { result = call.toString() } - - override Location getLocation() { result = call.getLocation() } - } - - /** - * A route block that is guarded by a conditional statement. - * For example: - * ```rb - * if Rails.env.test? - * get "/foo/bar", to: "foo#bar" - * end - * ``` - * We ignore the condition and analyze both branches to obtain as - * much routing information as possible. - */ - private class ConditionalRouteBlock extends NestedRouteBlock, TConditionalRouteBlock { - private ConditionalExpr e; - - ConditionalRouteBlock() { this = TConditionalRouteBlock(parent, e) } - - override string getAPrimaryQlClass() { result = "ConditionalRouteBlock" } - - override Stmt getAStmt() { result = e.getBranch(_).(StmtSequence).getAStmt() } - - override string getPathComponent() { none() } - - override string getControllerComponent() { none() } - - override string toString() { result = e.toString() } - - override Location getLocation() { result = e.getLocation() } - } - - /** - * A route block defined by a call to `namespace`. - * ```rb - * namespace :admin do - * resources :posts - * end - * ``` - * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-namespace - */ - private class NamespaceRouteBlock extends NestedRouteBlock, TNamespaceRouteBlock { - private MethodCall call; - private Block block; - - NamespaceRouteBlock() { this = TNamespaceRouteBlock(parent, call, block) } - - override Stmt getAStmt() { result = block.getAStmt() } - - override string getPathComponent() { result = this.getNamespace() } - - override string getControllerComponent() { result = this.getNamespace() } - - private string getNamespace() { - call.getArgument(0).getConstantValue().isStringlikeValue(result) - } - - override string toString() { result = call.toString() } - - override Location getLocation() { result = call.getLocation() } - } - - /** - * A route configuration. This defines a combination of HTTP method and URL - * path which should be routed to a particular controller-action pair. - * This can arise from an explicit call to a routing method, for example: - * ```rb - * get "/photos", to: "photos#index" - * ``` - * or via a convenience method like `resources`, which defines multiple routes at once: - * ```rb - * resources :photos - * ``` - */ - class Route extends TRoute instanceof RouteImpl { - /** - * Gets the name of a primary CodeQL class to which this route belongs. - */ - string getAPrimaryQlClass() { result = "Route" } - - /** Gets a string representation of this route. */ - string toString() { result = super.toString() } - - /** - * Gets the location of the method call that defines this route. - */ - Location getLocation() { result = super.getLocation() } - - /** - * Gets the full controller targeted by this route. - */ - string getController() { result = super.getController() } - - /** - * Gets the action targeted by this route. - */ - string getAction() { result = super.getAction() } - - /** - * Gets the HTTP method of this route. - * The result is one of [get, post, put, patch, delete]. - */ - string getHttpMethod() { result = super.getHttpMethod() } - - /** - * Gets the full path of the route. - */ - string getPath() { result = super.getPath() } - - /** - * Get a URL capture. This is a wildcard URL segment whose value is placed in `params`. - * For example, in - * ```ruby - * get "/foo/:bar/baz", to: "users#index" - * ``` - * the capture is `:bar`. - */ - string getACapture() { result = super.getACapture() } - } - - /** - * The implementation of `Route`. - * This class is abstract and is thus kept private so we don't expose it to - * users. - * Extend this class to add new instances of routes. - */ - abstract private class RouteImpl extends TRoute { - /** - * Gets the name of a primary CodeQL class to which this route belongs. - */ - string getAPrimaryQlClass() { result = "RouteImpl" } - - MethodCall method; - - /** Gets a string representation of this route. */ - string toString() { result = method.toString() } - - /** - * Gets the location of the method call that defines this route. - */ - Location getLocation() { result = method.getLocation() } - - /** - * Gets the method call that defines this route. - */ - MethodCall getDefiningMethodCall() { result = method } - - /** - * Get the last component of the path. For example, in - * ```rb - * get "/photos", to: "photos#index" - * ``` - * this is `/photos`. - * If the string has any interpolations, this predicate will have no result. - */ - abstract string getLastPathComponent(); - - /** - * Gets the HTTP method of this route. - * The result is one of [get, post, put, patch, delete]. - */ - abstract string getHttpMethod(); - - /** - * Gets the last controller component. - * This is the controller specified in the route itself. - */ - abstract string getLastControllerComponent(); - - /** - * Gets a component of the controller. - * This behaves identically to `getPathComponent`, but for controller information. - */ - string getControllerComponent(int n) { - if n = 0 - then result = this.getLastControllerComponent() - else result = this.getParentBlock().getParent(n - 1).getControllerComponent() - } - - /** - * Gets the full controller targeted by this route. - */ - string getController() { - result = - concat(int n | - this.getControllerComponent(n) != "" - | - this.getControllerComponent(n), "/" order by n desc - ) - } - - /** - * Gets the action targeted by this route. - */ - abstract string getAction(); - - /** - * Gets the parent `RouteBlock` of this route. - */ - abstract RouteBlock getParentBlock(); - - /** - * Gets a component of the path. Components are numbered from 0 up, where 0 - * is the last component, 1 is the second-last, etc. - * For example, in the following route: - * - * ```rb - * namespace path: "foo" do - * namespace path: "bar" do - * get "baz", to: "foo#bar - * end - * end - * ``` - * - * the components are: - * - * | n | component - * |---|---------- - * | 0 | baz - * | 1 | bar - * | 2 | foo - */ - string getPathComponent(int n) { - if n = 0 - then result = this.getLastPathComponent() - else result = this.getParentBlock().getParent(n - 1).getPathComponent() - } - - /** - * Gets the full path of the route. - */ - string getPath() { - result = - concat(int n | - this.getPathComponent(n) != "" - | - // Strip leading and trailing slashes from each path component before combining - stripSlashes(this.getPathComponent(n)), "/" order by n desc - ) - } - - /** - * Get a URL capture. This is a wildcard URL segment whose value is placed in `params`. - * For example, in - * ```ruby - * get "/foo/:bar/baz", to: "users#index" - * ``` - * the capture is `:bar`. - * We don't currently make use of this, but it may be useful in future to more accurately - * model the contents of the `params` hash. - */ - string getACapture() { result = this.getPathComponent(_).regexpFind(":[^:/]+", _, _) } - } - - /** - * A route generated by an explicit call to `get`, `post`, etc. - * - * ```ruby - * get "/photos", to: "photos#index" - * put "/photos/:id", to: "photos#update" - * ``` - */ - private class ExplicitRoute extends RouteImpl, TExplicitRoute { - RouteBlock parentBlock; - - ExplicitRoute() { this = TExplicitRoute(parentBlock, method) } - - override string getAPrimaryQlClass() { result = "ExplicitRoute" } - - override RouteBlock getParentBlock() { result = parentBlock } - - override string getLastPathComponent() { - method.getArgument(0).getConstantValue().isStringlikeValue(result) - } - - override string getLastControllerComponent() { - method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result) - or - not exists(method.getKeywordArgument("controller")) and - ( - result = extractController(this.getActionString()) - or - // If controller is not specified, and we're in a `resources` route block, use the controller of that route. - // For example, in - // - // resources :posts do - // get "timestamp", to: :timestamp - // end - // - // The route is GET /posts/:post_id/timestamp => posts/timestamp - not exists(extractController(this.getActionString())) and - exists(ResourcesRoute r | - r.getDefiningMethodCall() = parentBlock.(ResourcesRouteBlock).getDefiningMethodCall() - | - result = r.getLastControllerComponent() - ) - ) - } - - private string getActionString() { - method.getKeywordArgument("to").getConstantValue().isStringlikeValue(result) - or - method.getKeywordArgument("to").(MethodCall).getMethodName() = "redirect" and - result = "<redirect>#<redirect>" - } - - override string getAction() { - // get "/photos", action: "index" - method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result) - or - not exists(method.getKeywordArgument("action")) and - ( - // get "/photos", to: "photos#index" - // get "/photos", to: redirect("some_url") - result = extractAction(this.getActionString()) - or - // resources :photos, only: [] do - // get "/", to: "index" - // end - not exists(extractAction(this.getActionString())) and result = this.getActionString() - or - // get :some_action - not exists(this.getActionString()) and - method.getArgument(0).getConstantValue().isStringlikeValue(result) - ) - } - - override string getHttpMethod() { result = method.getMethodName().toString() } - } - - /** - * A route generated by a call to `resources`. - * - * ```ruby - * resources :photos - * ``` - * This creates eight routes, equivalent to the following code: - * ```ruby - * get "/photos", to: "photos#index" - * get "/photos/new", to: "photos#new" - * post "/photos", to: "photos#create" - * get "/photos/:id", to: "photos#show" - * get "/photos/:id/edit", to: "photos#edit" - * patch "/photos/:id", to: "photos#update" - * put "/photos/:id", to: "photos#update" - * delete "/photos/:id", to: "photos#delete" - * ``` - * - * `resources` can take a block. Any routes defined inside the block will inherit a path component of - * `/<resource>/:<resource>_id`. For example: - * - * ```ruby - * resources :photos do - * get "/foo", to: "photos#foo" - * end - * ``` - * This creates the eight default routes, plus one more, which is nested under "/photos/:photo_id", equivalent to: - * ```ruby - * get "/photos/:photo_id/foo", to: "photos#foo" - * ``` - */ - private class ResourcesRoute extends RouteImpl, TResourcesRoute { - RouteBlock parent; - string action; - string httpMethod; - string pathComponent; - - ResourcesRoute() { - exists(string resource | - this = TResourcesRoute(parent, method, action) and - method.getArgument(0).getConstantValue().isStringlikeValue(resource) and - isDefaultResourceRoute(resource, httpMethod, pathComponent, action) - ) - } - - override string getAPrimaryQlClass() { result = "ResourcesRoute" } - - override RouteBlock getParentBlock() { result = parent } - - override string getLastPathComponent() { result = pathComponent } - - override string getLastControllerComponent() { - method.getArgument(0).getConstantValue().isStringlikeValue(result) - } - - override string getAction() { result = action } - - override string getHttpMethod() { result = httpMethod } - } - - /** - * A route generated by a call to `resource`. - * This is like a `resources` route, but creates routes for a singular resource. - * This means there's no index route, no id parameter, and the resource name is expected to be singular. - * It will still be routed to a pluralised controller name. - * ```ruby - * resource :account - * ``` - */ - private class SingularResourceRoute extends RouteImpl, TResourceRoute { - RouteBlock parent; - string action; - string httpMethod; - string pathComponent; - - SingularResourceRoute() { - exists(string resource | - this = TResourceRoute(parent, method, action) and - method.getArgument(0).getConstantValue().isStringlikeValue(resource) and - isDefaultSingularResourceRoute(resource, httpMethod, pathComponent, action) - ) - } - - override string getAPrimaryQlClass() { result = "SingularResourceRoute" } - - override RouteBlock getParentBlock() { result = parent } - - override string getLastPathComponent() { result = pathComponent } - - override string getLastControllerComponent() { - method.getArgument(0).getConstantValue().isStringlikeValue(result) - } - - override string getAction() { result = action } - - override string getHttpMethod() { result = httpMethod } - } - - /** - * A route generated by a call to `match`. - * This is a lower level primitive that powers `get`, `post` etc. - * The first argument can be a path or a (path, controller-action) pair. - * The controller, action and HTTP method can be specified with the - * `controller:`, `action:` and `via:` keyword arguments, respectively. - * ```ruby - * match 'photos/:id' => 'photos#show', via: :get - * match 'photos/:id', to: 'photos#show', via: :get - * match 'photos/:id', to 'photos#show', via: [:get, :post] - * match 'photos/:id', controller: 'photos', action: 'show', via: :get - * ``` - */ - private class MatchRoute extends RouteImpl, TMatchRoute { - private RouteBlock parent; - - MatchRoute() { this = TMatchRoute(parent, method) } - - override string getAPrimaryQlClass() { result = "MatchRoute" } - - override RouteBlock getParentBlock() { result = parent } - - override string getLastPathComponent() { - [method.getArgument(0), method.getArgument(0).(Pair).getKey()] - .getConstantValue() - .isStringlikeValue(result) - } - - override string getLastControllerComponent() { - result = - extractController(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or - method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result) or - result = - extractController(method - .getArgument(0) - .(Pair) - .getValue() - .getConstantValue() - .getStringlikeValue()) - } - - override string getHttpMethod() { - exists(string via | - method.getKeywordArgument("via").getConstantValue().isStringlikeValue(via) - | - via = "all" and result = anyHttpMethod() - or - via != "all" and result = via - ) - or - result = - method - .getKeywordArgument("via") - .(ArrayLiteral) - .getElement(_) - .getConstantValue() - .getStringlikeValue() - } - - override string getAction() { - result = - extractAction(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or - method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result) or - result = - extractAction(method - .getArgument(0) - .(Pair) - .getValue() - .getConstantValue() - .getStringlikeValue()) - } - } - - private import Cached - - /** - * This module contains the IPA types backing `RouteBlock` and `Route`, cached for performance. - */ - cached - private module Cached { - cached - newtype TRouteBlock = - TTopLevelRouteBlock(MethodCall routes, MethodCall draw, Block b) { - routes.getMethodName() = "routes" and - draw.getMethodName() = "draw" and - draw.getReceiver() = routes and - draw.getBlock() = b - } or - // constraints(foo: /some_regex/) do - // get "/posts/:foo", to "posts#something" - // end - TConstraintsRouteBlock(RouteBlock parent, MethodCall constraints, Block b) { - parent.getAStmt() = constraints and - constraints.getMethodName() = "constraints" and - constraints.getBlock() = b - } or - // scope(path: "/some_path", module: "some_module") do - // get "/posts/:foo", to "posts#something" - // end - TScopeRouteBlock(RouteBlock parent, MethodCall scope, Block b) { - parent.getAStmt() = scope and scope.getMethodName() = "scope" and scope.getBlock() = b - } or - // resources :articles do - // get "/comments", to "comments#index" - // end - TResourcesRouteBlock(RouteBlock parent, MethodCall resources, Block b) { - parent.getAStmt() = resources and - resources.getMethodName() = "resources" and - resources.getBlock() = b - } or - // A conditional statement guarding some routes. - // We ignore the condition and analyze both branches to obtain as - // much routing information as possible. - TConditionalRouteBlock(RouteBlock parent, ConditionalExpr e) { parent.getAStmt() = e } or - // namespace :admin do - // resources :posts - // end - TNamespaceRouteBlock(RouteBlock parent, MethodCall namespace, Block b) { - parent.getAStmt() = namespace and - namespace.getMethodName() = "namespace" and - namespace.getBlock() = b - } - - /** - * A route configuration. See `Route` for more info - */ - cached - newtype TRoute = - /** - * See `ExplicitRoute` - */ - TExplicitRoute(RouteBlock b, MethodCall m) { - b.getAStmt() = m and m.getMethodName() = anyHttpMethod() - } or - /** - * See `ResourcesRoute` - */ - TResourcesRoute(RouteBlock b, MethodCall m, string action) { - b.getAStmt() = m and - m.getMethodName() = "resources" and - action in ["show", "index", "new", "edit", "create", "update", "destroy"] and - applyActionFilters(m, action) - } or - /** - * See `SingularResourceRoute` - */ - TResourceRoute(RouteBlock b, MethodCall m, string action) { - b.getAStmt() = m and - m.getMethodName() = "resource" and - action in ["show", "new", "edit", "create", "update", "destroy"] and - applyActionFilters(m, action) - } or - /** - * See `MatchRoute` - */ - TMatchRoute(RouteBlock b, MethodCall m) { b.getAStmt() = m and m.getMethodName() = "match" } - } - - /** - * Several routing methods support the keyword arguments `only:` and `except:`. - * - `only:` restricts the set of actions to just those in the argument. - * - `except:` removes the given actions from the set. - */ - bindingset[action] - private predicate applyActionFilters(MethodCall m, string action) { - // Respect the `only` keyword argument, which restricts the set of actions. - ( - not exists(m.getKeywordArgument("only")) - or - exists(Expr only | only = m.getKeywordArgument("only") | - [only.(ArrayLiteral).getElement(_), only].getConstantValue().isStringlikeValue(action) - ) - ) and - // Respect the `except` keyword argument, which removes actions from the default set. - ( - not exists(m.getKeywordArgument("except")) - or - exists(Expr except | except = m.getKeywordArgument("except") | - [except.(ArrayLiteral).getElement(_), except].getConstantValue().getStringlikeValue() != - action - ) - ) - } - - /** - * Holds if the (resource, method, path, action) combination would be generated by a call to `resources :<resource>`. - */ - bindingset[resource] - private predicate isDefaultResourceRoute( - string resource, string method, string path, string action - ) { - action = "create" and - (method = "post" and path = "/" + resource) - or - action = "index" and - (method = "get" and path = "/" + resource) - or - action = "new" and - (method = "get" and path = "/" + resource + "/new") - or - action = "edit" and - (method = "get" and path = "/" + resource + ":id/edit") - or - action = "show" and - (method = "get" and path = "/" + resource + "/:id") - or - action = "update" and - (method in ["put", "patch"] and path = "/" + resource + "/:id") - or - action = "destroy" and - (method = "delete" and path = "/" + resource + "/:id") - } - - /** - * Holds if the (resource, method, path, action) combination would be generated by a call to `resource :<resource>`. - */ - bindingset[resource] - private predicate isDefaultSingularResourceRoute( - string resource, string method, string path, string action - ) { - action = "create" and - (method = "post" and path = "/" + resource) - or - action = "new" and - (method = "get" and path = "/" + resource + "/new") - or - action = "edit" and - (method = "get" and path = "/" + resource + "/edit") - or - action = "show" and - (method = "get" and path = "/" + resource) - or - action = "update" and - (method in ["put", "patch"] and path = "/" + resource) - or - action = "destroy" and - (method = "delete" and path = "/" + resource) - } - - /** - * Extract the controller from a Rails routing string - * ``` - * extractController("posts#show") = "posts" - * ``` - */ - bindingset[input] - private string extractController(string input) { result = input.regexpCapture("([^#]+)#.+", 1) } - - /** - * Extract the action from a Rails routing string - * ``` - * extractAction("posts#show") = "show" - */ - bindingset[input] - private string extractAction(string input) { result = input.regexpCapture("[^#]+#(.+)", 1) } - - /** - * Returns the lowercase name of every HTTP method we support. - */ - private string anyHttpMethod() { result = ["get", "post", "put", "patch", "delete"] } - - /** - * The inverse of `pluralize`. If `input` is a plural word, it returns the - * singular version. - * - * Examples: - * - * - photos -> photo - * - stories -> story - * - not_plural -> not_plural - */ - bindingset[input] - private string singularize(string input) { - exists(string prefix | prefix = input.regexpCapture("(.*)ies", 1) | result = prefix + "y") - or - not input.matches("%ies") and - exists(string prefix | prefix = input.regexpCapture("(.*)s", 1) | result = prefix) - or - not input.regexpMatch(".*(ies|s)") and result = input - } - - /** - * Convert a camel-case string to underscore case. Converts `::` to `/`. - * This can be used to convert ActiveRecord controller names to a canonical form that matches the routes they handle. - * Note: All-uppercase words like `CONSTANT` are not handled correctly. - */ - bindingset[base] - string underscore(string base) { - base = "" and result = "" - or - result = - base.charAt(0).toLowerCase() + - // Walk along the string, keeping track of the previous character - // in order to determine if we've crossed a boundary. - // Boundaries are: - // - lower case to upper case: B in FooBar - // - entering a namespace: B in Foo::Bar - concat(int i, string prev, string char | - prev = base.charAt(i) and - char = base.charAt(i + 1) - | - any(string s | - char.regexpMatch("[A-Za-z0-9]") and - if prev = ":" - then s = "/" + char.toLowerCase() - else - if prev.isLowercase() and char.isUppercase() - then s = "_" + char.toLowerCase() - else s = char.toLowerCase() - ) - order by - i - ) - } - - /** - * Strip leading and trailing forward slashes from the string. - */ - bindingset[input] - private string stripSlashes(string input) { - result = input.regexpReplaceAll("^/+(.+)$", "$1").regexpReplaceAll("^(.*[^/])/+$", "$1") - } - } + class MimeTypeMatchRegExpInterpretation = Mime::MimeTypeMatchRegExpInterpretation; } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll new file mode 100644 index 00000000000..a47b4700d93 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll @@ -0,0 +1,46 @@ +/** + * Models MIME type handling using the `ActionDispatch` library, which is part of Rails. + */ + +private import codeql.ruby.Regexp as RE +private import codeql.ruby.frameworks.data.ModelsAsData + +/** + * Models MIME type handling using the `ActionDispatch` library, which is part of Rails. + */ +module Mime { + /** + * Type summaries for the `Mime::Type` class, i.e. method calls that produce new + * `Mime::Type` instances. + */ + private class MimeTypeTypeSummary extends ModelInput::TypeModelCsv { + override predicate row(string row) { + // type1;type2;path + row = + [ + // Mime[type] : Mime::Type (omitted) + // Method names with brackets like [] cannot be represented in MaD. + // Mime.fetch(type) : Mime::Type + "Mime::Type;Mime!;Method[fetch].ReturnValue", + // Mime::Type.lookup(str) : Mime::Type + "Mime::Type;Mime::Type!;Method[lookup].ReturnValue", + // Mime::Type.lookup_by_extension(str) : Mime::Type + "Mime::Type;Mime::Type!;Method[lookup_by_extension].ReturnValue", + // Mime::Type.register(str) : Mime::Type + "Mime::Type;Mime::Type!;Method[register].ReturnValue", + // Mime::Type.register_alias(str) : Mime::Type + "Mime::Type;Mime::Type!;Method[register_alias].ReturnValue", + ] + } + } + + /** + * An argument to `Mime::Type#match?`, which is converted to a RegExp via + * `Regexp.new`. + */ + class MimeTypeMatchRegExpInterpretation extends RE::RegExpInterpretation::Range { + MimeTypeMatchRegExpInterpretation() { + this = ModelOutput::getATypeNode("Mime::Type").getAMethodCall(["match?", "=~"]).getArgument(0) + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll new file mode 100644 index 00000000000..3c34846bee8 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll @@ -0,0 +1,961 @@ +/** + * Models routing configuration specified using the `ActionDispatch` library, which is part of Rails. + */ + +private import codeql.ruby.AST + +/** + * Models routing configuration specified using the `ActionDispatch` library, which is part of Rails. + */ +module Routing { + /** + * A block that defines some routes. + * Route blocks can contribute to the path or controller namespace of their child routes. + * For example, in the block below + * ```rb + * scope path: "/admin" do + * get "/dashboard", to: "admin_dashboard#show" + * end + * ``` + * the route defined by the call to `get` has the full path `/admin/dashboard`. + * We track these contributions via `getPathComponent` and `getControllerComponent`. + */ + abstract private class RouteBlock extends TRouteBlock { + /** + * Gets the name of a primary CodeQL class to which this route block belongs. + */ + string getAPrimaryQlClass() { result = "RouteBlock" } + + /** + * Gets a string representation of this route block. + */ + string toString() { none() } + + /** + * Gets a `Stmt` within this route block. + */ + abstract Stmt getAStmt(); + + /** + * Gets the parent of this route block, if one exists. + */ + abstract RouteBlock getParent(); + + /** + * Gets the `n`th parent of this route block. + * The zeroth parent is this block, the first parent is the direct parent of this block, etc. + */ + RouteBlock getParent(int n) { + if n = 0 then result = this else result = this.getParent().getParent(n - 1) + } + + /** + * Gets the component of the path defined by this block, if it exists. + */ + abstract string getPathComponent(); + + /** + * Gets the component of the controller namespace defined by this block, if it exists. + */ + abstract string getControllerComponent(); + + /** + * Gets the location of this route block. + */ + abstract Location getLocation(); + } + + /** + * A route block that is not the top-level block. + * This block will always have a parent. + */ + abstract private class NestedRouteBlock extends RouteBlock { + RouteBlock parent; + + override RouteBlock getParent() { result = parent } + + override string getAPrimaryQlClass() { result = "NestedRouteBlock" } + } + + /** + * A top-level routes block. + * ```rb + * Rails.application.routes.draw do + * ... + * end + * ``` + */ + private class TopLevelRouteBlock extends RouteBlock, TTopLevelRouteBlock { + MethodCall call; + // Routing blocks create scopes which define the namespace for controllers and paths, + // though they can be overridden in various ways. + // The namespaces can differ, so we track them separately. + Block block; + + TopLevelRouteBlock() { this = TTopLevelRouteBlock(_, call, block) } + + override string getAPrimaryQlClass() { result = "TopLevelRouteBlock" } + + Block getBlock() { result = block } + + override Stmt getAStmt() { result = block.getAStmt() } + + override RouteBlock getParent() { none() } + + override string toString() { result = call.toString() } + + override Location getLocation() { result = call.getLocation() } + + override string getPathComponent() { none() } + + override string getControllerComponent() { none() } + } + + /** + * A route block defined by a call to `constraints`. + * ```rb + * constraints(foo: /some_regex/) do + * get "/posts/:foo", to "posts#something" + * end + * ``` + * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-constraints + */ + private class ConstraintsRouteBlock extends NestedRouteBlock, TConstraintsRouteBlock { + private Block block; + private MethodCall call; + + ConstraintsRouteBlock() { this = TConstraintsRouteBlock(parent, call, block) } + + override string getAPrimaryQlClass() { result = "ConstraintsRouteBlock" } + + override Stmt getAStmt() { result = block.getAStmt() } + + override string getPathComponent() { result = "" } + + override string getControllerComponent() { result = "" } + + override string toString() { result = call.toString() } + + override Location getLocation() { result = call.getLocation() } + } + + /** + * A route block defined by a call to `scope`. + * ```rb + * scope(path: "/some_path", module: "some_module") do + * get "/posts/:foo", to "posts#something" + * end + * ``` + * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope + */ + private class ScopeRouteBlock extends NestedRouteBlock, TScopeRouteBlock { + private MethodCall call; + private Block block; + + ScopeRouteBlock() { this = TScopeRouteBlock(parent, call, block) } + + override string getAPrimaryQlClass() { result = "ScopeRouteBlock" } + + override Stmt getAStmt() { result = block.getAStmt() } + + override string toString() { result = call.toString() } + + override Location getLocation() { result = call.getLocation() } + + override string getPathComponent() { + call.getKeywordArgument("path").getConstantValue().isStringlikeValue(result) + or + not exists(call.getKeywordArgument("path")) and + call.getArgument(0).getConstantValue().isStringlikeValue(result) + } + + override string getControllerComponent() { + call.getKeywordArgument(["controller", "module"]).getConstantValue().isStringlikeValue(result) + } + } + + /** + * A route block defined by a call to `resources`. + * ```rb + * resources :articles do + * get "/comments", to "comments#index" + * end + * ``` + * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources + */ + private class ResourcesRouteBlock extends NestedRouteBlock, TResourcesRouteBlock { + private MethodCall call; + private Block block; + + ResourcesRouteBlock() { this = TResourcesRouteBlock(parent, call, block) } + + override string getAPrimaryQlClass() { result = "ResourcesRouteBlock" } + + override Stmt getAStmt() { result = block.getAStmt() } + + /** + * Gets the `resources` call that gives rise to this route block. + */ + MethodCall getDefiningMethodCall() { result = call } + + override string getPathComponent() { + exists(string resource | call.getArgument(0).getConstantValue().isStringlikeValue(resource) | + result = resource + "/:" + singularize(resource) + "_id" + ) + } + + override string getControllerComponent() { result = "" } + + override string toString() { result = call.toString() } + + override Location getLocation() { result = call.getLocation() } + } + + /** + * A route block that is guarded by a conditional statement. + * For example: + * ```rb + * if Rails.env.test? + * get "/foo/bar", to: "foo#bar" + * end + * ``` + * We ignore the condition and analyze both branches to obtain as + * much routing information as possible. + */ + private class ConditionalRouteBlock extends NestedRouteBlock, TConditionalRouteBlock { + private ConditionalExpr e; + + ConditionalRouteBlock() { this = TConditionalRouteBlock(parent, e) } + + override string getAPrimaryQlClass() { result = "ConditionalRouteBlock" } + + override Stmt getAStmt() { result = e.getBranch(_).(StmtSequence).getAStmt() } + + override string getPathComponent() { none() } + + override string getControllerComponent() { none() } + + override string toString() { result = e.toString() } + + override Location getLocation() { result = e.getLocation() } + } + + /** + * A route block defined by a call to `namespace`. + * ```rb + * namespace :admin do + * resources :posts + * end + * ``` + * https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-namespace + */ + private class NamespaceRouteBlock extends NestedRouteBlock, TNamespaceRouteBlock { + private MethodCall call; + private Block block; + + NamespaceRouteBlock() { this = TNamespaceRouteBlock(parent, call, block) } + + override Stmt getAStmt() { result = block.getAStmt() } + + override string getPathComponent() { result = this.getNamespace() } + + override string getControllerComponent() { result = this.getNamespace() } + + private string getNamespace() { + call.getArgument(0).getConstantValue().isStringlikeValue(result) + } + + override string toString() { result = call.toString() } + + override Location getLocation() { result = call.getLocation() } + } + + /** + * A route configuration. This defines a combination of HTTP method and URL + * path which should be routed to a particular controller-action pair. + * This can arise from an explicit call to a routing method, for example: + * ```rb + * get "/photos", to: "photos#index" + * ``` + * or via a convenience method like `resources`, which defines multiple routes at once: + * ```rb + * resources :photos + * ``` + */ + class Route extends TRoute instanceof RouteImpl { + /** + * Gets the name of a primary CodeQL class to which this route belongs. + */ + string getAPrimaryQlClass() { result = "Route" } + + /** Gets a string representation of this route. */ + string toString() { result = super.toString() } + + /** + * Gets the location of the method call that defines this route. + */ + Location getLocation() { result = super.getLocation() } + + /** + * Gets the full controller targeted by this route. + */ + string getController() { result = super.getController() } + + /** + * Gets the action targeted by this route. + */ + string getAction() { result = super.getAction() } + + /** + * Gets the HTTP method of this route. + * The result is one of [get, post, put, patch, delete]. + */ + string getHttpMethod() { result = super.getHttpMethod() } + + /** + * Gets the full path of the route. + */ + string getPath() { result = super.getPath() } + + /** + * Get a URL capture. This is a wildcard URL segment whose value is placed in `params`. + * For example, in + * ```ruby + * get "/foo/:bar/baz", to: "users#index" + * ``` + * the capture is `:bar`. + */ + string getACapture() { result = super.getACapture() } + } + + /** + * The implementation of `Route`. + * This class is abstract and is thus kept private so we don't expose it to + * users. + * Extend this class to add new instances of routes. + */ + abstract private class RouteImpl extends TRoute { + /** + * Gets the name of a primary CodeQL class to which this route belongs. + */ + string getAPrimaryQlClass() { result = "RouteImpl" } + + MethodCall method; + + /** Gets a string representation of this route. */ + string toString() { result = method.toString() } + + /** + * Gets the location of the method call that defines this route. + */ + Location getLocation() { result = method.getLocation() } + + /** + * Gets the method call that defines this route. + */ + MethodCall getDefiningMethodCall() { result = method } + + /** + * Get the last component of the path. For example, in + * ```rb + * get "/photos", to: "photos#index" + * ``` + * this is `/photos`. + * If the string has any interpolations, this predicate will have no result. + */ + abstract string getLastPathComponent(); + + /** + * Gets the HTTP method of this route. + * The result is one of [get, post, put, patch, delete]. + */ + abstract string getHttpMethod(); + + /** + * Gets the last controller component. + * This is the controller specified in the route itself. + */ + abstract string getLastControllerComponent(); + + /** + * Gets a component of the controller. + * This behaves identically to `getPathComponent`, but for controller information. + */ + string getControllerComponent(int n) { + if n = 0 + then result = this.getLastControllerComponent() + else result = this.getParentBlock().getParent(n - 1).getControllerComponent() + } + + /** + * Gets the full controller targeted by this route. + */ + string getController() { + result = + concat(int n | + this.getControllerComponent(n) != "" + | + this.getControllerComponent(n), "/" order by n desc + ) + } + + /** + * Gets the action targeted by this route. + */ + abstract string getAction(); + + /** + * Gets the parent `RouteBlock` of this route. + */ + abstract RouteBlock getParentBlock(); + + /** + * Gets a component of the path. Components are numbered from 0 up, where 0 + * is the last component, 1 is the second-last, etc. + * For example, in the following route: + * + * ```rb + * namespace path: "foo" do + * namespace path: "bar" do + * get "baz", to: "foo#bar + * end + * end + * ``` + * + * the components are: + * + * | n | component + * |---|---------- + * | 0 | baz + * | 1 | bar + * | 2 | foo + */ + string getPathComponent(int n) { + if n = 0 + then result = this.getLastPathComponent() + else result = this.getParentBlock().getParent(n - 1).getPathComponent() + } + + /** + * Gets the full path of the route. + */ + string getPath() { + result = + concat(int n | + this.getPathComponent(n) != "" + | + // Strip leading and trailing slashes from each path component before combining + stripSlashes(this.getPathComponent(n)), "/" order by n desc + ) + } + + /** + * Get a URL capture. This is a wildcard URL segment whose value is placed in `params`. + * For example, in + * ```ruby + * get "/foo/:bar/baz", to: "users#index" + * ``` + * the capture is `:bar`. + * We don't currently make use of this, but it may be useful in future to more accurately + * model the contents of the `params` hash. + */ + string getACapture() { result = this.getPathComponent(_).regexpFind(":[^:/]+", _, _) } + } + + /** + * A route generated by an explicit call to `get`, `post`, etc. + * + * ```ruby + * get "/photos", to: "photos#index" + * put "/photos/:id", to: "photos#update" + * ``` + */ + private class ExplicitRoute extends RouteImpl, TExplicitRoute { + RouteBlock parentBlock; + + ExplicitRoute() { this = TExplicitRoute(parentBlock, method) } + + override string getAPrimaryQlClass() { result = "ExplicitRoute" } + + override RouteBlock getParentBlock() { result = parentBlock } + + override string getLastPathComponent() { + method.getArgument(0).getConstantValue().isStringlikeValue(result) + } + + override string getLastControllerComponent() { + method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result) + or + not exists(method.getKeywordArgument("controller")) and + ( + result = extractController(this.getActionString()) + or + // If controller is not specified, and we're in a `resources` route block, use the controller of that route. + // For example, in + // + // resources :posts do + // get "timestamp", to: :timestamp + // end + // + // The route is GET /posts/:post_id/timestamp => posts/timestamp + not exists(extractController(this.getActionString())) and + exists(ResourcesRoute r | + r.getDefiningMethodCall() = parentBlock.(ResourcesRouteBlock).getDefiningMethodCall() + | + result = r.getLastControllerComponent() + ) + ) + } + + private string getActionString() { + method.getKeywordArgument("to").getConstantValue().isStringlikeValue(result) + or + method.getKeywordArgument("to").(MethodCall).getMethodName() = "redirect" and + result = "<redirect>#<redirect>" + } + + override string getAction() { + // get "/photos", action: "index" + method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result) + or + not exists(method.getKeywordArgument("action")) and + ( + // get "/photos", to: "photos#index" + // get "/photos", to: redirect("some_url") + result = extractAction(this.getActionString()) + or + // resources :photos, only: [] do + // get "/", to: "index" + // end + not exists(extractAction(this.getActionString())) and result = this.getActionString() + or + // get :some_action + not exists(this.getActionString()) and + method.getArgument(0).getConstantValue().isStringlikeValue(result) + ) + } + + override string getHttpMethod() { result = method.getMethodName().toString() } + } + + /** + * A route generated by a call to `resources`. + * + * ```ruby + * resources :photos + * ``` + * This creates eight routes, equivalent to the following code: + * ```ruby + * get "/photos", to: "photos#index" + * get "/photos/new", to: "photos#new" + * post "/photos", to: "photos#create" + * get "/photos/:id", to: "photos#show" + * get "/photos/:id/edit", to: "photos#edit" + * patch "/photos/:id", to: "photos#update" + * put "/photos/:id", to: "photos#update" + * delete "/photos/:id", to: "photos#delete" + * ``` + * + * `resources` can take a block. Any routes defined inside the block will inherit a path component of + * `/<resource>/:<resource>_id`. For example: + * + * ```ruby + * resources :photos do + * get "/foo", to: "photos#foo" + * end + * ``` + * This creates the eight default routes, plus one more, which is nested under "/photos/:photo_id", equivalent to: + * ```ruby + * get "/photos/:photo_id/foo", to: "photos#foo" + * ``` + */ + private class ResourcesRoute extends RouteImpl, TResourcesRoute { + RouteBlock parent; + string action; + string httpMethod; + string pathComponent; + + ResourcesRoute() { + exists(string resource | + this = TResourcesRoute(parent, method, action) and + method.getArgument(0).getConstantValue().isStringlikeValue(resource) and + isDefaultResourceRoute(resource, httpMethod, pathComponent, action) + ) + } + + override string getAPrimaryQlClass() { result = "ResourcesRoute" } + + override RouteBlock getParentBlock() { result = parent } + + override string getLastPathComponent() { result = pathComponent } + + override string getLastControllerComponent() { + method.getArgument(0).getConstantValue().isStringlikeValue(result) + } + + override string getAction() { result = action } + + override string getHttpMethod() { result = httpMethod } + } + + /** + * A route generated by a call to `resource`. + * This is like a `resources` route, but creates routes for a singular resource. + * This means there's no index route, no id parameter, and the resource name is expected to be singular. + * It will still be routed to a pluralised controller name. + * ```ruby + * resource :account + * ``` + */ + private class SingularResourceRoute extends RouteImpl, TResourceRoute { + RouteBlock parent; + string action; + string httpMethod; + string pathComponent; + + SingularResourceRoute() { + exists(string resource | + this = TResourceRoute(parent, method, action) and + method.getArgument(0).getConstantValue().isStringlikeValue(resource) and + isDefaultSingularResourceRoute(resource, httpMethod, pathComponent, action) + ) + } + + override string getAPrimaryQlClass() { result = "SingularResourceRoute" } + + override RouteBlock getParentBlock() { result = parent } + + override string getLastPathComponent() { result = pathComponent } + + override string getLastControllerComponent() { + method.getArgument(0).getConstantValue().isStringlikeValue(result) + } + + override string getAction() { result = action } + + override string getHttpMethod() { result = httpMethod } + } + + /** + * A route generated by a call to `match`. + * This is a lower level primitive that powers `get`, `post` etc. + * The first argument can be a path or a (path, controller-action) pair. + * The controller, action and HTTP method can be specified with the + * `controller:`, `action:` and `via:` keyword arguments, respectively. + * ```ruby + * match 'photos/:id' => 'photos#show', via: :get + * match 'photos/:id', to: 'photos#show', via: :get + * match 'photos/:id', to 'photos#show', via: [:get, :post] + * match 'photos/:id', controller: 'photos', action: 'show', via: :get + * ``` + */ + private class MatchRoute extends RouteImpl, TMatchRoute { + private RouteBlock parent; + + MatchRoute() { this = TMatchRoute(parent, method) } + + override string getAPrimaryQlClass() { result = "MatchRoute" } + + override RouteBlock getParentBlock() { result = parent } + + override string getLastPathComponent() { + [method.getArgument(0), method.getArgument(0).(Pair).getKey()] + .getConstantValue() + .isStringlikeValue(result) + } + + override string getLastControllerComponent() { + result = + extractController(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or + method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result) or + result = + extractController(method + .getArgument(0) + .(Pair) + .getValue() + .getConstantValue() + .getStringlikeValue()) + } + + override string getHttpMethod() { + exists(string via | + method.getKeywordArgument("via").getConstantValue().isStringlikeValue(via) + | + via = "all" and result = anyHttpMethod() + or + via != "all" and result = via + ) + or + result = + method + .getKeywordArgument("via") + .(ArrayLiteral) + .getElement(_) + .getConstantValue() + .getStringlikeValue() + } + + override string getAction() { + result = + extractAction(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or + method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result) or + result = + extractAction(method + .getArgument(0) + .(Pair) + .getValue() + .getConstantValue() + .getStringlikeValue()) + } + } + + private import Cached + + /** + * This module contains the IPA types backing `RouteBlock` and `Route`, cached for performance. + */ + cached + private module Cached { + cached + newtype TRouteBlock = + TTopLevelRouteBlock(MethodCall routes, MethodCall draw, Block b) { + routes.getMethodName() = "routes" and + draw.getMethodName() = "draw" and + draw.getReceiver() = routes and + draw.getBlock() = b + } or + // constraints(foo: /some_regex/) do + // get "/posts/:foo", to "posts#something" + // end + TConstraintsRouteBlock(RouteBlock parent, MethodCall constraints, Block b) { + parent.getAStmt() = constraints and + constraints.getMethodName() = "constraints" and + constraints.getBlock() = b + } or + // scope(path: "/some_path", module: "some_module") do + // get "/posts/:foo", to "posts#something" + // end + TScopeRouteBlock(RouteBlock parent, MethodCall scope, Block b) { + parent.getAStmt() = scope and scope.getMethodName() = "scope" and scope.getBlock() = b + } or + // resources :articles do + // get "/comments", to "comments#index" + // end + TResourcesRouteBlock(RouteBlock parent, MethodCall resources, Block b) { + parent.getAStmt() = resources and + resources.getMethodName() = "resources" and + resources.getBlock() = b + } or + // A conditional statement guarding some routes. + // We ignore the condition and analyze both branches to obtain as + // much routing information as possible. + TConditionalRouteBlock(RouteBlock parent, ConditionalExpr e) { parent.getAStmt() = e } or + // namespace :admin do + // resources :posts + // end + TNamespaceRouteBlock(RouteBlock parent, MethodCall namespace, Block b) { + parent.getAStmt() = namespace and + namespace.getMethodName() = "namespace" and + namespace.getBlock() = b + } + + /** + * A route configuration. See `Route` for more info + */ + cached + newtype TRoute = + /** + * See `ExplicitRoute` + */ + TExplicitRoute(RouteBlock b, MethodCall m) { + b.getAStmt() = m and m.getMethodName() = anyHttpMethod() + } or + /** + * See `ResourcesRoute` + */ + TResourcesRoute(RouteBlock b, MethodCall m, string action) { + b.getAStmt() = m and + m.getMethodName() = "resources" and + action in ["show", "index", "new", "edit", "create", "update", "destroy"] and + applyActionFilters(m, action) + } or + /** + * See `SingularResourceRoute` + */ + TResourceRoute(RouteBlock b, MethodCall m, string action) { + b.getAStmt() = m and + m.getMethodName() = "resource" and + action in ["show", "new", "edit", "create", "update", "destroy"] and + applyActionFilters(m, action) + } or + /** + * See `MatchRoute` + */ + TMatchRoute(RouteBlock b, MethodCall m) { b.getAStmt() = m and m.getMethodName() = "match" } + } + + /** + * Several routing methods support the keyword arguments `only:` and `except:`. + * - `only:` restricts the set of actions to just those in the argument. + * - `except:` removes the given actions from the set. + */ + bindingset[action] + private predicate applyActionFilters(MethodCall m, string action) { + // Respect the `only` keyword argument, which restricts the set of actions. + ( + not exists(m.getKeywordArgument("only")) + or + exists(Expr only | only = m.getKeywordArgument("only") | + [only.(ArrayLiteral).getElement(_), only].getConstantValue().isStringlikeValue(action) + ) + ) and + // Respect the `except` keyword argument, which removes actions from the default set. + ( + not exists(m.getKeywordArgument("except")) + or + exists(Expr except | except = m.getKeywordArgument("except") | + [except.(ArrayLiteral).getElement(_), except].getConstantValue().getStringlikeValue() != + action + ) + ) + } + + /** + * Holds if the (resource, method, path, action) combination would be generated by a call to `resources :<resource>`. + */ + bindingset[resource] + private predicate isDefaultResourceRoute( + string resource, string method, string path, string action + ) { + action = "create" and + (method = "post" and path = "/" + resource) + or + action = "index" and + (method = "get" and path = "/" + resource) + or + action = "new" and + (method = "get" and path = "/" + resource + "/new") + or + action = "edit" and + (method = "get" and path = "/" + resource + ":id/edit") + or + action = "show" and + (method = "get" and path = "/" + resource + "/:id") + or + action = "update" and + (method in ["put", "patch"] and path = "/" + resource + "/:id") + or + action = "destroy" and + (method = "delete" and path = "/" + resource + "/:id") + } + + /** + * Holds if the (resource, method, path, action) combination would be generated by a call to `resource :<resource>`. + */ + bindingset[resource] + private predicate isDefaultSingularResourceRoute( + string resource, string method, string path, string action + ) { + action = "create" and + (method = "post" and path = "/" + resource) + or + action = "new" and + (method = "get" and path = "/" + resource + "/new") + or + action = "edit" and + (method = "get" and path = "/" + resource + "/edit") + or + action = "show" and + (method = "get" and path = "/" + resource) + or + action = "update" and + (method in ["put", "patch"] and path = "/" + resource) + or + action = "destroy" and + (method = "delete" and path = "/" + resource) + } + + /** + * Extract the controller from a Rails routing string + * ``` + * extractController("posts#show") = "posts" + * ``` + */ + bindingset[input] + private string extractController(string input) { result = input.regexpCapture("([^#]+)#.+", 1) } + + /** + * Extract the action from a Rails routing string + * ``` + * extractAction("posts#show") = "show" + */ + bindingset[input] + private string extractAction(string input) { result = input.regexpCapture("[^#]+#(.+)", 1) } + + /** + * Returns the lowercase name of every HTTP method we support. + */ + private string anyHttpMethod() { result = ["get", "post", "put", "patch", "delete"] } + + /** + * The inverse of `pluralize`. If `input` is a plural word, it returns the + * singular version. + * + * Examples: + * + * - photos -> photo + * - stories -> story + * - not_plural -> not_plural + */ + bindingset[input] + private string singularize(string input) { + exists(string prefix | prefix = input.regexpCapture("(.*)ies", 1) | result = prefix + "y") + or + not input.matches("%ies") and + exists(string prefix | prefix = input.regexpCapture("(.*)s", 1) | result = prefix) + or + not input.regexpMatch(".*(ies|s)") and result = input + } + + /** + * Convert a camel-case string to underscore case. Converts `::` to `/`. + * This can be used to convert ActiveRecord controller names to a canonical form that matches the routes they handle. + * Note: All-uppercase words like `CONSTANT` are not handled correctly. + */ + bindingset[base] + string underscore(string base) { + base = "" and result = "" + or + result = + base.charAt(0).toLowerCase() + + // Walk along the string, keeping track of the previous character + // in order to determine if we've crossed a boundary. + // Boundaries are: + // - lower case to upper case: B in FooBar + // - entering a namespace: B in Foo::Bar + concat(int i, string prev, string char | + prev = base.charAt(i) and + char = base.charAt(i + 1) + | + any(string s | + char.regexpMatch("[A-Za-z0-9]") and + if prev = ":" + then s = "/" + char.toLowerCase() + else + if prev.isLowercase() and char.isUppercase() + then s = "_" + char.toLowerCase() + else s = char.toLowerCase() + ) + order by + i + ) + } + + /** + * Strip leading and trailing forward slashes from the string. + */ + bindingset[input] + private string stripSlashes(string input) { + result = input.regexpReplaceAll("^/+(.+)$", "$1").regexpReplaceAll("^(.*[^/])/+$", "$1") + } +} From 27729af088e0ee5c4abd2f933cb44b6a89703c45 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 13:48:58 +0100 Subject: [PATCH 035/219] Ruby: move ActionDispatch::Request logic out of ActionController.qll --- .../ruby/frameworks/ActionController.qll | 146 +---------------- .../codeql/ruby/frameworks/ActionDispatch.qll | 1 + .../frameworks/actiondispatch/Request.qll | 147 ++++++++++++++++++ 3 files changed, 150 insertions(+), 144 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll index 480a1f78035..9e4ce72a249 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll @@ -83,7 +83,8 @@ class ActionControllerClass extends DataFlow::ClassNode { } } -private DataFlow::LocalSourceNode actionControllerInstance() { +// TODO: private +DataFlow::LocalSourceNode actionControllerInstance() { result = any(ActionControllerClass cls).getSelf() } @@ -204,149 +205,6 @@ private class ActionControllerParamsCall extends ParamsCallImpl { } } -/** Modeling for `ActionDispatch::Request`. */ -private module Request { - /** - * A call to `request` from within a controller. This is an instance of - * `ActionDispatch::Request`. - */ - private class RequestNode extends DataFlow::CallNode { - RequestNode() { this = actionControllerInstance().getAMethodCall("request") } - } - - /** - * A method call on `request`. - */ - private class RequestMethodCall extends DataFlow::CallNode { - RequestMethodCall() { - any(RequestNode r).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) - } - } - - abstract private class RequestInputAccess extends RequestMethodCall, - Http::Server::RequestInputAccess::Range - { - override string getSourceType() { result = "ActionDispatch::Request#" + this.getMethodName() } - } - - /** - * A method call on `request` which returns request parameters. - */ - private class ParametersCall extends RequestInputAccess { - ParametersCall() { - this.getMethodName() = - [ - "parameters", "params", "GET", "POST", "query_parameters", "request_parameters", - "filtered_parameters" - ] - } - - override Http::Server::RequestInputKind getKind() { - result = Http::Server::parameterInputKind() - } - } - - /** A method call on `request` which returns part or all of the request path. */ - private class PathCall extends RequestInputAccess { - PathCall() { - this.getMethodName() = - ["path", "filtered_path", "fullpath", "original_fullpath", "original_url", "url"] - } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::urlInputKind() } - } - - /** A method call on `request` which returns a specific request header. */ - private class HeadersCall extends RequestInputAccess { - HeadersCall() { - this.getMethodName() = - [ - "authorization", "script_name", "path_info", "user_agent", "referer", "referrer", - "host_authority", "content_type", "host", "hostname", "accept_encoding", - "accept_language", "if_none_match", "if_none_match_etags", "content_mime_type" - ] - or - // Request headers are prefixed with `HTTP_` to distinguish them from - // "headers" supplied by Rack middleware. - this.getMethodName() = ["get_header", "fetch_header"] and - this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+") - } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } - } - - // TODO: each_header - /** - * A method call on `request` which returns part or all of the host. - * This can be influenced by headers such as Host and X-Forwarded-Host. - */ - private class HostCall extends RequestInputAccess { - HostCall() { - this.getMethodName() = - [ - "authority", "host", "host_authority", "host_with_port", "hostname", "forwarded_for", - "forwarded_host", "port", "forwarded_port" - ] - } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } - } - - /** - * A method call on `request` which is influenced by one or more request - * headers. - */ - private class HeaderTaintedCall extends RequestInputAccess { - HeaderTaintedCall() { - this.getMethodName() = ["media_type", "media_type_params", "content_charset", "base_url"] - } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } - } - - /** A method call on `request` which returns the request body. */ - private class BodyCall extends RequestInputAccess { - BodyCall() { this.getMethodName() = ["body", "raw_post", "body_stream"] } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() } - } - - private module Env { - abstract private class Env extends DataFlow::LocalSourceNode { } - - /** - * A method call on `request` which returns the rack env. - * This is a hash containing all the information about the request. Values - * under keys starting with `HTTP_` are user-controlled. - */ - private class RequestEnvCall extends DataFlow::CallNode, Env { - RequestEnvCall() { this.getMethodName() = ["env", "filtered_env"] } - } - - private import codeql.ruby.frameworks.Rack - - private class RackEnv extends Env { - RackEnv() { this = any(Rack::AppCandidate app).getEnv().getALocalUse() } - } - - /** - * A read of a user-controlled parameter from the request env. - */ - private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range { - EnvHttpAccess() { - this = any(Env c).getAMethodCall("[]") and - exists(string key | key = this.getArgument(0).getConstantValue().getString() | - key.regexpMatch("^HTTP_.+") or key = "PATH_INFO" - ) - } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } - - override string getSourceType() { result = "ActionDispatch::Request#env[]" } - } - } -} - /** A call to `render` from within a controller. */ private class ActionControllerRenderCall extends RenderCallImpl { ActionControllerRenderCall() { diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll index c8720d5f1dc..1493307982f 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll @@ -9,6 +9,7 @@ */ module ActionDispatch { private import actiondispatch.Mime + private import actiondispatch.Request import actiondispatch.Routing class MimeTypeMatchRegExpInterpretation = Mime::MimeTypeMatchRegExpInterpretation; diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll new file mode 100644 index 00000000000..864767afd28 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll @@ -0,0 +1,147 @@ +/** Modeling for `ActionDispatch::Request`. */ + +private import codeql.ruby.Concepts +private import codeql.ruby.DataFlow +private import codeql.ruby.frameworks.ActionController + +/** Modeling for `ActionDispatch::Request`. */ +module Request { + /** + * An instance of `ActionDispatch::Request`. + */ + private class RequestNode extends DataFlow::CallNode { + RequestNode() { this = actionControllerInstance().getAMethodCall("request") } + } + + /** + * A method call on `request`. + */ + private class RequestMethodCall extends DataFlow::CallNode { + RequestMethodCall() { + any(RequestNode r).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) + } + } + + abstract private class RequestInputAccess extends RequestMethodCall, + Http::Server::RequestInputAccess::Range + { + override string getSourceType() { result = "ActionDispatch::Request#" + this.getMethodName() } + } + + /** + * A method call on `request` which returns request parameters. + */ + private class ParametersCall extends RequestInputAccess { + ParametersCall() { + this.getMethodName() = + [ + "parameters", "params", "GET", "POST", "query_parameters", "request_parameters", + "filtered_parameters" + ] + } + + override Http::Server::RequestInputKind getKind() { + result = Http::Server::parameterInputKind() + } + } + + /** A method call on `request` which returns part or all of the request path. */ + private class PathCall extends RequestInputAccess { + PathCall() { + this.getMethodName() = + ["path", "filtered_path", "fullpath", "original_fullpath", "original_url", "url"] + } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::urlInputKind() } + } + + /** A method call on `request` which returns a specific request header. */ + private class HeadersCall extends RequestInputAccess { + HeadersCall() { + this.getMethodName() = + [ + "authorization", "script_name", "path_info", "user_agent", "referer", "referrer", + "host_authority", "content_type", "host", "hostname", "accept_encoding", + "accept_language", "if_none_match", "if_none_match_etags", "content_mime_type" + ] + or + // Request headers are prefixed with `HTTP_` to distinguish them from + // "headers" supplied by Rack middleware. + this.getMethodName() = ["get_header", "fetch_header"] and + this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+") + } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } + } + + // TODO: each_header + /** + * A method call on `request` which returns part or all of the host. + * This can be influenced by headers such as Host and X-Forwarded-Host. + */ + private class HostCall extends RequestInputAccess { + HostCall() { + this.getMethodName() = + [ + "authority", "host", "host_authority", "host_with_port", "hostname", "forwarded_for", + "forwarded_host", "port", "forwarded_port" + ] + } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } + } + + /** + * A method call on `request` which is influenced by one or more request + * headers. + */ + private class HeaderTaintedCall extends RequestInputAccess { + HeaderTaintedCall() { + this.getMethodName() = ["media_type", "media_type_params", "content_charset", "base_url"] + } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } + } + + /** A method call on `request` which returns the request body. */ + private class BodyCall extends RequestInputAccess { + BodyCall() { this.getMethodName() = ["body", "raw_post", "body_stream"] } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() } + } + + private module Env { + abstract private class Env extends DataFlow::LocalSourceNode { } + + /** + * A method call on `request` which returns the rack env. + * This is a hash containing all the information about the request. Values + * under keys starting with `HTTP_` are user-controlled. + */ + private class RequestEnvCall extends DataFlow::CallNode, Env { + RequestEnvCall() { this.getMethodName() = ["env", "filtered_env"] } + } + + private import codeql.ruby.frameworks.Rack + + private class RackEnv extends Env { + RackEnv() { this = any(Rack::AppCandidate app).getEnv().getALocalUse() } + } + + /** + * A read of a user-controlled parameter from the request env. + */ + private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range { + EnvHttpAccess() { + this = any(Env c).getAMethodCall("[]") and + exists(string key | key = this.getArgument(0).getConstantValue().getString() | + key.regexpMatch("^HTTP_.+") or key = "PATH_INFO" + ) + } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } + + override string getSourceType() { result = "ActionDispatch::Request#env[]" } + } + } +} From c2f5bacc4782e133d28f185fe0672df937ca80bf Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 14:10:07 +0100 Subject: [PATCH 036/219] Ruby: consider more calls to e.g. ActionDispatch::Request#params as remote input sources --- .../ruby/frameworks/ActionController.qll | 3 +-- .../frameworks/actiondispatch/Request.qll | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll index 9e4ce72a249..31bdc42e350 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll @@ -83,8 +83,7 @@ class ActionControllerClass extends DataFlow::ClassNode { } } -// TODO: private -DataFlow::LocalSourceNode actionControllerInstance() { +private DataFlow::LocalSourceNode actionControllerInstance() { result = any(ActionControllerClass cls).getSelf() } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll index 864767afd28..d749b87f273 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll @@ -2,23 +2,26 @@ private import codeql.ruby.Concepts private import codeql.ruby.DataFlow +private import codeql.ruby.ApiGraphs private import codeql.ruby.frameworks.ActionController /** Modeling for `ActionDispatch::Request`. */ module Request { /** - * An instance of `ActionDispatch::Request`. - */ - private class RequestNode extends DataFlow::CallNode { - RequestNode() { this = actionControllerInstance().getAMethodCall("request") } - } - - /** - * A method call on `request`. + * A method call against an `ActionDispatch::Request` instance. */ private class RequestMethodCall extends DataFlow::CallNode { RequestMethodCall() { - any(RequestNode r).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) + any(ActionControllerClass cls) + .getSelf() + .getAMethodCall("request") + .(DataFlow::LocalSourceNode) + .flowsTo(this.getReceiver()) or + this = + API::getTopLevelMember("ActionDispatch") + .getMember("Request") + .getInstance() + .getAMethodCall(_) } } From 1c9e4c0f0bd9161a1e4b18139b461623bdd3d1f1 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 15:17:38 +0100 Subject: [PATCH 037/219] Ruby: test for RequestInputAccess instances in ActionDispatch --- .../action_dispatch/ActionDispatch.expected | 13 +++++++++++++ .../frameworks/action_dispatch/ActionDispatch.ql | 3 +++ 2 files changed, 16 insertions(+) diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected index 4524e715d4f..74e9b30b19a 100644 --- a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected @@ -66,3 +66,16 @@ mimeTypeMatchRegExpInterpretations | mime_type.rb:12:7:12:15 | "foo/bar" | | mime_type.rb:13:11:13:11 | s | | mime_type.rb:14:7:14:7 | s | +requestInputAccesses +| app/controllers/comments_controller.rb:3:5:3:18 | call to params | +| app/controllers/comments_controller.rb:4:5:4:22 | call to parameters | +| app/controllers/comments_controller.rb:5:5:5:15 | call to GET | +| app/controllers/comments_controller.rb:6:5:6:16 | call to POST | +| app/controllers/comments_controller.rb:7:5:7:28 | call to query_parameters | +| app/controllers/comments_controller.rb:8:5:8:30 | call to request_parameters | +| app/controllers/comments_controller.rb:9:5:9:31 | call to filtered_parameters | +| app/controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies | +| app/controllers/foo/bars_controller.rb:13:21:13:26 | call to params | +| app/controllers/foo/bars_controller.rb:14:10:14:15 | call to params | +| app/controllers/foo/bars_controller.rb:21:21:21:26 | call to params | +| app/controllers/foo/bars_controller.rb:22:10:22:15 | call to params | diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql index 5b1275595ea..f7931ea7569 100644 --- a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql @@ -2,6 +2,7 @@ private import codeql.ruby.AST private import codeql.ruby.frameworks.ActionDispatch private import codeql.ruby.frameworks.ActionController private import codeql.ruby.ApiGraphs +private import codeql.ruby.Concepts private import codeql.ruby.frameworks.data.ModelsAsData private import codeql.ruby.DataFlow private import codeql.ruby.Regexp as RE @@ -36,3 +37,5 @@ query predicate mimeTypeMatchRegExpInterpretations( ) { any() } + +query predicate requestInputAccesses(Http::Server::RequestInputAccess a) { any() } From 9f5c73cf6353b9212e763ebb4ad92d80d196e9e0 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 15:18:32 +0100 Subject: [PATCH 038/219] Ruby: add a test case for instantiating ActionDispatch::Request directly --- .../frameworks/action_dispatch/ActionDispatch.expected | 5 +++-- .../action_dispatch/app/controllers/comments_controller.rb | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected index 74e9b30b19a..71327350941 100644 --- a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected @@ -36,8 +36,8 @@ actionDispatchRoutes actionDispatchControllerMethods | app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index | | app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show | -| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index | -| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show | +| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:39:5 | index | +| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:41:3:42:5 | show | | app/config/routes.rb:7:5:7:37 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote | | app/config/routes.rb:27:3:27:48 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | | app/config/routes.rb:28:3:28:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | @@ -74,6 +74,7 @@ requestInputAccesses | app/controllers/comments_controller.rb:7:5:7:28 | call to query_parameters | | app/controllers/comments_controller.rb:8:5:8:30 | call to request_parameters | | app/controllers/comments_controller.rb:9:5:9:31 | call to filtered_parameters | +| app/controllers/comments_controller.rb:38:5:38:14 | call to params | | app/controllers/foo/bars_controller.rb:10:27:10:33 | call to cookies | | app/controllers/foo/bars_controller.rb:13:21:13:26 | call to params | | app/controllers/foo/bars_controller.rb:14:10:14:15 | call to params | diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb index 57fac7797bd..77918c53943 100644 --- a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb @@ -33,6 +33,9 @@ class CommentsController < ApplicationController response.last_modified = Date.yesterday response.weak_etag = "value" response.strong_etag = "value" + + req = ActionDispatch::Request.new(request.env) + req.params end def show From 9ccfec0571ed0b43aa999a3dd6e7054932f04a52 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Tue, 23 May 2023 15:26:52 +0100 Subject: [PATCH 039/219] Ruby: move actiondispatch components to an internal subdirectory --- ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll | 6 +++--- .../ruby/frameworks/actiondispatch/{ => internal}/Mime.qll | 0 .../frameworks/actiondispatch/{ => internal}/Request.qll | 0 .../frameworks/actiondispatch/{ => internal}/Routing.qll | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/{ => internal}/Mime.qll (100%) rename ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/{ => internal}/Request.qll (100%) rename ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/{ => internal}/Routing.qll (100%) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll index 1493307982f..fbd36e637cf 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll @@ -8,9 +8,9 @@ * Version: 7.1.0. */ module ActionDispatch { - private import actiondispatch.Mime - private import actiondispatch.Request - import actiondispatch.Routing + private import actiondispatch.internal.Mime + private import actiondispatch.internal.Request + import actiondispatch.internal.Routing class MimeTypeMatchRegExpInterpretation = Mime::MimeTypeMatchRegExpInterpretation; } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Mime.qll similarity index 100% rename from ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Mime.qll rename to ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Mime.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Request.qll similarity index 100% rename from ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Request.qll rename to ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Request.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll b/ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Routing.qll similarity index 100% rename from ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/Routing.qll rename to ruby/ql/lib/codeql/ruby/frameworks/actiondispatch/internal/Routing.qll From deee3143700d507ef7c7f8f0c21b9cf1008844e2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Thu, 4 May 2023 13:21:46 +0200 Subject: [PATCH 040/219] Python/Ruby: Optimize join-order in `TypeTracker::[small]step` --- .../dataflow/new/internal/TypeTracker.qll | 170 ++++++++++++++++-- .../codeql/ruby/typetracking/TypeTracker.qll | 170 ++++++++++++++++-- 2 files changed, 320 insertions(+), 20 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll index d4d9e1f31f5..4be26f6cea9 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll @@ -224,6 +224,74 @@ private module Cached { private import Cached +pragma[nomagic] +private predicate stepNoCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { + stepNoCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker stepNoCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + stepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + stepNoCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { + stepCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker stepCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + stepCallProj(nodeFrom, summary) and + result = t.append(summary) and + stepCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate smallstepNoCallProj(Node nodeFrom, StepSummary summary) { + smallstepNoCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker smallstepNoCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + smallstepNoCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate smallstepCallProj(Node nodeFrom, StepSummary summary) { + smallstepCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker smallstepCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepCallProj(nodeFrom, summary) and + result = t.append(summary) and + smallstepCall(nodeFrom, nodeTo, summary) + ) +} + /** * Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`. * @@ -296,6 +364,24 @@ class StepSummary extends TStepSummary { /** Provides predicates for updating step summaries (`StepSummary`s). */ module StepSummary { + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate stepCall = Cached::stepCall/3; + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate stepNoCall = Cached::stepNoCall/3; + /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. @@ -313,6 +399,24 @@ module StepSummary { stepCall(nodeFrom, nodeTo, summary) } + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate smallstepNoCall = Cached::smallstepNoCall/3; + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate smallstepCall = Cached::smallstepCall/3; + /** * Gets the summary that corresponds to having taken a forwards * local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. @@ -425,16 +529,66 @@ class TypeTracker extends TTypeTracker { */ TypeTracker continue() { content = noContent() and result = this } + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker stepNoCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { + result = stepNoCallInlineLate(this, nodeFrom, nodeTo) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker stepCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { + result = stepCallInlineLate(this, nodeFrom, nodeTo) + } + /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ pragma[inline] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and - result = this.append(pragma[only_bind_into](summary)) - ) + result = this.stepNoCall(nodeFrom, nodeTo) + or + result = this.stepCall(nodeFrom, nodeTo) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker smallstepNoCall(Node nodeFrom, Node nodeTo) { + result = smallstepNoCallInlineLate(this, nodeFrom, nodeTo) + or + simpleLocalFlowStep(nodeFrom, nodeTo) and + result = this + } + + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker smallstepCall(Node nodeFrom, Node nodeTo) { + result = smallstepCallInlineLate(this, nodeFrom, nodeTo) } /** @@ -463,13 +617,9 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - StepSummary::smallstep(nodeFrom, nodeTo, summary) and - result = this.append(summary) - ) + result = this.smallstepNoCall(nodeFrom, nodeTo) or - simpleLocalFlowStep(nodeFrom, nodeTo) and - result = this + result = this.smallstepCall(nodeFrom, nodeTo) } } diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll index d4d9e1f31f5..4be26f6cea9 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll @@ -224,6 +224,74 @@ private module Cached { private import Cached +pragma[nomagic] +private predicate stepNoCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { + stepNoCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker stepNoCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + stepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + stepNoCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { + stepCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker stepCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + stepCallProj(nodeFrom, summary) and + result = t.append(summary) and + stepCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate smallstepNoCallProj(Node nodeFrom, StepSummary summary) { + smallstepNoCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker smallstepNoCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + smallstepNoCall(nodeFrom, nodeTo, summary) + ) +} + +pragma[nomagic] +private predicate smallstepCallProj(Node nodeFrom, StepSummary summary) { + smallstepCall(nodeFrom, _, summary) +} + +bindingset[nodeFrom, t] +pragma[inline_late] +pragma[noopt] +private TypeTracker smallstepCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepCallProj(nodeFrom, summary) and + result = t.append(summary) and + smallstepCall(nodeFrom, nodeTo, summary) + ) +} + /** * Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`. * @@ -296,6 +364,24 @@ class StepSummary extends TStepSummary { /** Provides predicates for updating step summaries (`StepSummary`s). */ module StepSummary { + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate stepCall = Cached::stepCall/3; + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate stepNoCall = Cached::stepNoCall/3; + /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. @@ -313,6 +399,24 @@ module StepSummary { stepCall(nodeFrom, nodeTo, summary) } + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate smallstepNoCall = Cached::smallstepNoCall/3; + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + predicate smallstepCall = Cached::smallstepCall/3; + /** * Gets the summary that corresponds to having taken a forwards * local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. @@ -425,16 +529,66 @@ class TypeTracker extends TTypeTracker { */ TypeTracker continue() { content = noContent() and result = this } + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker stepNoCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { + result = stepNoCallInlineLate(this, nodeFrom, nodeTo) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker stepCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { + result = stepCallInlineLate(this, nodeFrom, nodeTo) + } + /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ pragma[inline] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and - result = this.append(pragma[only_bind_into](summary)) - ) + result = this.stepNoCall(nodeFrom, nodeTo) + or + result = this.stepCall(nodeFrom, nodeTo) + } + + /** + * Gets the summary that corresponds to having taken a forwards + * intra-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker smallstepNoCall(Node nodeFrom, Node nodeTo) { + result = smallstepNoCallInlineLate(this, nodeFrom, nodeTo) + or + simpleLocalFlowStep(nodeFrom, nodeTo) and + result = this + } + + /** + * Gets the summary that corresponds to having taken a forwards + * inter-procedural step from `nodeFrom` to `nodeTo`. + * + * This predicate should normally not be used; consider using `step` + * instead. + */ + pragma[inline] + TypeTracker smallstepCall(Node nodeFrom, Node nodeTo) { + result = smallstepCallInlineLate(this, nodeFrom, nodeTo) } /** @@ -463,13 +617,9 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - StepSummary::smallstep(nodeFrom, nodeTo, summary) and - result = this.append(summary) - ) + result = this.smallstepNoCall(nodeFrom, nodeTo) or - simpleLocalFlowStep(nodeFrom, nodeTo) and - result = this + result = this.smallstepCall(nodeFrom, nodeTo) } } From 13ada1e6ad4643bf146b456c26fbd844d752dbdb Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Thu, 4 May 2023 13:21:41 +0200 Subject: [PATCH 041/219] Ruby: Remove canonical return nodes --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 4 +- .../dataflow/internal/DataFlowDispatch.qll | 227 ++++++++++++------ .../dataflow/internal/DataFlowPrivate.qll | 137 ++++------- .../ruby/dataflow/internal/DataFlowPublic.qll | 31 ++- .../codeql/ruby/frameworks/ActiveRecord.qll | 7 +- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 2 +- .../frameworks/actioncontroller/Filters.qll | 4 +- .../ruby/typetracking/TypeTrackerSpecific.qll | 41 +--- .../library-tests/dataflow/local/Nodes.ql | 2 +- .../type-tracker/TypeTracker.expected | 203 ---------------- 10 files changed, 235 insertions(+), 423 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index b1320d047cc..1cf4c445781 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -778,7 +778,7 @@ module API { or exists(TypeTracker t2 | result = trackUseNode(src, t2).track(t2, t) and - not result instanceof DataFlowPrivate::SelfParameterNode + not result instanceof DataFlow::SelfParameterNode ) } @@ -800,7 +800,7 @@ module API { or exists(TypeBackTracker t2, DataFlow::LocalSourceNode mid | mid = trackDefNode(rhs, t2) and - not mid instanceof DataFlowPrivate::SelfParameterNode and + not mid instanceof DataFlow::SelfParameterNode and result = mid.backtrack(t2, t) ) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll index 2b4c030707b..410867c7ead 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll @@ -10,16 +10,17 @@ private import codeql.ruby.dataflow.FlowSummary private import codeql.ruby.dataflow.SSA /** - * A `LocalSourceNode` for a `self` variable. This is either an implicit `self` - * parameter or an implicit SSA entry definition. + * A `LocalSourceNode` for a `self` variable. This is the implicit `self` + * parameter, when it exists, otherwise the implicit SSA entry definition. */ private class SelfLocalSourceNode extends DataFlow::LocalSourceNode { private SelfVariable self; SelfLocalSourceNode() { - self = this.(SelfParameterNode).getSelfVariable() + self = this.(SelfParameterNodeImpl).getSelfVariable() or - self = this.(SsaSelfDefinitionNode).getVariable() + self = this.(SsaSelfDefinitionNode).getVariable() and + not LocalFlow::localFlowSsaParamInput(_, this) } /** Gets the `self` variable. */ @@ -469,23 +470,43 @@ private module Cached { import Cached +pragma[nomagic] +private predicate stepCallProj(DataFlow::LocalSourceNode nodeFrom, StepSummary summary) { + StepSummary::stepCall(nodeFrom, _, summary) +} + +pragma[nomagic] +private predicate isNotSelf(DataFlow::Node n) { not n instanceof SelfParameterNodeImpl } + pragma[nomagic] private DataFlow::LocalSourceNode trackModuleAccess(Module m, TypeTracker t) { t.start() and m = resolveConstantReadAccess(result.asExpr().getExpr()) or - exists(TypeTracker t2, StepSummary summary | - result = trackModuleAccessRec(m, t2, summary) and t = t2.append(summary) + // We exclude steps into `self` parameters, and instead rely on the type of the + // enclosing module + isNotSelf(result) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(trackModuleAccess(m, t2), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(trackModuleAccessCall(m, t, summary), result, summary) + ) ) } -/** - * We exclude steps into `self` parameters, and instead rely on the type of the - * enclosing module. - */ +bindingset[t, summary] +pragma[inline_late] +private TypeTracker append(TypeTracker t, StepSummary summary) { result = t.append(summary) } + pragma[nomagic] -private DataFlow::LocalSourceNode trackModuleAccessRec(Module m, TypeTracker t, StepSummary summary) { - StepSummary::step(trackModuleAccess(m, t), result, summary) and - not result instanceof SelfParameterNode +private DataFlow::LocalSourceNode trackModuleAccessCall(Module m, TypeTracker t, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = trackModuleAccess(m, t2) and + stepCallProj(result, summary) and + t = append(t2, summary) + ) } pragma[nomagic] @@ -498,7 +519,7 @@ private predicate hasUserDefinedNew(Module m) { exists(DataFlow::MethodNode method | // not `getAnAncestor` because singleton methods cannot be included singletonMethodOnModule(method.asCallableAstNode(), "new", m.getSuperClass*()) and - not method.getSelfParameter().getAMethodCall("allocate").flowsTo(method.getAReturningNode()) + not method.getSelfParameter().getAMethodCall("allocate").flowsTo(method.getAReturnNode()) ) } @@ -610,6 +631,49 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) { exact = false } +private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { + localFlowStepTypeTracker(nodeFrom, nodeTo) and + summary.toString() = "level" +} + +pragma[nomagic] +private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) { + hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _) +} + +pragma[nomagic] +private predicate smallStepNoCallForTrackInstance0( + DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary +) { + // We exclude steps into `self` parameters. For those, we instead rely on the type of + // the enclosing module + StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and + isNotSelf(nodeTo) + or + // We exclude steps into type checked variables. For those, we instead rely on the + // type being checked against + localFlowStep(nodeFrom, nodeTo, summary) and + not hasAdjacentTypeCheckedReads(nodeTo) +} + +pragma[nomagic] +private predicate smallStepNoCallForTrackInstance0Proj(DataFlow::Node nodeFrom, StepSummary summary) { + smallStepNoCallForTrackInstance0(nodeFrom, _, summary) +} + +bindingset[t, nodeFrom] +pragma[inline_late] +pragma[noopt] +private TypeTracker smallStepNoCallForTrackInstance( + TypeTracker t, DataFlow::Node nodeFrom, DataFlow::Node nodeTo +) { + exists(StepSummary summary | + smallStepNoCallForTrackInstance0Proj(nodeFrom, summary) and + result = t.append(summary) and + smallStepNoCallForTrackInstance0(nodeFrom, nodeTo, summary) + ) +} + pragma[nomagic] private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) { t.start() and @@ -631,35 +695,33 @@ private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) { ) ) or - exists(TypeTracker t2, StepSummary summary | - result = trackInstanceRec(tp, t2, exact, summary) and t = t2.append(summary) + exists(TypeTracker t2 | + t = smallStepNoCallForTrackInstance(t2, trackInstance(tp, exact, t2), result) + ) + or + // We exclude steps into `self` parameters. For those, we instead rely on the type of + // the enclosing module + exists(StepSummary summary | + // non-linear recursion + StepSummary::smallstepCall(trackInstanceCall(tp, t, exact, summary), result, summary) and + isNotSelf(result) ) } -private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { - localFlowStepTypeTracker(nodeFrom, nodeTo) and - summary.toString() = "level" +pragma[nomagic] +private predicate smallStepCallProj(DataFlow::Node nodeFrom, StepSummary summary) { + StepSummary::smallstepCall(nodeFrom, _, summary) } pragma[nomagic] -private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) { - hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _) -} - -/** - * We exclude steps into `self` parameters and type checked variables. For those, - * we instead rely on the type of the enclosing module resp. the type being checked - * against, and apply an open-world assumption when determining possible dispatch - * targets. - */ -pragma[nomagic] -private DataFlow::Node trackInstanceRec(Module tp, TypeTracker t, boolean exact, StepSummary summary) { - exists(DataFlow::Node mid | mid = trackInstance(tp, exact, t) | - StepSummary::smallstep(mid, result, summary) and - not result instanceof SelfParameterNode - or - localFlowStep(mid, result, summary) and - not hasAdjacentTypeCheckedReads(result) +private DataFlow::Node trackInstanceCall( + Module tp, TypeTracker t, boolean exact, StepSummary summary +) { + exists(TypeTracker t2 | + // non-linear recursion + result = trackInstance(tp, exact, t2) and + smallStepCallProj(result, summary) and + t = append(t2, summary) ) } @@ -710,20 +772,27 @@ pragma[nomagic] private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) { t.start() and result.asExpr().getExpr() = block or - exists(TypeTracker t2, StepSummary summary | - result = trackBlockRec(block, t2, summary) and - t = t2.append(summary) + // We exclude steps into `self` parameters, which may happen when the code + // base contains implementations of `call`. + isNotSelf(result) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(trackBlock(block, t2), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(trackBlockCall(block, t, summary), result, summary) + ) ) } -/** - * We exclude steps into `self` parameters, which may happen when the code - * base contains implementations of `call`. - */ pragma[nomagic] -private DataFlow::LocalSourceNode trackBlockRec(Block block, TypeTracker t, StepSummary summary) { - StepSummary::step(trackBlock(block, t), result, summary) and - not result instanceof SelfParameterNode +private DataFlow::LocalSourceNode trackBlockCall(Block block, TypeTracker t, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = trackBlock(block, t2) and + stepCallProj(result, summary) and + t = append(t2, summary) + ) } pragma[nomagic] @@ -942,7 +1011,7 @@ private predicate paramReturnFlow( | nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess() or - nodeFromPreExpr = p.(SelfParameterNode).getSelfVariable().getAnAccess() + nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfVariable().getAnAccess() ) } @@ -951,31 +1020,53 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string t.start() and singletonMethodOnInstance(method, name, result.asExpr().getExpr()) or - exists(TypeTracker t2, StepSummary summary | - result = trackSingletonMethodOnInstanceRec(method, name, t2, summary) and - t = t2.append(summary) and - // Stop flow at redefinitions. - // - // Example: - // ```rb - // def x.foo; end - // def x.foo; end - // x.foo # <- we want to resolve this call to the second definition only - // ``` - not singletonMethodOnInstance(_, name, result.asExpr().getExpr()) - ) + ( + exists(TypeTracker t2 | + t = t2.smallstepNoCall(trackSingletonMethodOnInstance(method, name, t2), result) + ) + or + exists(StepSummary summary | + // non-linear recursion + smallStepCallForTrackSingletonMethodOnInstance(trackSingletonMethodOnInstanceCall(method, + name, t, summary), result, summary) + ) + ) and + // Stop flow at redefinitions. + // + // Example: + // ```rb + // def x.foo; end + // def x.foo; end + // x.foo # <- we want to resolve this call to the second definition only + // ``` + not singletonMethodOnInstance(_, name, result.asExpr().getExpr()) } pragma[nomagic] -private DataFlow::Node trackSingletonMethodOnInstanceRec( +private predicate smallStepCallForTrackSingletonMethodOnInstance( + DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary +) { + StepSummary::smallstepCall(nodeFrom, nodeTo, summary) + or + paramReturnFlow(nodeFrom, nodeTo, summary) +} + +pragma[nomagic] +private predicate smallStepCallForTrackSingletonMethodOnInstanceProj( + DataFlow::Node nodeFrom, StepSummary summary +) { + smallStepCallForTrackSingletonMethodOnInstance(nodeFrom, _, summary) +} + +pragma[nomagic] +private DataFlow::Node trackSingletonMethodOnInstanceCall( MethodBase method, string name, TypeTracker t, StepSummary summary ) { - exists(DataFlow::Node mid | mid = trackSingletonMethodOnInstance(method, name, t) | - StepSummary::smallstep(mid, result, summary) - or - paramReturnFlow(mid, result, summary) - or - localFlowStep(mid, result, summary) + exists(TypeTracker t2 | + // non-linear recursion + result = trackSingletonMethodOnInstance(method, name, t2) and + smallStepCallForTrackSingletonMethodOnInstanceProj(result, summary) and + t = append(t2, summary) ) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index d6908827ba9..6a7d87e9bd5 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -131,10 +131,10 @@ module LocalFlow { /** * Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node. */ - predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) { + predicate localFlowSsaParamInput(Node nodeFrom, SsaDefinitionExtNode nodeTo) { nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter()) or - nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod()) + nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNodeImpl).getMethod()) } /** @@ -143,14 +143,13 @@ module LocalFlow { * * This is intended to recover from flow not currently recognised by ordinary capture flow. */ - predicate localFlowSsaParamCaptureInput(Node nodeFrom, Node nodeTo) { - exists(Ssa::CapturedEntryDefinition def, ParameterNodeImpl p | - (nodeFrom = p or LocalFlow::localFlowSsaParamInput(p, nodeFrom)) and + predicate localFlowSsaParamCaptureInput(ParameterNodeImpl nodeFrom, Node nodeTo) { + exists(Ssa::CapturedEntryDefinition def | nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def | - p.getParameter().(NamedParameter).getVariable() = def.getSourceVariable() + nodeFrom.getParameter().(NamedParameter).getVariable() = def.getSourceVariable() or - p.(SelfParameterNode).getSelfVariable() = def.getSourceVariable() + nodeFrom.(SelfParameterNode).getSelfVariable() = def.getSourceVariable() ) } @@ -164,7 +163,7 @@ module LocalFlow { /** * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving - * SSA definition `def`. + * some SSA definition. */ private predicate localSsaFlowStep(Node nodeFrom, Node nodeTo) { exists(SsaImpl::DefinitionExt def | @@ -182,6 +181,8 @@ module LocalFlow { // Flow into phi (read) SSA definition node from def localFlowSsaInputFromDef(nodeFrom, def, nodeTo) ) + or + localFlowSsaParamInput(nodeFrom, nodeTo) // TODO // or // // Flow into uncertain SSA definition @@ -223,6 +224,13 @@ module LocalFlow { op.getExpr() instanceof BinaryLogicalOperation and nodeFrom.asExpr() = op.getAnOperand() ) + or + nodeTo.(ParameterNodeImpl).getParameter() = + any(NamedParameter p | + p.(OptionalParameter).getDefaultValue() = nodeFrom.asExpr().getExpr() + or + p.(KeywordParameter).getDefaultValue() = nodeFrom.asExpr().getExpr() + ) } } @@ -279,12 +287,6 @@ private module Cached { newtype TNode = TExprNode(CfgNodes::ExprCfgNode n) { TaintTrackingPrivate::forceCachingInSameStage() } or TReturningNode(CfgNodes::ReturningCfgNode n) or - TSynthReturnNode(CfgScope scope, ReturnKind kind) { - exists(ReturningNode ret | - ret.(NodeImpl).getCfgScope() = scope and - ret.getKind() = kind - ) - } or TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or TNormalParameterNode(Parameter p) { p instanceof SimpleParameter or @@ -326,12 +328,6 @@ private module Cached { TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or TSynthHashSplatParameterNode or TSummaryParameterNode; - private predicate defaultValueFlow(NamedParameter p, ExprNode e) { - p.(OptionalParameter).getDefaultValue() = e.getExprNode().getExpr() - or - p.(KeywordParameter).getDefaultValue() = e.getExprNode().getExpr() - } - cached Location getLocation(NodeImpl n) { result = n.getLocationImpl() } @@ -346,12 +342,6 @@ private module Cached { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or - defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom) - or - LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo) - or - nodeTo.(SynthReturnNode).getAnInput() = nodeFrom - or LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _) or @@ -373,10 +363,6 @@ private module Cached { predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or - defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom) - or - LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo) - or LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) or // Simple flow through library code is included in the exposed local @@ -386,19 +372,11 @@ private module Cached { /** * This is the local flow predicate that is used in type tracking. - * - * This needs to exclude `localFlowSsaParamInput` due to a performance trick - * in type tracking, where such steps are treated as call steps. */ cached predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or - exists(NamedParameter p | - defaultValueFlow(p, nodeFrom) and - nodeTo = LocalFlow::getParameterDefNode(p) - ) - or LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) or // Flow into phi node from read @@ -440,12 +418,10 @@ private module Cached { n instanceof ExprNode and not reachedFromExprOrEntrySsaDef(n) or - // Ensure all entry SSA definitions are local sources -- for parameters, this - // is needed by type tracking - entrySsaDefinition(n) - or - // Needed for flow out in type tracking - n instanceof SynthReturnNode + // Ensure all entry SSA definitions are local sources, except those that correspond + // to parameters (which are themselves local sources) + entrySsaDefinition(n) and + not LocalFlow::localFlowSsaParamInput(_, n) or // Needed for stores in type tracking TypeTrackerSpecific::storeStepIntoSourceNode(_, n, _) @@ -507,7 +483,7 @@ private module Cached { */ cached predicate exprNodeReturnedFromCached(ExprNode e, Callable c) { - exists(ReturningNode r | + exists(ReturnNode r | nodeGetEnclosingCallable(r).asCallable() = c and ( r.(ExplicitReturnNode).getReturningNode().getReturnedValueNode() = e.asExpr() or @@ -542,8 +518,6 @@ predicate nodeIsHidden(Node n) { or n instanceof SummaryParameterNode or - n instanceof SynthReturnNode - or n instanceof SynthHashSplatParameterNode or n instanceof SynthHashSplatArgumentNode @@ -658,10 +632,10 @@ private module ParameterNodes { * The value of the `self` parameter at function entry, viewed as a node in a data * flow graph. */ - class SelfParameterNode extends ParameterNodeImpl, TSelfParameterNode { + class SelfParameterNodeImpl extends ParameterNodeImpl, TSelfParameterNode { private MethodBase method; - SelfParameterNode() { this = TSelfParameterNode(method) } + SelfParameterNodeImpl() { this = TSelfParameterNode(method) } final MethodBase getMethod() { result = method } @@ -937,24 +911,26 @@ private class NewCall extends DataFlowCall { NewCall() { this.asCall().getExpr().(MethodCall).getMethodName() = "new" } } -/** A data-flow node that represents a value syntactically returned by a callable. */ -abstract class ReturningNode extends Node { - /** Gets the kind of this return node. */ - abstract ReturnKind getKind(); - - pragma[nomagic] - predicate hasKind(ReturnKind kind, CfgScope scope) { - kind = this.getKind() and - scope = this.(NodeImpl).getCfgScope() - } -} - /** A data-flow node that represents a value returned by a callable. */ abstract class ReturnNode extends Node { /** Gets the kind of this return node. */ abstract ReturnKind getKind(); } +/** A data-flow node that represents a value returned by a callable. */ +abstract class SourceReturnNode extends ReturnNode { + /** Gets the kind of this return node. */ + abstract ReturnKind getKindSource(); // only exists to avoid spurious negative recursion + + final override ReturnKind getKind() { result = this.getKindSource() } + + pragma[nomagic] + predicate hasKind(ReturnKind kind, CfgScope scope) { + kind = this.getKindSource() and + scope = this.(NodeImpl).getCfgScope() + } +} + private module ReturnNodes { private predicate isValid(CfgNodes::ReturningCfgNode node) { exists(ReturningStmt stmt, Callable scope | @@ -976,14 +952,14 @@ private module ReturnNodes { * A data-flow node that represents an expression explicitly returned by * a callable. */ - class ExplicitReturnNode extends ReturningNode, ReturningStatementNode { + class ExplicitReturnNode extends SourceReturnNode, ReturningStatementNode { ExplicitReturnNode() { isValid(n) and n.getASuccessor().(CfgNodes::AnnotatedExitNode).isNormal() and n.getScope() instanceof Callable } - override ReturnKind getKind() { + override ReturnKind getKindSource() { if n.getNode() instanceof BreakStmt then result instanceof BreakReturnKind else @@ -1012,10 +988,10 @@ private module ReturnNodes { * a callable. An implicit return happens when an expression can be the * last thing that is evaluated in the body of the callable. */ - class ExprReturnNode extends ReturningNode, ExprNode { + class ExprReturnNode extends SourceReturnNode, ExprNode { ExprReturnNode() { exists(Callable c | implicitReturn(c, this) = c.getAStmt()) } - override ReturnKind getKind() { + override ReturnKind getKindSource() { exists(CfgScope scope | scope = this.(NodeImpl).getCfgScope() | if isUserDefinedNew(scope) then result instanceof NewReturnKind @@ -1040,7 +1016,7 @@ private module ReturnNodes { * the implicit `self` reference in `@x` will return data stored in the field * `x` out to the call `C.new`. */ - class InitializeReturnNode extends ExprPostUpdateNode, ReturningNode { + class InitializeReturnNode extends ExprPostUpdateNode, ReturnNode { InitializeReturnNode() { exists(Method initialize | this.getCfgScope() = initialize and @@ -1053,32 +1029,6 @@ private module ReturnNodes { override ReturnKind getKind() { result instanceof NewReturnKind } } - /** - * A synthetic data-flow node for joining flow from different syntactic - * returns into a single node. - * - * This node only exists to avoid computing the product of a large fan-in - * with a large fan-out. - */ - class SynthReturnNode extends NodeImpl, ReturnNode, TSynthReturnNode { - private CfgScope scope; - private ReturnKind kind; - - SynthReturnNode() { this = TSynthReturnNode(scope, kind) } - - /** Gets a syntactic return node that flows into this synthetic node. */ - pragma[nomagic] - ReturningNode getAnInput() { result.hasKind(kind, scope) } - - override ReturnKind getKind() { result = kind } - - override CfgScope getCfgScope() { result = scope } - - override Location getLocationImpl() { result = scope.getLocation() } - - override string toStringImpl() { result = "return " + kind + " in " + scope } - } - private class SummaryReturnNode extends SummaryNode, ReturnNode { private ReturnKind rk; @@ -1339,9 +1289,6 @@ private import PostUpdateNodes /** A node that performs a type cast. */ class CastNode extends Node { CastNode() { - // ensure that actual return nodes are included in the path graph - this instanceof ReturningNode - or // ensure that all variable assignments are included in the path graph this.(SsaDefinitionExtNode).getDefinitionExt() instanceof Ssa::WriteDefinition } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index 9d668e0b300..501cf70593e 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -195,10 +195,22 @@ class ParameterNode extends LocalSourceNode, TParameterNode instanceof Parameter /** Gets the parameter corresponding to this node, if any. */ final Parameter getParameter() { result = super.getParameter() } + /** Gets the callable that this parameter belongs to. */ + final Callable getCallable() { result = super.getCfgScope() } + /** Gets the name of the parameter, if any. */ final string getName() { result = this.getParameter().(NamedParameter).getName() } } +/** + * The value of an implicit `self` parameter at function entry, viewed as a node in a data + * flow graph. + */ +class SelfParameterNode extends ParameterNode instanceof SelfParameterNodeImpl { + /** Gets the underlying `self` variable. */ + final SelfVariable getSelfVariable() { result = super.getSelfVariable() } +} + /** * A data-flow node that is a source of local flow. */ @@ -328,9 +340,6 @@ private module Cached { exists(Node mid | hasLocalSource(mid, source) | localFlowStepTypeTracker(mid, sink) or - // Explicitly include the SSA param input step as type-tracking omits this step. - LocalFlow::localFlowSsaParamInput(mid, sink) - or LocalFlow::localFlowSsaParamCaptureInput(mid, sink) ) } @@ -1176,19 +1185,15 @@ class CallableNode extends StmtSequenceNode { result = this.getBlockParameter().getAMethodCall("call") } - /** - * Gets the canonical return node from this callable. - * - * Each callable has exactly one such node, and its location may not correspond - * to any particular return site - consider using `getAReturningNode` to get nodes - * whose locations correspond to return sites. - */ - Node getReturn() { result.(SynthReturnNode).getCfgScope() = callable } - /** * Gets a data flow node whose value is about to be returned by this callable. */ - Node getAReturningNode() { result = this.getReturn().(SynthReturnNode).getAnInput() } + Node getAReturnNode() { result.(ReturnNode).(NodeImpl).getCfgScope() = callable } + + /** + * DEPRECATED. Use `getAReturnNode` instead. + */ + deprecated Node getAReturningNode() { result = this.getAReturnNode() } } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll index 5869486ac91..fcca078f933 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll @@ -7,7 +7,6 @@ private import codeql.ruby.Concepts private import codeql.ruby.controlflow.CfgNodes private import codeql.ruby.DataFlow private import codeql.ruby.dataflow.internal.DataFlowDispatch -private import codeql.ruby.dataflow.internal.DataFlowPrivate private import codeql.ruby.ApiGraphs private import codeql.ruby.frameworks.Stdlib private import codeql.ruby.frameworks.Core @@ -319,19 +318,19 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation // A `self` reference that may resolve to an active record model object private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation, - SsaSelfDefinitionNode + DataFlow::SelfParameterNode { private ActiveRecordModelClass cls; ActiveRecordModelClassSelfReference() { exists(MethodBase m | - m = this.getCfgScope() and + m = this.getCallable() and m.getEnclosingModule() = cls and m = cls.getAMethod() ) and // In a singleton method, `self` refers to the class itself rather than an // instance of that class - not this.getSelfScope() instanceof SingletonMethod + not this.getSelfVariable().getDeclaringScope() instanceof SingletonMethod } final override ActiveRecordModelClass getClass() { result = cls } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 693cd4c197c..49281c609bd 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -21,7 +21,7 @@ module Rack { AppCandidate() { call = this.getInstanceMethod("call") and call.getNumberOfParameters() = 1 and - call.getReturn() = trackRackResponse() + call.getAReturnNode() = trackRackResponse() } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/actioncontroller/Filters.qll b/ruby/ql/lib/codeql/ruby/frameworks/actioncontroller/Filters.qll index 97ea8de1cd6..bc1766580e9 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/actioncontroller/Filters.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/actioncontroller/Filters.qll @@ -412,9 +412,7 @@ module Filters { /** * Holds if `n` is the self parameter of method `m`. */ - private predicate selfParameter(DataFlowPrivate::SelfParameterNode n, Method m) { - m = n.getMethod() - } + private predicate selfParameter(DataFlow::SelfParameterNode n, Method m) { m = n.getCallable() } /** * A class defining additional jump steps arising from filters. diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index 7283ffedf09..889d0abbed8 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -79,7 +79,7 @@ predicate jumpStep = DataFlowPrivate::jumpStep/2; /** Holds if there is direct flow from `param` to a return. */ pragma[nomagic] private predicate flowThrough(DataFlowPublic::ParameterNode param) { - exists(DataFlowPrivate::ReturningNode returnNode, DataFlowDispatch::ReturnKind rk | + exists(DataFlowPrivate::SourceReturnNode returnNode, DataFlowDispatch::ReturnKind rk | param.flowsTo(returnNode) and returnNode.hasKind(rk, param.(DataFlowPrivate::NodeImpl).getCfgScope()) | @@ -210,15 +210,7 @@ predicate callStep(ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::Param * recursion (or, at best, terrible performance), since identifying calls to library * methods is done using API graphs (which uses type tracking). */ -predicate callStep(Node nodeFrom, Node nodeTo) { - callStep(_, nodeFrom, nodeTo) - or - // In normal data-flow, this will be a local flow step. But for type tracking - // we model it as a call step, in order to avoid computing a potential - // self-cross product of all calls to a function that returns one of its parameters - // (only to later filter that flow out using `TypeTracker::append`). - DataFlowPrivate::LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo) -} +predicate callStep(Node nodeFrom, Node nodeTo) { callStep(_, nodeFrom, nodeTo) } /** * Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. @@ -230,19 +222,13 @@ predicate callStep(Node nodeFrom, Node nodeTo) { predicate returnStep(Node nodeFrom, Node nodeTo) { exists(ExprNodes::CallCfgNode call | nodeFrom instanceof DataFlowPrivate::ReturnNode and + not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode and nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and // deliberately do not include `getInitializeTarget`, since calls to `new` should not // get the return value from `initialize`. Any fields being set in the initializer // will reach all reads via `callStep` and `localFieldStep`. nodeTo.asExpr().getNode() = call.getNode() ) - or - // In normal data-flow, this will be a local flow step. But for type tracking - // we model it as a returning flow step, in order to avoid computing a potential - // self-cross product of all calls to a function that returns one of its parameters - // (only to later filter that flow out using `TypeTracker::append`). - nodeTo.(DataFlowPrivate::SynthReturnNode).getAnInput() = nodeFrom and - not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode } /** @@ -598,26 +584,15 @@ private DataFlow::Node evaluateSummaryComponentStackLocal( pragma[only_bind_out](tail)) and stack = SCS::push(pragma[only_bind_out](head), pragma[only_bind_out](tail)) | - exists( - DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos, - DataFlowPrivate::ParameterNodeImpl p - | + exists(DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos | head = SummaryComponent::parameter(apos) and DataFlowDispatch::parameterMatch(ppos, apos) and - p.isSourceParameterOf(prev.asExpr().getExpr(), ppos) and - // We need to include both `p` and the SSA definition for `p`, since in type-tracking - // the step from `p` to the SSA definition is considered a call step. - result = - [p.(DataFlow::Node), DataFlowPrivate::LocalFlow::getParameterDefNode(p.getParameter())] + result.(DataFlowPrivate::ParameterNodeImpl).isSourceParameterOf(prev.asExpr().getExpr(), ppos) ) or - exists(DataFlowPrivate::SynthReturnNode ret | - head = SummaryComponent::return() and - ret.getCfgScope() = prev.asExpr().getExpr() and - // We need to include both `ret` and `ret.getAnInput()`, since in type-tracking - // the step from `ret.getAnInput()` to `ret` is considered a return step. - result = [ret.(DataFlow::Node), ret.getAnInput()] - ) + head = SummaryComponent::return() and + result.(DataFlowPrivate::ReturnNode).(DataFlowPrivate::NodeImpl).getCfgScope() = + prev.asExpr().getExpr() or exists(DataFlow::ContentSet content | head = SummaryComponent::withoutContent(content) and diff --git a/ruby/ql/test/library-tests/dataflow/local/Nodes.ql b/ruby/ql/test/library-tests/dataflow/local/Nodes.ql index 2f89f667625..88ee1c5b208 100644 --- a/ruby/ql/test/library-tests/dataflow/local/Nodes.ql +++ b/ruby/ql/test/library-tests/dataflow/local/Nodes.ql @@ -2,7 +2,7 @@ import codeql.ruby.AST import codeql.ruby.dataflow.internal.DataFlowPrivate import codeql.ruby.dataflow.internal.DataFlowDispatch -query predicate ret(ReturningNode node) { any() } +query predicate ret(SourceReturnNode node) { any() } query predicate arg(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { n.argumentOf(call, pos) and diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index bc7b35eb941..9a4277f4c0e 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -1,129 +1,72 @@ track | type_tracker.rb:1:1:10:3 | self (Container) | type tracker without call steps | type_tracker.rb:1:1:10:3 | self (Container) | -| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) | | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self in positional | -| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker without call steps | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | | type_tracker.rb:2:5:5:7 | &block | type tracker without call steps | type_tracker.rb:2:5:5:7 | &block | | type_tracker.rb:2:5:5:7 | field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | field= | -| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | -| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | -| type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) | -| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | -| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= | -| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | -| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:8:9:8:14 | @field | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts | | type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field | | type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block | | type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field | -| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | -| type_tracker.rb:7:5:9:7 | self (field) | type tracker without call steps | type_tracker.rb:7:5:9:7 | self (field) | -| type_tracker.rb:7:5:9:7 | self in field | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:7:5:9:7 | self in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:12:1:16:3 | &block | type tracker without call steps | type_tracker.rb:12:1:16:3 | &block | | type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m | -| type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m | -| type_tracker.rb:12:1:16:3 | self (m) | type tracker without call steps | type_tracker.rb:12:1:16:3 | self (m) | -| type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) | | type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m | | type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var | | type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container | -| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= | -| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new | -| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var | | type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | -| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:8:9:8:14 | @field | -| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content attribute field | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content attribute field | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps with content attribute field | type_tracker.rb:14:5:14:7 | [post] var | | type_tracker.rb:14:17:14:23 | __synth__0 | type tracker without call steps | type_tracker.rb:14:17:14:23 | __synth__0 | -| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m | | type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:15:5:15:18 | call to puts | | type_tracker.rb:15:10:15:18 | call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:18:1:21:3 | &block | type tracker without call steps | type_tracker.rb:18:1:21:3 | &block | | type_tracker.rb:18:1:21:3 | positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | positional | -| type_tracker.rb:18:1:21:3 | return return in positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | return return in positional | -| type_tracker.rb:18:1:21:3 | return return in positional | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional | -| type_tracker.rb:18:1:21:3 | self (positional) | type tracker without call steps | type_tracker.rb:18:1:21:3 | self (positional) | -| type_tracker.rb:18:1:21:3 | self in positional | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) | | type_tracker.rb:18:1:21:3 | self in positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | self in positional | -| type_tracker.rb:18:16:18:17 | p1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 | | type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 | | type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 | -| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 | -| type_tracker.rb:18:20:18:21 | p2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 | -| type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:19:5:19:11 | call to puts | type tracker without call steps | type_tracker.rb:19:5:19:11 | call to puts | -| type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:18:1:21:3 | return return in positional | | type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:20:5:20:11 | call to puts | | type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional | | type_tracker.rb:23:1:23:16 | call to positional | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional | | type_tracker.rb:23:12:23:12 | 1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 | -| type_tracker.rb:23:12:23:12 | 1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 | | type_tracker.rb:23:12:23:12 | 1 | type tracker without call steps | type_tracker.rb:23:12:23:12 | 1 | | type_tracker.rb:23:15:23:15 | 2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 | -| type_tracker.rb:23:15:23:15 | 2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:23:15:23:15 | 2 | type tracker without call steps | type_tracker.rb:23:15:23:15 | 2 | | type_tracker.rb:25:1:28:3 | &block | type tracker without call steps | type_tracker.rb:25:1:28:3 | &block | | type_tracker.rb:25:1:28:3 | **kwargs | type tracker without call steps | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:25:1:28:3 | keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | return return in keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:30:1:30:21 | call to keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:31:1:31:21 | call to keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:32:1:32:27 | call to keyword | -| type_tracker.rb:25:1:28:3 | self (keyword) | type tracker without call steps | type_tracker.rb:25:1:28:3 | self (keyword) | -| type_tracker.rb:25:1:28:3 | self in keyword | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:25:1:28:3 | self in keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | self in keyword | -| type_tracker.rb:25:13:25:14 | p1 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:25:18:25:19 | p2 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:26:5:26:11 | call to puts | type tracker without call steps | type_tracker.rb:26:5:26:11 | call to puts | -| type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:25:1:28:3 | return return in keyword | | type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:27:5:27:11 | call to puts | | type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:30:1:30:21 | call to keyword | | type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:31:1:31:21 | call to keyword | @@ -134,14 +77,12 @@ track | type_tracker.rb:30:9:30:10 | :p1 | type tracker without call steps | type_tracker.rb:30:9:30:10 | :p1 | | type_tracker.rb:30:9:30:13 | Pair | type tracker without call steps | type_tracker.rb:30:9:30:13 | Pair | | type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:30:13:30:13 | 3 | type tracker without call steps | type_tracker.rb:30:13:30:13 | 3 | | type_tracker.rb:30:13:30:13 | 3 | type tracker without call steps with content element :p1 | type_tracker.rb:30:1:30:21 | ** | | type_tracker.rb:30:16:30:17 | :p2 | type tracker without call steps | type_tracker.rb:30:16:30:17 | :p2 | | type_tracker.rb:30:16:30:20 | Pair | type tracker without call steps | type_tracker.rb:30:16:30:20 | Pair | | type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:30:20:30:20 | 4 | type tracker without call steps | type_tracker.rb:30:20:30:20 | 4 | | type_tracker.rb:30:20:30:20 | 4 | type tracker without call steps with content element :p2 | type_tracker.rb:30:1:30:21 | ** | @@ -151,14 +92,12 @@ track | type_tracker.rb:31:9:31:10 | :p2 | type tracker without call steps | type_tracker.rb:31:9:31:10 | :p2 | | type_tracker.rb:31:9:31:13 | Pair | type tracker without call steps | type_tracker.rb:31:9:31:13 | Pair | | type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:31:13:31:13 | 5 | type tracker without call steps | type_tracker.rb:31:13:31:13 | 5 | | type_tracker.rb:31:13:31:13 | 5 | type tracker without call steps with content element :p2 | type_tracker.rb:31:1:31:21 | ** | | type_tracker.rb:31:16:31:17 | :p1 | type tracker without call steps | type_tracker.rb:31:16:31:17 | :p1 | | type_tracker.rb:31:16:31:20 | Pair | type tracker without call steps | type_tracker.rb:31:16:31:20 | Pair | | type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:31:20:31:20 | 6 | type tracker without call steps | type_tracker.rb:31:20:31:20 | 6 | | type_tracker.rb:31:20:31:20 | 6 | type tracker without call steps with content element :p1 | type_tracker.rb:31:1:31:21 | ** | @@ -168,68 +107,33 @@ track | type_tracker.rb:32:9:32:11 | :p2 | type tracker without call steps | type_tracker.rb:32:9:32:11 | :p2 | | type_tracker.rb:32:9:32:16 | Pair | type tracker without call steps | type_tracker.rb:32:9:32:16 | Pair | | type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:32:16:32:16 | 7 | type tracker without call steps | type_tracker.rb:32:16:32:16 | 7 | | type_tracker.rb:32:16:32:16 | 7 | type tracker without call steps with content element :p2 | type_tracker.rb:32:1:32:27 | ** | | type_tracker.rb:32:19:32:21 | :p1 | type tracker without call steps | type_tracker.rb:32:19:32:21 | :p1 | | type_tracker.rb:32:19:32:26 | Pair | type tracker without call steps | type_tracker.rb:32:19:32:26 | Pair | | type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:32:26:32:26 | 8 | type tracker without call steps | type_tracker.rb:32:26:32:26 | 8 | | type_tracker.rb:32:26:32:26 | 8 | type tracker without call steps with content element :p1 | type_tracker.rb:32:1:32:27 | ** | | type_tracker.rb:34:1:53:3 | &block | type tracker without call steps | type_tracker.rb:34:1:53:3 | &block | -| type_tracker.rb:34:1:53:3 | return return in throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:34:1:53:3 | self in throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | self in throughArray | | type_tracker.rb:34:1:53:3 | throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | throughArray | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:34:18:34:20 | obj | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:36:5:36:10 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:40:5:40:12 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:44:5:44:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:38:13:38:25 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] | | type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] | -| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] | -| type_tracker.rb:34:23:34:23 | y | type tracker with call steps | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y | -| type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y | -| type_tracker.rb:34:26:34:26 | z | type tracker with call steps | type_tracker.rb:34:26:34:26 | z | -| type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z | | type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z | | type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z | | type_tracker.rb:35:5:35:7 | tmp | type tracker without call steps | type_tracker.rb:35:5:35:7 | tmp | @@ -315,46 +219,33 @@ track | type_tracker.rb:50:5:50:10 | array4 | type tracker without call steps | type_tracker.rb:50:5:50:10 | array4 | | type_tracker.rb:50:14:50:26 | Array | type tracker without call steps | type_tracker.rb:50:14:50:26 | Array | | type_tracker.rb:50:14:50:26 | call to [] | type tracker without call steps | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:50:15:50:15 | 1 | | type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element 0 or unknown | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:50:17:50:17 | 2 | | type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element 1 or unknown | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:50:19:50:19 | 3 | | type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element 2 or unknown | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:50:21:50:21 | 4 | | type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element 3 or unknown | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:50:23:50:23 | 5 | | type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element 4 or unknown | type_tracker.rb:50:14:50:26 | call to [] | -| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:50:25:50:25 | 6 | | type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element 5 or unknown | type_tracker.rb:50:14:50:26 | call to [] | | type_tracker.rb:51:5:51:10 | [post] array4 | type tracker without call steps | type_tracker.rb:51:5:51:10 | [post] array4 | | type_tracker.rb:51:5:51:13 | call to []= | type tracker without call steps | type_tracker.rb:51:5:51:13 | call to []= | | type_tracker.rb:51:17:51:19 | __synth__0 | type tracker without call steps | type_tracker.rb:51:17:51:19 | __synth__0 | -| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] | trackEnd | type_tracker.rb:1:1:10:3 | self (Container) | type_tracker.rb:1:1:10:3 | self (Container) | @@ -373,15 +264,6 @@ trackEnd | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type_tracker.rb:32:1:32:27 | self | | type_tracker.rb:2:5:5:7 | &block | type_tracker.rb:2:5:5:7 | &block | | type_tracker.rb:2:5:5:7 | field= | type_tracker.rb:2:5:5:7 | field= | -| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:2:5:5:7 | self (field=) | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:4:9:4:14 | self | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self (field) | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field | -| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self | @@ -390,25 +272,14 @@ trackEnd | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:8:9:8:14 | self | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= | -| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts | | type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field | @@ -416,23 +287,14 @@ trackEnd | type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block | | type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container | | type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field | -| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:7:5:9:7 | return return in field | -| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:15:10:15:18 | call to field | -| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:7:5:9:7 | self (field) | -| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:3:14:3:23 | call to field | -| type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:12:1:16:3 | &block | type_tracker.rb:12:1:16:3 | &block | | type_tracker.rb:12:1:16:3 | m | type_tracker.rb:12:1:16:3 | m | -| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m | -| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) | -| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self | | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self (m) | | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m | | type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self | @@ -470,16 +332,10 @@ trackEnd | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | __synth__0 | | type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:14:17:14:23 | __synth__0 | type_tracker.rb:14:17:14:23 | __synth__0 | -| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:12:1:16:3 | return return in m | | type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:15:5:15:18 | call to puts | | type_tracker.rb:15:10:15:18 | call to field | type_tracker.rb:15:10:15:18 | call to field | | type_tracker.rb:18:1:21:3 | &block | type_tracker.rb:18:1:21:3 | &block | | type_tracker.rb:18:1:21:3 | positional | type_tracker.rb:18:1:21:3 | positional | -| type_tracker.rb:18:1:21:3 | return return in positional | type_tracker.rb:18:1:21:3 | return return in positional | -| type_tracker.rb:18:1:21:3 | return return in positional | type_tracker.rb:23:1:23:16 | call to positional | -| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:18:1:21:3 | self (positional) | -| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:19:5:19:11 | self | -| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:20:5:20:11 | self | | type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:18:1:21:3 | self (positional) | | type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:18:1:21:3 | self in positional | | type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:19:5:19:11 | self | @@ -487,17 +343,12 @@ trackEnd | type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 | | type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 | | type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 | -| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 | -| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:19:10:19:11 | p1 | | type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:19:10:19:11 | p1 | | type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 | | type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 | -| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 | -| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:20:10:20:11 | p2 | | type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:20:10:20:11 | p2 | | type_tracker.rb:19:5:19:11 | call to puts | type_tracker.rb:19:5:19:11 | call to puts | -| type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:18:1:21:3 | return return in positional | | type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:20:5:20:11 | call to puts | | type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:23:1:23:16 | call to positional | | type_tracker.rb:23:1:23:16 | call to positional | type_tracker.rb:23:1:23:16 | call to positional | @@ -512,13 +363,6 @@ trackEnd | type_tracker.rb:25:1:28:3 | &block | type_tracker.rb:25:1:28:3 | &block | | type_tracker.rb:25:1:28:3 | **kwargs | type_tracker.rb:25:1:28:3 | **kwargs | | type_tracker.rb:25:1:28:3 | keyword | type_tracker.rb:25:1:28:3 | keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:25:1:28:3 | return return in keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:30:1:30:21 | call to keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:31:1:31:21 | call to keyword | -| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:32:1:32:27 | call to keyword | -| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:25:1:28:3 | self (keyword) | -| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:26:5:26:11 | self | -| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:27:5:27:11 | self | | type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:26:5:26:11 | self | @@ -526,17 +370,12 @@ trackEnd | type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 | -| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:26:10:26:11 | p1 | | type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:26:10:26:11 | p1 | | type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 | -| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:27:10:27:11 | p2 | | type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:27:10:27:11 | p2 | | type_tracker.rb:26:5:26:11 | call to puts | type_tracker.rb:26:5:26:11 | call to puts | -| type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:25:1:28:3 | return return in keyword | | type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:27:5:27:11 | call to puts | | type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:30:1:30:21 | call to keyword | | type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:31:1:31:21 | call to keyword | @@ -587,80 +426,45 @@ trackEnd | type_tracker.rb:32:26:32:26 | 8 | type_tracker.rb:26:10:26:11 | p1 | | type_tracker.rb:32:26:32:26 | 8 | type_tracker.rb:32:26:32:26 | 8 | | type_tracker.rb:34:1:53:3 | &block | type_tracker.rb:34:1:53:3 | &block | -| type_tracker.rb:34:1:53:3 | return return in throughArray | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:34:1:53:3 | self in throughArray | type_tracker.rb:34:1:53:3 | self in throughArray | | type_tracker.rb:34:1:53:3 | throughArray | type_tracker.rb:34:1:53:3 | throughArray | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:35:12:35:14 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:35:12:35:14 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:36:5:36:10 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:36:5:36:10 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:12 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:12 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:18 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:18 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:40:5:40:12 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:40:5:40:12 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:13 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:13 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:19 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:19 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:44:5:44:13 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:44:5:44:13 | ...[...] | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:13 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:13 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:19 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:19 | ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | ... = ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | obj | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:13 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:13 | __synth__0 | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:19 | ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:19 | ... | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | ... = ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | ... = ... | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | __synth__0 | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | obj | | type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:39:11:39:11 | y | -| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:39:11:39:11 | y | -| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:44:12:44:12 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:44:12:44:12 | y | | type_tracker.rb:34:23:34:23 | y | type_tracker.rb:51:12:51:12 | y | -| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:51:12:51:12 | y | | type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z | | type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z | | type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z | -| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z | -| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:52:12:52:12 | z | | type_tracker.rb:34:26:34:26 | z | type_tracker.rb:52:12:52:12 | z | | type_tracker.rb:35:5:35:7 | tmp | type_tracker.rb:35:5:35:7 | tmp | | type_tracker.rb:35:11:35:15 | Array | type_tracker.rb:35:11:35:15 | Array | @@ -743,29 +547,22 @@ trackEnd | type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:50:14:50:26 | call to [] | | type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:51:5:51:10 | array4 | | type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:52:5:52:10 | array4 | -| type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:50:15:50:15 | 1 | | type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:50:17:50:17 | 2 | | type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:50:19:50:19 | 3 | | type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:50:21:50:21 | 4 | | type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:50:23:50:23 | 5 | | type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:52:5:52:13 | ...[...] | -| type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:50:25:50:25 | 6 | | type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:52:5:52:13 | ...[...] | | type_tracker.rb:51:5:51:10 | [post] array4 | type_tracker.rb:51:5:51:10 | [post] array4 | | type_tracker.rb:51:5:51:10 | [post] array4 | type_tracker.rb:52:5:52:10 | array4 | | type_tracker.rb:51:5:51:13 | call to []= | type_tracker.rb:51:5:51:13 | call to []= | | type_tracker.rb:51:17:51:19 | __synth__0 | type_tracker.rb:51:17:51:19 | __synth__0 | -| type_tracker.rb:52:5:52:13 | ...[...] | type_tracker.rb:34:1:53:3 | return return in throughArray | | type_tracker.rb:52:5:52:13 | ...[...] | type_tracker.rb:52:5:52:13 | ...[...] | forwardButNoBackwardFlow backwardButNoForwardFlow From 1788c54bd8eed26609e78e0244cbc343772632e1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 1 May 2023 13:13:26 +0200 Subject: [PATCH 042/219] Python: Avoid calling `TypeTracker::step` in call graph construction --- .../new/internal/DataFlowDispatch.qll | 331 +++++++++++++----- 1 file changed, 246 insertions(+), 85 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index cdca96cc4ac..958bca246cb 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -464,22 +464,55 @@ private predicate ignoreForCallGraph(File f) { f.getAbsolutePath().matches("%/site-packages/sympy/%") } +bindingset[n] +pragma[inline_late] +private predicate includeInCallGraph(TypeTrackingNode n) { + not ignoreForCallGraph(n.getLocation().getFile()) +} + +pragma[nomagic] +private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { + StepSummary::stepCall(nodeFrom, _, summary) +} + +bindingset[t, summary] +pragma[inline_late] +private TypeTracker append(TypeTracker t, StepSummary summary) { result = t.append(summary) } + /** * Gets a reference to the function `func`. */ private TypeTrackingNode functionTracker(TypeTracker t, Function func) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and + includeInCallGraph(result) and ( - result.asExpr() = func.getDefinition() + t.start() and + ( + result.asExpr() = func.getDefinition() + or + // when a function is decorated, it's the result of the (last) decorator call that + // is used + result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() + ) or - // when a function is decorated, it's the result of the (last) decorator call that - // is used - result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() + ( + exists(TypeTracker t2 | t = t2.stepNoCall(functionTracker(t2, func), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(functionTrackerCall(t, func, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode functionTrackerCall(TypeTracker t, Function func, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = functionTracker(t2, func) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = functionTracker(t2, func).track(t2, t)) } /** @@ -491,23 +524,41 @@ Node functionTracker(Function func) { functionTracker(TypeTracker::end(), func). * Gets a reference to the class `cls`. */ private TypeTrackingNode classTracker(TypeTracker t, Class cls) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and + includeInCallGraph(result) and ( - result.asExpr() = cls.getParent() + t.start() and + ( + result.asExpr() = cls.getParent() + or + // when a class is decorated, it's the result of the (last) decorator call that + // is used + result.asExpr() = cls.getParent().getADecoratorCall() + or + // `type(obj)`, where obj is an instance of this class + result = getTypeCall() and + result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) + ) or - // when a class is decorated, it's the result of the (last) decorator call that - // is used - result.asExpr() = cls.getParent().getADecoratorCall() - or - // `type(obj)`, where obj is an instance of this class - result = getTypeCall() and - result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(classTracker(t2, cls), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(classTrackerCall(t, cls, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode classTrackerCall(TypeTracker t, Class cls, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = classTracker(t2, cls) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -519,21 +570,38 @@ Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(res * Gets a reference to an instance of the class `cls`. */ private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and - resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) - or - // result of `super().__new__` as used in a `__new__` method implementation - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and - exists(Class classUsedInSuper | - fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and - classUsedInSuper = getADirectSuperclass*(cls) + includeInCallGraph(result) and + ( + t.start() and + resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) + or + // result of `super().__new__` as used in a `__new__` method implementation + t.start() and + exists(Class classUsedInSuper | + fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and + classUsedInSuper = getADirectSuperclass*(cls) + ) + or + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(classInstanceTracker(t2, cls), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(classInstanceTrackerCall(t, cls, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode classInstanceTrackerCall(TypeTracker t, Class cls, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = classInstanceTracker(t2, cls) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -548,19 +616,37 @@ Node classInstanceTracker(Class cls) { * The method cannot be a `staticmethod` or `classmethod`. */ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and - exists(Function func | - func = classWithMethod.getAMethod() and - not isStaticmethod(func) and - not isClassmethod(func) - | - result.asExpr() = func.getArg(0) + includeInCallGraph(result) and + ( + t.start() and + exists(Function func | + func = classWithMethod.getAMethod() and + not isStaticmethod(func) and + not isClassmethod(func) + | + result.asExpr() = func.getArg(0) + ) + or + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(selfTracker(t2, classWithMethod), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(selfTrackerCall(t, classWithMethod, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode selfTrackerCall(TypeTracker t, Class classWithMethod, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = selfTracker(t2, classWithMethod) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -577,24 +663,44 @@ Node selfTracker(Class classWithMethod) { * from a normal method. */ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and + includeInCallGraph(result) and ( - exists(Function func | - func = classWithMethod.getAMethod() and - isClassmethod(func) - | - result.asExpr() = func.getArg(0) + t.start() and + ( + exists(Function func | + func = classWithMethod.getAMethod() and + isClassmethod(func) + | + result.asExpr() = func.getArg(0) + ) + or + // type(self) + result = getTypeCall() and + result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) ) or - // type(self) - result = getTypeCall() and - result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(clsArgumentTracker(t2, classWithMethod), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(clsArgumentTrackerCall(t, classWithMethod, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode clsArgumentTrackerCall( + TypeTracker t, Class classWithMethod, StepSummary summary +) { + exists(TypeTracker t2 | + // non-linear recursion + result = clsArgumentTracker(t2, classWithMethod) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = clsArgumentTracker(t2, classWithMethod).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -611,18 +717,38 @@ Node clsArgumentTracker(Class classWithMethod) { * call happened in the method `func` (either a method or a classmethod). */ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and - not isStaticmethod(func) and - exists(CallCfgNode call | result = call | - call = getSuperCall() and - not exists(call.getArg(_)) and - call.getScope() = func + includeInCallGraph(result) and + ( + t.start() and + not isStaticmethod(func) and + exists(CallCfgNode call | result = call | + call = getSuperCall() and + not exists(call.getArg(_)) and + call.getScope() = func + ) + or + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(superCallNoArgumentTracker(t2, func), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(superCallNoArgumentTrackerCall(t, func, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode superCallNoArgumentTrackerCall( + TypeTracker t, Function func, StepSummary summary +) { + exists(TypeTracker t2 | + // non-linear recursion + result = functionTracker(t2, func) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -638,17 +764,37 @@ Node superCallNoArgumentTracker(Function func) { * first is a reference to the class `cls`, and the second argument is `obj`. */ private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, Node obj) { - not ignoreForCallGraph(result.getLocation().getFile()) and - t.start() and - exists(CallCfgNode call | result = call | - call = getSuperCall() and - call.getArg(0) = classTracker(cls) and - call.getArg(1) = obj + includeInCallGraph(result) and + ( + t.start() and + exists(CallCfgNode call | result = call | + call = getSuperCall() and + call.getArg(0) = classTracker(cls) and + call.getArg(1) = obj + ) + or + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and + ( + exists(TypeTracker t2 | t = t2.stepNoCall(superCallTwoArgumentTracker(t2, cls, obj), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(superCallTwoArgumentTrackerCall(t, cls, obj, summary), result, summary) + ) + ) + ) +} + +pragma[nomagic] +private TypeTrackingNode superCallTwoArgumentTrackerCall( + TypeTracker t, Class cls, Node obj, StepSummary summary +) { + exists(TypeTracker t2 | + // non-linear recursion + result = superCallTwoArgumentTracker(t2, cls, obj) and + stepCallProj(result, summary) and + t = append(t2, summary) ) - or - not ignoreForCallGraph(result.getLocation().getFile()) and - exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) and - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -809,7 +955,22 @@ private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) { superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _) ] or - exists(TypeTracker t2 | result = attrReadTracker(t2, attr).track(t2, t)) + exists(TypeTracker t2 | t = t2.stepNoCall(attrReadTracker(t2, attr), result)) + or + exists(StepSummary summary | + // non-linear recursion + StepSummary::stepCall(attrReadTrackerCall(t, attr, summary), result, summary) + ) +} + +pragma[nomagic] +private TypeTrackingNode attrReadTrackerCall(TypeTracker t, AttrRead attr, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = attrReadTracker(t2, attr) and + stepCallProj(result, summary) and + t = append(t2, summary) + ) } /** Gets a reference to the attribute read `attr` */ From 242d263e8a11617492d7375193f7841521306431 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 15:18:15 +0200 Subject: [PATCH 043/219] Codegen: move ipa info from `ql.Class` to `ql.Property` --- misc/codegen/generators/qlgen.py | 6 +++--- misc/codegen/lib/ql.py | 2 +- misc/codegen/templates/ql_class.mustache | 16 ++++++++-------- misc/codegen/test/test_qlgen.py | 16 ++++++++++++---- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index 7affea51828..49b1b537bc2 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -110,7 +110,8 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str = is_optional=prop.is_optional, is_predicate=prop.is_predicate, is_unordered=prop.is_unordered, - description=prop.description + description=prop.description, + synth=bool(cls.ipa), ) if prop.is_single: args.update( @@ -162,7 +163,6 @@ def get_ql_class(cls: schema.Class) -> ql.Class: final=not cls.derived, properties=properties, dir=pathlib.Path(cls.group or ""), - ipa=bool(cls.ipa), doc=cls.doc, **pragmas, ) @@ -342,7 +342,7 @@ def generate(opts, renderer): with renderer.manage(generated=generated, stubs=stubs, registry=opts.generated_registry, force=opts.force) as renderer: - db_classes = [cls for cls in classes.values() if not cls.ipa] + db_classes = [cls for name, cls in classes.items() if not data.classes[name].ipa] renderer.render(ql.DbClasses(db_classes), out / "Raw.qll") classes_by_dir_and_name = sorted(classes.values(), key=lambda cls: (cls.dir, cls.name)) diff --git a/misc/codegen/lib/ql.py b/misc/codegen/lib/ql.py index 97165053fd0..e4bac3197cb 100644 --- a/misc/codegen/lib/ql.py +++ b/misc/codegen/lib/ql.py @@ -42,6 +42,7 @@ class Property: description: List[str] = field(default_factory=list) doc: Optional[str] = None doc_plural: Optional[str] = None + synth: bool = False def __post_init__(self): if self.tableparams: @@ -111,7 +112,6 @@ class Class: qltest_collapse_hierarchy: bool = False qltest_uncollapse_hierarchy: bool = False ql_internal: bool = False - ipa: bool = False doc: List[str] = field(default_factory=list) def __post_init__(self): diff --git a/misc/codegen/templates/ql_class.mustache b/misc/codegen/templates/ql_class.mustache index 9f72caef392..8ee465bf993 100644 --- a/misc/codegen/templates/ql_class.mustache +++ b/misc/codegen/templates/ql_class.mustache @@ -67,12 +67,12 @@ module Generated { * behavior of both the `Immediate` and non-`Immediate` versions. */ {{type}} get{{#is_unordered}}An{{/is_unordered}}Immediate{{singular}}({{#is_indexed}}int index{{/is_indexed}}) { - {{^ipa}} + {{^synth}} result = Synth::convert{{type}}FromRaw(Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_indexed}}index{{/is_indexed}})) - {{/ipa}} - {{#ipa}} + {{/synth}} + {{#synth}} none() - {{/ipa}} + {{/synth}} } /** @@ -99,12 +99,12 @@ module Generated { {{/has_description}} */ {{type}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) { - {{^ipa}} + {{^synth}} {{^is_predicate}}result = {{/is_predicate}}Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_indexed}}index{{/is_indexed}}) - {{/ipa}} - {{#ipa}} + {{/synth}} + {{#synth}} none() - {{/ipa}} + {{/synth}} } {{/type_is_class}} diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 1cd85762315..6ed83edf4e0 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -861,25 +861,33 @@ def test_property_on_class_with_default_doc_name(generate_classes): def test_stub_on_class_with_ipa_from_class(generate_classes): assert generate_classes([ - schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A")), + schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A"), + properties=[schema.SingleProperty("foo", "bar")]), ]) == { "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ ql.IpaUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]), ]), - a_ql_class(name="MyObject", final=True, ipa=True)), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, + tableparams=["this", "result"], doc="foo of this my object"), + ])), } def test_stub_on_class_with_ipa_on_arguments(generate_classes): assert generate_classes([ - schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"})), + schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"}), + properties=[schema.SingleProperty("foo", "bar")]), ]) == { "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ ql.IpaUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]), ql.IpaUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]), ql.IpaUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]), ]), - a_ql_class(name="MyObject", final=True, ipa=True)), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, + tableparams=["this", "result"], doc="foo of this my object"), + ])), } From 165ac3eeaa2104b5947cc0869e9c9479abfa8e3c Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 15:28:53 +0200 Subject: [PATCH 044/219] Codegen: define and propagate `synth` property flag --- misc/codegen/generators/qlgen.py | 2 +- misc/codegen/lib/schema.py | 1 + misc/codegen/test/test_qlgen.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index 49b1b537bc2..a5b8379580f 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -111,7 +111,7 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str = is_predicate=prop.is_predicate, is_unordered=prop.is_unordered, description=prop.description, - synth=bool(cls.ipa), + synth=bool(cls.ipa) or prop.synth, ) if prop.is_single: args.update( diff --git a/misc/codegen/lib/schema.py b/misc/codegen/lib/schema.py index 64a4720093b..2f3ce1cb9d3 100644 --- a/misc/codegen/lib/schema.py +++ b/misc/codegen/lib/schema.py @@ -34,6 +34,7 @@ class Property: pragmas: List[str] = field(default_factory=list) doc: Optional[str] = None description: List[str] = field(default_factory=list) + synth: bool = False @property def is_single(self) -> bool: diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 6ed83edf4e0..4650974510f 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -891,5 +891,19 @@ def test_stub_on_class_with_ipa_on_arguments(generate_classes): } +def test_synth_property(generate_classes): + assert generate_classes([ + schema.Class("MyObject", properties=[ + schema.SingleProperty("foo", "bar", synth=True)]), + ]) == { + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, + tableparams=["this", "result"], doc="foo of this my object"), + ])), + } + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) From d2c9847a790197ce1fe36b957f7ac511f3d630fa Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 15:36:32 +0200 Subject: [PATCH 045/219] Codegen: parse `synth` property modifier --- misc/codegen/lib/schemadefs.py | 7 ++++++- misc/codegen/test/test_schemaloader.py | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py index f3bfd9840dc..3db8fe781ce 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -44,10 +44,15 @@ class _Namespace: self.__dict__.update(kwargs) +class _SynthModifier(_schema.PropertyModifier, _Namespace): + def modify(self, prop: _schema.Property): + prop.synth = True + + qltest = _Namespace() ql = _Namespace() cpp = _Namespace() -synth = _Namespace() +synth = _SynthModifier() @_dataclass diff --git a/misc/codegen/test/test_schemaloader.py b/misc/codegen/test/test_schemaloader.py index 9c9750818ea..949d2f385be 100644 --- a/misc/codegen/test/test_schemaloader.py +++ b/misc/codegen/test/test_schemaloader.py @@ -455,6 +455,17 @@ def test_ipa_class_hierarchy(): } +def test_synthesized_property(): + @load + class data: + class A: + x: defs.int | defs.synth + + assert data.classes["A"].properties == [ + schema.SingleProperty("x", "int", synth=True) + ] + + def test_class_docstring(): @load class data: From 00fb796f3bd79243830bbb11b97e675c70adac43 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 15:43:43 +0200 Subject: [PATCH 046/219] Codegen: ignore `synth` properties in `dbschemegen` --- misc/codegen/generators/dbschemegen.py | 7 +++++-- misc/codegen/test/test_dbschemegen.py | 27 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/misc/codegen/generators/dbschemegen.py b/misc/codegen/generators/dbschemegen.py index 8441b6fd61d..bc45ae3022f 100755 --- a/misc/codegen/generators/dbschemegen.py +++ b/misc/codegen/generators/dbschemegen.py @@ -49,7 +49,7 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a # Leaf classes need a table to bind the `@` ids # 1-to-1 properties are added to a class specific table # in other cases, separate tables are used for the properties, and a class specific table is unneeded - if not cls.derived or any(f.is_single for f in cls.properties): + if not cls.derived or any(f.is_single and not f.synth for f in cls.properties): binding = not cls.derived keyset = KeySet(["id"]) if cls.derived else None yield Table( @@ -58,12 +58,15 @@ def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], a columns=[ Column("id", type=dbtype(cls.name), binding=binding), ] + [ - Column(f.name, dbtype(f.type, add_or_none_except)) for f in cls.properties if f.is_single + Column(f.name, dbtype(f.type, add_or_none_except)) + for f in cls.properties if f.is_single and not f.synth ], dir=dir, ) # use property-specific tables for 1-to-many and 1-to-at-most-1 properties for f in cls.properties: + if f.synth: + continue if f.is_unordered: yield Table( name=inflection.tableize(f"{cls.name}_{f.name}"), diff --git a/misc/codegen/test/test_dbschemegen.py b/misc/codegen/test/test_dbschemegen.py index 86b9dd2fc84..45b5718a876 100644 --- a/misc/codegen/test/test_dbschemegen.py +++ b/misc/codegen/test/test_dbschemegen.py @@ -566,5 +566,32 @@ def test_ipa_derived_classes_ignored(generate): ) +def test_synth_properties_ignored(generate): + assert generate([ + schema.Class(name="A", properties=[ + schema.SingleProperty("x", "a"), + schema.SingleProperty("y", "b", synth=True), + schema.SingleProperty("z", "c"), + schema.OptionalProperty("foo", "bar", synth=True), + schema.RepeatedProperty("baz", "bazz", synth=True), + schema.RepeatedOptionalProperty("bazzz", "bazzzz", synth=True), + schema.RepeatedUnorderedProperty("bazzzzz", "bazzzzzz", synth=True), + ]), + ]) == dbscheme.Scheme( + src=schema_file.name, + includes=[], + declarations=[ + dbscheme.Table( + name="as", + columns=[ + dbscheme.Column("id", "@a", binding=True), + dbscheme.Column("x", "a"), + dbscheme.Column("z", "c"), + ], + ) + ], + ) + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) From b09386a2c8ff10d6227a04236c688afe340a4f43 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 15:55:57 +0200 Subject: [PATCH 047/219] Codegen: ignore `synth` properties in `Raw.qll` --- misc/codegen/templates/ql_db.mustache | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misc/codegen/templates/ql_db.mustache b/misc/codegen/templates/ql_db.mustache index d16416f4a5b..188abebc120 100644 --- a/misc/codegen/templates/ql_db.mustache +++ b/misc/codegen/templates/ql_db.mustache @@ -15,6 +15,7 @@ module Raw { {{#final}}override string toString() { result = "{{name}}" }{{/final}} {{#properties}} + {{^synth}} /** * {{>ql_property_doc}} * {{#has_description}} @@ -26,6 +27,7 @@ module Raw { {{type}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) { {{tablename}}({{#tableparams}}{{^first}}, {{/first}}{{param}}{{/tableparams}}) } + {{/synth}} {{/properties}} } From cc271d682e387a0163fa21de7c50ce36fecf0d91 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Tue, 23 May 2023 16:46:43 +0200 Subject: [PATCH 048/219] Codegen: ignore `synth` properties in `cppgen` --- misc/codegen/generators/cppgen.py | 2 +- misc/codegen/test/test_cppgen.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/misc/codegen/generators/cppgen.py b/misc/codegen/generators/cppgen.py index 1cd6cc36450..8f522dc1435 100644 --- a/misc/codegen/generators/cppgen.py +++ b/misc/codegen/generators/cppgen.py @@ -76,7 +76,7 @@ class Processor: bases=[self._get_class(b) for b in cls.bases], fields=[ _get_field(cls, p, self._add_or_none_except) - for p in cls.properties if "cpp_skip" not in p.pragmas + for p in cls.properties if "cpp_skip" not in p.pragmas and not p.synth ], final=not cls.derived, trap_name=trap_name, diff --git a/misc/codegen/test/test_cppgen.py b/misc/codegen/test/test_cppgen.py index 1bc7d150b2e..ebb7b3887ef 100644 --- a/misc/codegen/test/test_cppgen.py +++ b/misc/codegen/test/test_cppgen.py @@ -203,5 +203,27 @@ def test_ipa_classes_ignored(generate): ] +def test_synth_properties_ignored(generate): + assert generate([ + schema.Class( + name="X", + properties=[ + schema.SingleProperty("x", "a"), + schema.SingleProperty("y", "b", synth=True), + schema.SingleProperty("z", "c"), + schema.OptionalProperty("foo", "bar", synth=True), + schema.RepeatedProperty("baz", "bazz", synth=True), + schema.RepeatedOptionalProperty("bazzz", "bazzzz", synth=True), + schema.RepeatedUnorderedProperty("bazzzzz", "bazzzzzz", synth=True), + ], + ), + ]) == [ + cpp.Class(name="X", final=True, trap_name="Xes", fields=[ + cpp.Field("x", "a"), + cpp.Field("z", "c"), + ]), + ] + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) From 0e443da7106bd86078b98e2ab3aeb09bb17ba49a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 May 2023 17:43:42 +0100 Subject: [PATCH 049/219] Swift: Remove id() categorization due to accuracy, and repair the old bank.?account case. --- .../codeql/swift/security/SensitiveExprs.qll | 8 +- .../CWE-311/CleartextTransmission.expected | 4 - .../Security/CWE-311/SensitiveExprs.expected | 85 +++++++++---------- .../Security/CWE-311/testURL.swift | 2 +- .../CWE-328/WeakSensitiveDataHashing.expected | 12 --- .../Security/CWE-328/testCryptoKit.swift | 12 +-- 6 files changed, 53 insertions(+), 70 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index c3432fa58e4..b6f5c231823 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -30,7 +30,11 @@ class SensitiveCredential extends SensitiveDataType, TCredential { override string toString() { result = "credential" } override string getRegexp() { - result = HeuristicNames::maybeSensitiveRegexp(_) or + exists(SensitiveDataClassification classification | + not classification = SensitiveDataClassification::id() and // not accurate enough + result = HeuristicNames::maybeSensitiveRegexp(classification) + ) + or result = "(?is).*(license.?key).*" } } @@ -54,7 +58,7 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { // Geographic location - where the user is (or was) "latitude|longitude|" + // Financial data - such as credit card numbers, salary, bank accounts, and debts - "credit.?card|debit.?card|salary|" + + "credit.?card|debit.?card|salary|bank.?account|" + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. "email|" + // Health - medical conditions, insurance status, prescription records diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index c832cf51a15..94272faf6d0 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -13,7 +13,6 @@ edges | testSend.swift:54:17:54:17 | password | testSend.swift:41:10:41:18 | data | | testSend.swift:54:17:54:17 | password | testSend.swift:54:13:54:25 | call to pad(_:) | | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | -| testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | nodes | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | @@ -41,8 +40,6 @@ nodes | testSend.swift:66:27:66:30 | .mobileNumber | semmle.label | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:13:54:13:54 | passwd | semmle.label | passwd | -| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| testURL.swift:15:55:15:55 | account_no | semmle.label | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | semmle.label | credit_card_no | | testURL.swift:20:22:20:22 | passwd | semmle.label | passwd | @@ -61,6 +58,5 @@ subpaths | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | This operation transmits 'license_key', which may contain unencrypted sensitive data from $@. | testSend.swift:65:27:65:27 | license_key | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | This operation transmits '.mobileNumber', which may contain unencrypted sensitive data from $@. | testSend.swift:66:27:66:30 | .mobileNumber | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:13:54:13:54 | passwd | passwd | -| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:15:55:15:55 | account_no | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:16:55:16:55 | credit_card_no | credit_card_no | | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | This operation transmits 'passwd', which may contain unencrypted sensitive data from $@. | testURL.swift:20:22:20:22 | passwd | passwd | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 708d68a05e9..89b8d36ccdf 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -4,54 +4,50 @@ | testAlamofire.swift:159:26:159:26 | email | label:email, type:private information | | testAlamofire.swift:171:35:171:35 | email | label:email, type:private information | | testAlamofire.swift:177:35:177:35 | email | label:email, type:private information | -| testAlamofire.swift:187:48:187:48 | username | label:username, type:credential | | testAlamofire.swift:187:65:187:65 | password | label:password, type:credential | -| testAlamofire.swift:195:47:195:47 | username | label:username, type:credential | | testAlamofire.swift:195:64:195:64 | password | label:password, type:credential | -| testAlamofire.swift:205:45:205:45 | username | label:username, type:credential | | testAlamofire.swift:205:62:205:62 | password | label:password, type:credential | -| testAlamofire.swift:213:48:213:48 | username | label:username, type:credential | | testAlamofire.swift:213:65:213:65 | password | label:password, type:credential | -| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | -| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | -| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | -| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | -| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | -| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:credential | -| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | -| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:credential | -| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:credential | -| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:credential | -| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:credential | -| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:credential | -| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:credential | -| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:credential | -| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:credential | +| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | +| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | +| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | +| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | +| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | +| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information | +| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | +| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information | +| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information | +| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:79:18:79:28 | .bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | label:bankAccountNo2, type:private information | +| testCoreData2.swift:82:18:82:18 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:83:18:83:18 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:84:18:84:18 | bankAccountNo2 | label:bankAccountNo2, type:private information | +| testCoreData2.swift:85:18:85:18 | bankAccountNo2 | label:bankAccountNo2, type:private information | +| testCoreData2.swift:87:22:87:32 | .bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:88:22:88:22 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:89:22:89:22 | bankAccountNo2 | label:bankAccountNo2, type:private information | +| testCoreData2.swift:91:10:91:10 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:95:10:95:10 | bankAccountNo | label:bankAccountNo, type:private information | +| testCoreData2.swift:101:10:101:10 | bankAccountNo | label:bankAccountNo, type:private information | | testCoreData.swift:48:15:48:15 | password | label:password, type:credential | | testCoreData.swift:51:24:51:24 | password | label:password, type:credential | | testCoreData.swift:58:15:58:15 | password | label:password, type:credential | @@ -133,6 +129,5 @@ | testSend.swift:66:27:66:30 | .mobileNumber | label:mobileNumber, type:private information | | testSend.swift:69:27:69:30 | .passwordFeatureEnabled | label:passwordFeatureEnabled, type:credential | | testURL.swift:13:54:13:54 | passwd | label:passwd, type:credential | -| testURL.swift:15:55:15:55 | account_no | label:account_no, type:credential | | testURL.swift:16:55:16:55 | credit_card_no | label:credit_card_no, type:private information | | testURL.swift:20:22:20:22 | passwd | label:passwd, type:credential | diff --git a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift index 7f9b64ff4f6..48ae815232f 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift @@ -12,7 +12,7 @@ struct URL func test1(passwd : String, encrypted_passwd : String, account_no : String, credit_card_no : String) { let a = URL(string: "http://example.com/login?p=" + passwd); // BAD let b = URL(string: "http://example.com/login?p=" + encrypted_passwd); // GOOD (not sensitive) - let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD + let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD [NOT DETECTED] let d = URL(string: "http://example.com/login?cc=" + credit_card_no); // BAD let base = URL(string: "http://example.com/"); // GOOD (not sensitive) diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected index 16fc67d4a6f..b6c7161b853 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected @@ -2,28 +2,22 @@ edges nodes | testCryptoKit.swift:56:47:56:47 | passwd | semmle.label | passwd | | testCryptoKit.swift:57:43:57:43 | cert | semmle.label | cert | -| testCryptoKit.swift:59:43:59:43 | account_no | semmle.label | account_no | | testCryptoKit.swift:60:43:60:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:61:43:61:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:63:44:63:44 | passwd | semmle.label | passwd | | testCryptoKit.swift:64:44:64:44 | cert | semmle.label | cert | -| testCryptoKit.swift:66:44:66:44 | account_no | semmle.label | account_no | | testCryptoKit.swift:67:44:67:44 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:90:23:90:23 | passwd | semmle.label | passwd | | testCryptoKit.swift:91:23:91:23 | cert | semmle.label | cert | -| testCryptoKit.swift:93:23:93:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:94:23:94:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:99:23:99:23 | passwd | semmle.label | passwd | | testCryptoKit.swift:100:23:100:23 | cert | semmle.label | cert | -| testCryptoKit.swift:102:23:102:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:103:23:103:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:132:32:132:32 | passwd | semmle.label | passwd | | testCryptoKit.swift:133:32:133:32 | cert | semmle.label | cert | -| testCryptoKit.swift:135:32:135:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:136:32:136:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:141:32:141:32 | passwd | semmle.label | passwd | | testCryptoKit.swift:142:32:142:32 | cert | semmle.label | cert | -| testCryptoKit.swift:144:32:144:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:145:32:145:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoSwift.swift:113:30:113:30 | passwdArray | semmle.label | passwdArray | | testCryptoSwift.swift:115:31:115:31 | passwdArray | semmle.label | passwdArray | @@ -39,28 +33,22 @@ subpaths #select | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:56:47:56:47 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:57:43:57:43 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:59:43:59:43 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:60:43:60:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:61:43:61:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:63:44:63:44 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:64:44:64:44 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:66:44:66:44 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:67:44:67:44 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:90:23:90:23 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:91:23:91:23 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:93:23:93:23 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:94:23:94:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:99:23:99:23 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:100:23:100:23 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:102:23:102:23 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:103:23:103:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:132:32:132:32 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:133:32:133:32 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:135:32:135:32 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:136:32:136:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:141:32:141:32 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:142:32:142:32 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:144:32:144:32 | account_no | sensitive data (credential account_no) | | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:145:32:145:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:113:30:113:30 | passwdArray | sensitive data (credential passwdArray) | | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:115:31:115:31 | passwdArray | sensitive data (credential passwdArray) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index 55fb9284fa6..4e6f301c84b 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -56,14 +56,14 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa var hash = Crypto.Insecure.MD5.hash(data: passwd) // BAD hash = Crypto.Insecure.MD5.hash(data: cert) // BAD hash = Crypto.Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD + hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD [NOT DETECTED] hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD hash = Crypto.Insecure.SHA1.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD + hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD [NOT DETECTED] hash = Crypto.Insecure.SHA1.hash(data: credit_card_no) // BAD hash = Crypto.SHA256.hash(data: passwd) // BAD [NOT DETECTED] not a computationally expensive hash @@ -90,7 +90,7 @@ func testMD5UpdateWithData(passwd : String, cert: String, encrypted_passwd : Str hash.update(data: passwd) // BAD hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD + hash.update(data: account_no) // BAD [NOT DETECTED] hash.update(data: credit_card_no) // BAD } @@ -99,7 +99,7 @@ func testSHA1UpdateWithData(passwd : String, cert: String, encrypted_passwd : St hash.update(data: passwd) // BAD hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD + hash.update(data: account_no) // BAD [NOT DETECTED] hash.update(data: credit_card_no) // BAD } @@ -132,7 +132,7 @@ func testMD5UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, ce hash.update(bufferPointer: passwd) // BAD hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD + hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] hash.update(bufferPointer: credit_card_no) // BAD } @@ -141,7 +141,7 @@ func testSHA1UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, c hash.update(bufferPointer: passwd) // BAD hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD + hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] hash.update(bufferPointer: credit_card_no) // BAD } From 736f2871f9cc61c078e1839d12f255926861613e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 May 2023 22:02:32 +0100 Subject: [PATCH 050/219] Swift: Tweak private info regexps to restore 'account_no' results. --- .../ql/lib/codeql/swift/security/SensitiveExprs.qll | 2 +- .../Security/CWE-311/CleartextTransmission.expected | 4 ++++ .../Security/CWE-311/SensitiveExprs.expected | 1 + .../test/query-tests/Security/CWE-311/testURL.swift | 2 +- .../CWE-328/WeakSensitiveDataHashing.expected | 12 ++++++++++++ .../query-tests/Security/CWE-328/testCryptoKit.swift | 12 ++++++------ 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index b6f5c231823..71a250229e7 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -58,7 +58,7 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo { // Geographic location - where the user is (or was) "latitude|longitude|" + // Financial data - such as credit card numbers, salary, bank accounts, and debts - "credit.?card|debit.?card|salary|bank.?account|" + + "credit.?card|debit.?card|salary|bank.?account|acc(ou)?nt.?(no|num)|" + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. "email|" + // Health - medical conditions, insurance status, prescription records diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index 94272faf6d0..c832cf51a15 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -13,6 +13,7 @@ edges | testSend.swift:54:17:54:17 | password | testSend.swift:41:10:41:18 | data | | testSend.swift:54:17:54:17 | password | testSend.swift:54:13:54:25 | call to pad(_:) | | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | +| testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | nodes | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | @@ -40,6 +41,8 @@ nodes | testSend.swift:66:27:66:30 | .mobileNumber | semmle.label | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:13:54:13:54 | passwd | semmle.label | passwd | +| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| testURL.swift:15:55:15:55 | account_no | semmle.label | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testURL.swift:16:55:16:55 | credit_card_no | semmle.label | credit_card_no | | testURL.swift:20:22:20:22 | passwd | semmle.label | passwd | @@ -58,5 +61,6 @@ subpaths | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | testSend.swift:65:27:65:27 | license_key | This operation transmits 'license_key', which may contain unencrypted sensitive data from $@. | testSend.swift:65:27:65:27 | license_key | license_key | | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | testSend.swift:66:27:66:30 | .mobileNumber | This operation transmits '.mobileNumber', which may contain unencrypted sensitive data from $@. | testSend.swift:66:27:66:30 | .mobileNumber | .mobileNumber | | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | testURL.swift:13:54:13:54 | passwd | testURL.swift:13:22:13:54 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:13:54:13:54 | passwd | passwd | +| testURL.swift:15:22:15:55 | ... .+(_:_:) ... | testURL.swift:15:55:15:55 | account_no | testURL.swift:15:22:15:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:15:55:15:55 | account_no | account_no | | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | testURL.swift:16:55:16:55 | credit_card_no | testURL.swift:16:22:16:55 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:16:55:16:55 | credit_card_no | credit_card_no | | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | This operation transmits 'passwd', which may contain unencrypted sensitive data from $@. | testURL.swift:20:22:20:22 | passwd | passwd | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index 89b8d36ccdf..69de9137213 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -129,5 +129,6 @@ | testSend.swift:66:27:66:30 | .mobileNumber | label:mobileNumber, type:private information | | testSend.swift:69:27:69:30 | .passwordFeatureEnabled | label:passwordFeatureEnabled, type:credential | | testURL.swift:13:54:13:54 | passwd | label:passwd, type:credential | +| testURL.swift:15:55:15:55 | account_no | label:account_no, type:private information | | testURL.swift:16:55:16:55 | credit_card_no | label:credit_card_no, type:private information | | testURL.swift:20:22:20:22 | passwd | label:passwd, type:credential | diff --git a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift index 48ae815232f..7f9b64ff4f6 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift @@ -12,7 +12,7 @@ struct URL func test1(passwd : String, encrypted_passwd : String, account_no : String, credit_card_no : String) { let a = URL(string: "http://example.com/login?p=" + passwd); // BAD let b = URL(string: "http://example.com/login?p=" + encrypted_passwd); // GOOD (not sensitive) - let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD [NOT DETECTED] + let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD let d = URL(string: "http://example.com/login?cc=" + credit_card_no); // BAD let base = URL(string: "http://example.com/"); // GOOD (not sensitive) diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected index b6c7161b853..a23916e1a5c 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected @@ -2,22 +2,28 @@ edges nodes | testCryptoKit.swift:56:47:56:47 | passwd | semmle.label | passwd | | testCryptoKit.swift:57:43:57:43 | cert | semmle.label | cert | +| testCryptoKit.swift:59:43:59:43 | account_no | semmle.label | account_no | | testCryptoKit.swift:60:43:60:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:61:43:61:43 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:63:44:63:44 | passwd | semmle.label | passwd | | testCryptoKit.swift:64:44:64:44 | cert | semmle.label | cert | +| testCryptoKit.swift:66:44:66:44 | account_no | semmle.label | account_no | | testCryptoKit.swift:67:44:67:44 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:90:23:90:23 | passwd | semmle.label | passwd | | testCryptoKit.swift:91:23:91:23 | cert | semmle.label | cert | +| testCryptoKit.swift:93:23:93:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:94:23:94:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:99:23:99:23 | passwd | semmle.label | passwd | | testCryptoKit.swift:100:23:100:23 | cert | semmle.label | cert | +| testCryptoKit.swift:102:23:102:23 | account_no | semmle.label | account_no | | testCryptoKit.swift:103:23:103:23 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:132:32:132:32 | passwd | semmle.label | passwd | | testCryptoKit.swift:133:32:133:32 | cert | semmle.label | cert | +| testCryptoKit.swift:135:32:135:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:136:32:136:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:141:32:141:32 | passwd | semmle.label | passwd | | testCryptoKit.swift:142:32:142:32 | cert | semmle.label | cert | +| testCryptoKit.swift:144:32:144:32 | account_no | semmle.label | account_no | | testCryptoKit.swift:145:32:145:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoSwift.swift:113:30:113:30 | passwdArray | semmle.label | passwdArray | | testCryptoSwift.swift:115:31:115:31 | passwdArray | semmle.label | passwdArray | @@ -33,22 +39,28 @@ subpaths #select | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | testCryptoKit.swift:56:47:56:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:56:47:56:47 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | testCryptoKit.swift:57:43:57:43 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:57:43:57:43 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | testCryptoKit.swift:59:43:59:43 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:59:43:59:43 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | testCryptoKit.swift:60:43:60:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:60:43:60:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | testCryptoKit.swift:61:43:61:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:61:43:61:43 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | testCryptoKit.swift:63:44:63:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:63:44:63:44 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | testCryptoKit.swift:64:44:64:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:64:44:64:44 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | testCryptoKit.swift:66:44:66:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:66:44:66:44 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | testCryptoKit.swift:67:44:67:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:67:44:67:44 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | testCryptoKit.swift:90:23:90:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:90:23:90:23 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | testCryptoKit.swift:91:23:91:23 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:91:23:91:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | testCryptoKit.swift:93:23:93:23 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:93:23:93:23 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | testCryptoKit.swift:94:23:94:23 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:94:23:94:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | testCryptoKit.swift:99:23:99:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:99:23:99:23 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | testCryptoKit.swift:100:23:100:23 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:100:23:100:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | testCryptoKit.swift:102:23:102:23 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:102:23:102:23 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | testCryptoKit.swift:103:23:103:23 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:103:23:103:23 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | testCryptoKit.swift:132:32:132:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:132:32:132:32 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | testCryptoKit.swift:133:32:133:32 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:133:32:133:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | testCryptoKit.swift:135:32:135:32 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:135:32:135:32 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | testCryptoKit.swift:136:32:136:32 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:136:32:136:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | testCryptoKit.swift:141:32:141:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:141:32:141:32 | passwd | sensitive data (credential passwd) | | testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | testCryptoKit.swift:142:32:142:32 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:142:32:142:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | testCryptoKit.swift:144:32:144:32 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:144:32:144:32 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | testCryptoKit.swift:145:32:145:32 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:145:32:145:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | testCryptoSwift.swift:113:30:113:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:113:30:113:30 | passwdArray | sensitive data (credential passwdArray) | | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | testCryptoSwift.swift:115:31:115:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:115:31:115:31 | passwdArray | sensitive data (credential passwdArray) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index 4e6f301c84b..55fb9284fa6 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -56,14 +56,14 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa var hash = Crypto.Insecure.MD5.hash(data: passwd) // BAD hash = Crypto.Insecure.MD5.hash(data: cert) // BAD hash = Crypto.Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD [NOT DETECTED] + hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD hash = Crypto.Insecure.SHA1.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD [NOT DETECTED] + hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: credit_card_no) // BAD hash = Crypto.SHA256.hash(data: passwd) // BAD [NOT DETECTED] not a computationally expensive hash @@ -90,7 +90,7 @@ func testMD5UpdateWithData(passwd : String, cert: String, encrypted_passwd : Str hash.update(data: passwd) // BAD hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD [NOT DETECTED] + hash.update(data: account_no) // BAD hash.update(data: credit_card_no) // BAD } @@ -99,7 +99,7 @@ func testSHA1UpdateWithData(passwd : String, cert: String, encrypted_passwd : St hash.update(data: passwd) // BAD hash.update(data: cert) // BAD hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD [NOT DETECTED] + hash.update(data: account_no) // BAD hash.update(data: credit_card_no) // BAD } @@ -132,7 +132,7 @@ func testMD5UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, ce hash.update(bufferPointer: passwd) // BAD hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] + hash.update(bufferPointer: account_no) // BAD hash.update(bufferPointer: credit_card_no) // BAD } @@ -141,7 +141,7 @@ func testSHA1UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, c hash.update(bufferPointer: passwd) // BAD hash.update(bufferPointer: cert) // BAD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD [NOT DETECTED] + hash.update(bufferPointer: account_no) // BAD hash.update(bufferPointer: credit_card_no) // BAD } From e48fc667823f3b92cb7fb171267178c5a0770312 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" <mbg@github.com> Date: Wed, 17 May 2023 16:44:55 +0100 Subject: [PATCH 051/219] Swift: Add `identify-environment` script --- swift/tools/BUILD.bazel | 6 ++++++ swift/tools/identify-environment.cmd | 6 ++++++ swift/tools/identify-environment.sh | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 swift/tools/identify-environment.cmd create mode 100755 swift/tools/identify-environment.sh diff --git a/swift/tools/BUILD.bazel b/swift/tools/BUILD.bazel index e7cff7bd024..8a3496a2700 100644 --- a/swift/tools/BUILD.bazel +++ b/swift/tools/BUILD.bazel @@ -11,9 +11,15 @@ sh_binary( srcs = ["autobuild.sh"], ) +sh_binary( + name = "identify-environment", + srcs = ["identify-environment.sh"], +) + pkg_files( name = "scripts", srcs = [ + ":identify-environment", ":autobuild", ":qltest", ], diff --git a/swift/tools/identify-environment.cmd b/swift/tools/identify-environment.cmd new file mode 100644 index 00000000000..7fd1786f31f --- /dev/null +++ b/swift/tools/identify-environment.cmd @@ -0,0 +1,6 @@ +@echo off +SETLOCAL EnableDelayedExpansion + +echo { "swift": { "os": { "name": "macOS" } } } + +ENDLOCAL diff --git a/swift/tools/identify-environment.sh b/swift/tools/identify-environment.sh new file mode 100755 index 00000000000..d686315c527 --- /dev/null +++ b/swift/tools/identify-environment.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +set -eu + +echo '{ "swift": { "os": { "name": "macOS" } } }' From af803c88867c7629470bfc0162bf9a0962023f06 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" <mbg@github.com> Date: Wed, 17 May 2023 17:58:09 +0100 Subject: [PATCH 052/219] Go: include new scripts in Makefile --- go/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/Makefile b/go/Makefile index 7e119b36f03..8f28079f008 100644 --- a/go/Makefile +++ b/go/Makefile @@ -14,7 +14,7 @@ CODEQL_PLATFORM = osx64 endif endif -CODEQL_TOOLS = $(addprefix codeql-tools/,autobuild.cmd autobuild.sh pre-finalize.cmd pre-finalize.sh index.cmd index.sh tracing-config.lua) +CODEQL_TOOLS = $(addprefix codeql-tools/,autobuild.cmd autobuild.sh pre-finalize.cmd pre-finalize.sh index.cmd index.sh identify-environment.cmd identify-environment.sh tracing-config.lua) EXTRACTOR_PACK_OUT = build/codeql-extractor-go From 631ba6584d810c4fe59baf25e086fdca033a3d43 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" <mbg@github.com> Date: Thu, 18 May 2023 20:21:12 +0100 Subject: [PATCH 053/219] Go: Update `identify-environment` JSON format The spec changed after this was implemented and merged --- go/extractor/cli/go-autobuilder/go-autobuilder.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go index 9fcad68d42a..ed4a238743b 100644 --- a/go/extractor/cli/go-autobuilder/go-autobuilder.go +++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go @@ -44,7 +44,7 @@ Build behavior: to 'false' disables the GOPATH set-up, CODEQL_EXTRACTOR_GO_BUILD_COMMAND (or alternatively LGTM_INDEX_BUILD_COMMAND), can be set to a newline-separated list of commands to run in order to install dependencies, and LGTM_INDEX_IMPORT_PATH can be used to override the package import path, - which is otherwise inferred from the SEMMLE_REPO_URL or GITHUB_REPOSITORY environment variables. + which is otherwise inferred from the SEMMLE_REPO_URL or GITHUB_REPOSITORY environment variables. In resource-constrained environments, the environment variable CODEQL_EXTRACTOR_GO_MAX_GOROUTINES (or its legacy alias SEMMLE_MAX_GOROUTINES) can be used to limit the number of parallel goroutines @@ -931,9 +931,9 @@ func getVersionToInstall(v versionInfo) (msg, version string) { func outputEnvironmentJson(version string) { var content string if version == "" { - content = `{ "include": [] }` + content = `{ "go": {} }` } else { - content = `{ "include": [ { "go": { "version": "` + version + `" } } ] }` + content = `{ "go": { "version": "` + version + `" } }` } _, err := fmt.Fprint(os.Stdout, content) From 2629ec1b1d0d0605862367409b649118e36f5441 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Thu, 25 May 2023 10:57:34 +0200 Subject: [PATCH 054/219] JS: Be more conservative about flagging "search" call arguments as regex --- .../ql/lib/semmle/javascript/Regexp.qll | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/Regexp.qll b/javascript/ql/lib/semmle/javascript/Regexp.qll index 9cef1455746..a20f5343428 100644 --- a/javascript/ql/lib/semmle/javascript/Regexp.qll +++ b/javascript/ql/lib/semmle/javascript/Regexp.qll @@ -958,6 +958,27 @@ private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) { ) } +/** + * Holds if `call` is a call to `search` whose result is used in a way that suggests it returns a number. + */ +pragma[inline] +private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) { + any(Comparison compare) + .hasOperands(value.getALocalUse().asExpr(), any(Expr e | e.analyze().getAType() = TTNumber())) + or + value.flowsToExpr(any(ArithmeticExpr e).getAnOperand()) + or + value.flowsToExpr(any(UnaryExpr e | e.getOperator() = "-").getOperand()) + or + value.flowsToExpr(any(IndexExpr expr).getPropertyNameExpr()) + or + exists(DataFlow::CallNode call | + call.getCalleeName() = + ["substring", "substr", "slice", "splice", "charAt", "charCodeAt", "codePointAt"] and + value.flowsTo(call.getAnArgument()) + ) +} + /** * Holds if `source` may be interpreted as a regular expression. */ @@ -985,9 +1006,9 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) { methodName = "search" and source = mce.getArgument(0) and mce.getNumArgument() = 1 and - // "search" is a common method name, and so we exclude chained accesses - // because `String.prototype.search` returns a number - not exists(PropAccess p | p.getBase() = mce.getEnclosingExpr()) + // "search" is a common method name, and the built-in "search" method is rarely used, + // so to reduce FPs we also require that the return value appears to be used as a number. + isUsedAsNumber(mce) ) or exists(DataFlow::SourceNode schema | schema = JsonSchema::getAPartOfJsonSchema() | From 40daa9c906c972be22aff4e8961c5f07d4dc9c9d Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Fri, 26 May 2023 14:05:36 +0200 Subject: [PATCH 055/219] JS: Update RegExpInjection test and expectations --- .../Security/CWE-730/RegExpInjection.expected | 35 ++++++++----------- .../Security/CWE-730/RegExpInjection.js | 12 +++---- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected index 693ef9e5e95..391be36fbb9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected @@ -31,14 +31,12 @@ nodes | RegExpInjection.js:41:26:41:30 | input | | RegExpInjection.js:42:25:42:29 | input | | RegExpInjection.js:42:25:42:29 | input | -| RegExpInjection.js:45:20:45:24 | input | -| RegExpInjection.js:45:20:45:24 | input | -| RegExpInjection.js:46:23:46:27 | input | -| RegExpInjection.js:46:23:46:27 | input | -| RegExpInjection.js:47:22:47:26 | input | -| RegExpInjection.js:47:22:47:26 | input | -| RegExpInjection.js:50:46:50:50 | input | -| RegExpInjection.js:50:46:50:50 | input | +| RegExpInjection.js:45:24:45:28 | input | +| RegExpInjection.js:45:24:45:28 | input | +| RegExpInjection.js:46:27:46:31 | input | +| RegExpInjection.js:46:27:46:31 | input | +| RegExpInjection.js:47:26:47:30 | input | +| RegExpInjection.js:47:26:47:30 | input | | RegExpInjection.js:54:14:54:16 | key | | RegExpInjection.js:54:14:54:27 | key.split(".") | | RegExpInjection.js:54:14:54:42 | key.spl ... x => x) | @@ -89,14 +87,12 @@ edges | RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:41:26:41:30 | input | | RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:42:25:42:29 | input | | RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:42:25:42:29 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:45:20:45:24 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:45:20:45:24 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:46:23:46:27 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:46:23:46:27 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:47:22:47:26 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:47:22:47:26 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:50:46:50:50 | input | -| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:50:46:50:50 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:45:24:45:28 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:45:24:45:28 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:46:27:46:31 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:46:27:46:31 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:47:26:47:30 | input | +| RegExpInjection.js:5:31:5:56 | input | RegExpInjection.js:47:26:47:30 | input | | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:5:31:5:56 | input | | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:5:31:5:56 | input | | RegExpInjection.js:8:31:8:33 | key | RegExpInjection.js:8:23:8:45 | "\\\\b" + ... (.*)\\n" | @@ -157,10 +153,9 @@ edges | RegExpInjection.js:40:23:40:27 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:40:23:40:27 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | | RegExpInjection.js:41:26:41:30 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:41:26:41:30 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | | RegExpInjection.js:42:25:42:29 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:42:25:42:29 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:45:20:45:24 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:45:20:45:24 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:46:23:46:27 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:46:23:46:27 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:47:22:47:26 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:47:22:47:26 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | -| RegExpInjection.js:50:46:50:50 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:50:46:50:50 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:45:24:45:28 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:45:24:45:28 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:46:27:46:31 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:46:27:46:31 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | +| RegExpInjection.js:47:26:47:30 | input | RegExpInjection.js:5:39:5:56 | req.param("input") | RegExpInjection.js:47:26:47:30 | input | This regular expression is constructed from a $@. | RegExpInjection.js:5:39:5:56 | req.param("input") | user-provided value | | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | | RegExpInjection.js:64:14:64:18 | input | RegExpInjection.js:60:39:60:56 | req.param("input") | RegExpInjection.js:64:14:64:18 | input | This regular expression is constructed from a $@. | RegExpInjection.js:60:39:60:56 | req.param("input") | user-provided value | | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | RegExpInjection.js:82:15:82:32 | req.param("input") | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | This regular expression is constructed from a $@. | RegExpInjection.js:82:15:82:32 | req.param("input") | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js index 1f8113f7d75..6cf3938486e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js @@ -42,12 +42,12 @@ app.get('/findKey', function(req, res) { if (maybeString.match(input)) {} // NOT OK if (notString.match(input)) {} // OK - defString.search(input); // NOT OK - likelyString.search(input); // NOT OK - maybeString.search(input); // NOT OK - notString.search(input); // OK + if (defString.search(input) > -1) {} // NOT OK + if (likelyString.search(input) > -1) {} // NOT OK + if (maybeString.search(input) > -1) {} // NOT OK + if (notString.search(input) > -1) {} // OK - URI(`${protocol}://${host}${path}`).search(input); // OK, but still flagged [INCONSISTENCY] + URI(`${protocol}://${host}${path}`).search(input); // OK URI(`${protocol}://${host}${path}`).search(input).href(); // OK unknown.search(input).unknown; // OK @@ -62,7 +62,7 @@ app.get('/findKey', function(req, res) { Search.search(input); // OK! new RegExp(input); // NOT OK - + var sanitized = input.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); new RegExp(sanitized); // OK }); From 9df9ca2916d90fdc4cc86a50581e35c98c2309ac Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Fri, 26 May 2023 14:07:34 +0200 Subject: [PATCH 056/219] JS: Update test and expectations for MissingRegExpAnchor --- .../CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected | 2 +- .../CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected b/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected index 0554d826383..a7933f2926e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected @@ -49,7 +49,7 @@ | tst-UnanchoredUrlRegExp.js:8:47:8:90 | "(https ... e.com)" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. | | tst-UnanchoredUrlRegExp.js:10:2:10:22 | /https? ... od.com/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | | tst-UnanchoredUrlRegExp.js:11:13:11:31 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | -| tst-UnanchoredUrlRegExp.js:13:44:13:62 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | +| tst-UnanchoredUrlRegExp.js:13:48:13:66 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | | tst-UnanchoredUrlRegExp.js:15:13:15:31 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | | tst-UnanchoredUrlRegExp.js:19:47:19:65 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | | tst-UnanchoredUrlRegExp.js:20:47:20:70 | "https? ... m:8080" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | diff --git a/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js b/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js index 5db3aa740fb..24815ebe59e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js @@ -10,7 +10,7 @@ /https?:\/\/good.com/.exec("http://evil.com/?http://good.com"); // NOT OK new RegExp("https?://good.com").exec("http://evil.com/?http://good.com"); // NOT OK - "http://evil.com/?http://good.com".search("https?://good.com"); // NOT OK + if ("http://evil.com/?http://good.com".search("https?://good.com") > -1) {} // NOT OK new RegExp("https?://good.com").test("http://evil.com/?http://good.com"); // NOT OK From c637b6f59a623a32720865da7fae2d4bcc67b2a5 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Fri, 26 May 2023 14:10:26 +0200 Subject: [PATCH 057/219] JS: Update test for RegExpAlwaysMatches --- .../test/query-tests/RegExp/RegExpAlwaysMatches/tst.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/test/query-tests/RegExp/RegExpAlwaysMatches/tst.js b/javascript/ql/test/query-tests/RegExp/RegExpAlwaysMatches/tst.js index a266e2d86f6..b4c54be9b8a 100644 --- a/javascript/ql/test/query-tests/RegExp/RegExpAlwaysMatches/tst.js +++ b/javascript/ql/test/query-tests/RegExp/RegExpAlwaysMatches/tst.js @@ -55,23 +55,23 @@ function emptyAlt3(x) { } function search(x) { - return x.search(/[a-z]*/); // NOT OK + return x.search(/[a-z]*/) > -1; // NOT OK } function search2(x) { - return x.search(/[a-z]/); // OK + return x.search(/[a-z]/) > -1; // OK } function lookahead(x) { - return x.search(/(?!x)/); // OK + return x.search(/(?!x)/) > -1; // OK } function searchPrefix(x) { - return x.search(/^(foo)?/); // NOT OK - `foo?` does not affect the returned index + return x.search(/^(foo)?/) > -1; // NOT OK - `foo?` does not affect the returned index } function searchSuffix(x) { - return x.search(/(foo)?$/); // OK - `foo?` affects the returned index + return x.search(/(foo)?$/) > -1; // OK - `foo?` affects the returned index } function wordBoundary(x) { From 486a5ac96f1682c352ee033ab39312b9ebf721eb Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Thu, 23 Feb 2023 21:23:05 +0100 Subject: [PATCH 058/219] v1 --- .../YAMLUnsafeYamlDeserialization.qhelp | 20 +++++ .../CWE-502/YAMLUnsafeYamlDeserialization.ql | 87 +++++++++++++++++++ .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 20 +++++ .../YAMLUnsafeYamlDeserialization.expected | 70 +++++++++++++++ .../YAMLUnsafeYamlDeserialization.qlref | 1 + .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 20 +++++ 6 files changed, 218 insertions(+) create mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp create mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql create mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb create mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected create mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref create mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp new file mode 100644 index 00000000000..821747e0b52 --- /dev/null +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp @@ -0,0 +1,20 @@ +<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> +<qhelp> + <overview> + <p> + Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. + Unsafe deserializing the malicious serialized yaml document through the Psych (YAML) library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. + </p> + </overview> + <recommendation> + <p> + After Psych(YAML) 4.0.0, the load method is same as safe_load method. + This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. + Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. + </p> + </recommendation> + <example> + <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> + <sample src="YAMLUnsafeYamlDeserialization.rb" /> + </example> +</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql new file mode 100644 index 00000000000..668dc822b15 --- /dev/null +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql @@ -0,0 +1,87 @@ +/** + * @name Deserialization of user-controlled data by YAML + * @description Deserializing user-controlled data may allow attackers to + * execute arbitrary code. + * @kind path-problem + * @problem.severity warning + * @security-severity 9.8 + * @precision high + * @id rb/YAML-unsafe-deserialization + * @tags security + * experimental + * external/cwe/cwe-502 + */ + +import codeql.ruby.AST +import codeql.ruby.ApiGraphs +import codeql.ruby.DataFlow +import codeql.ruby.dataflow.RemoteFlowSources +import codeql.ruby.TaintTracking +import DataFlow::PathGraph + +abstract class YAMLSink extends DataFlow::Node { } + +class YamlunsafeLoadArgument extends YAMLSink { + YamlunsafeLoadArgument() { + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) + .getArgument(0) + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load", "load_stream"]) + .getKeywordArgument("yaml") + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall("unsafe_load_file") + .getKeywordArgument("filename") + } +} + +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "UnsafeDeserialization" } + + override predicate isSource(DataFlow::Node source) { + // for detecting The CVE we should uncomment following line instead of current RemoteFlowSource + source instanceof DataFlow::LocalSourceNode + // source instanceof RemoteFlowSource + } + + override predicate isSink(DataFlow::Node sink) { + // for detecting The CVE we should uncomment following line + // sink.getLocation().getFile().toString().matches("%yaml_column%") and + sink instanceof YAMLSink or + sink = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["parse", "parse_stream", "parse_file"]) + .getAMethodCall("to_ruby") + } + + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = + API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + or + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("filename") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + } +} + +from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This file extraction depends on a $@.", source.getNode(), + "potentially untrusted source" diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..58ea8024350 --- /dev/null +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb @@ -0,0 +1,20 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # safe + Psych.load(params[:yaml_string]) + Psych.load_file(params[:yaml_file]) + Psych.parse_stream(params[:yaml_string]) + Psych.parse(params[:yaml_string]) + Psych.parse_file(params[:yaml_file]) + # unsafe + Psych.unsafe_load(params[:yaml_string]) + Psych.unsafe_load_file(params[:yaml_file]) + Psych.load_stream(params[:yaml_string]) + Psych.parse_stream(params[:yaml_string]).to_ruby + Psych.parse(params[:yaml_string]).to_ruby + Psych.parse_file(params[:yaml_file]).to_ruby + + end +end + diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected new file mode 100644 index 00000000000..e274fb6f005 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected @@ -0,0 +1,70 @@ +edges +| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | +| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | +| file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | +| file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | +| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | +| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | +| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | +| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | +nodes +| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | semmle.label | ...[...] : | +| file://:0:0:0:0 | parameter self of [] : | semmle.label | parameter self of [] : | +| file://:0:0:0:0 | parameter self of [](:yaml_file) : | semmle.label | parameter self of [](:yaml_file) : | +| file://:0:0:0:0 | parameter self of [](:yaml_string) : | semmle.label | parameter self of [](:yaml_string) : | +subpaths +#select +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_file) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_file) | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref new file mode 100644 index 00000000000..7e9e87117f9 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref @@ -0,0 +1 @@ +experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..58ea8024350 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb @@ -0,0 +1,20 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # safe + Psych.load(params[:yaml_string]) + Psych.load_file(params[:yaml_file]) + Psych.parse_stream(params[:yaml_string]) + Psych.parse(params[:yaml_string]) + Psych.parse_file(params[:yaml_file]) + # unsafe + Psych.unsafe_load(params[:yaml_string]) + Psych.unsafe_load_file(params[:yaml_file]) + Psych.load_stream(params[:yaml_string]) + Psych.parse_stream(params[:yaml_string]).to_ruby + Psych.parse(params[:yaml_string]).to_ruby + Psych.parse_file(params[:yaml_file]).to_ruby + + end +end + From e4b8a0e06dcfd027ea28bf73f0ab2c564d8c47e7 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Thu, 23 Feb 2023 21:45:33 +0100 Subject: [PATCH 059/219] v1.1 --- .../experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql index 668dc822b15..e8b3fb761f4 100644 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql @@ -18,6 +18,7 @@ import codeql.ruby.DataFlow import codeql.ruby.dataflow.RemoteFlowSources import codeql.ruby.TaintTracking import DataFlow::PathGraph +import codeql.ruby.security.UnsafeDeserializationCustomizations abstract class YAMLSink extends DataFlow::Node { } @@ -45,8 +46,8 @@ class Configuration extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { // for detecting The CVE we should uncomment following line instead of current RemoteFlowSource - source instanceof DataFlow::LocalSourceNode - // source instanceof RemoteFlowSource + // source instanceof DataFlow::LocalSourceNode + source instanceof UnsafeDeserialization::Source } override predicate isSink(DataFlow::Node sink) { From d96153a05ef945a0768888096468662e7cb8656d Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Fri, 24 Feb 2023 09:28:16 +0100 Subject: [PATCH 060/219] v1.2 change to PascalCase --- .../experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql index e8b3fb761f4..7612c556d90 100644 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql @@ -20,10 +20,10 @@ import codeql.ruby.TaintTracking import DataFlow::PathGraph import codeql.ruby.security.UnsafeDeserializationCustomizations -abstract class YAMLSink extends DataFlow::Node { } +abstract class YamlSink extends DataFlow::Node { } -class YamlunsafeLoadArgument extends YAMLSink { - YamlunsafeLoadArgument() { +class YamlUnsafeLoadArgument extends YamlSink { + YamlUnsafeLoadArgument() { this = API::getTopLevelMember(["YAML", "Psych"]) .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) @@ -53,7 +53,7 @@ class Configuration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { // for detecting The CVE we should uncomment following line // sink.getLocation().getFile().toString().matches("%yaml_column%") and - sink instanceof YAMLSink or + sink instanceof YamlSink or sink = API::getTopLevelMember(["YAML", "Psych"]) .getAMethodCall(["parse", "parse_stream", "parse_file"]) From 0e343e5a12b9dbb83dd0db30d79b6c42894a6ba9 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Fri, 24 Feb 2023 11:45:06 +0100 Subject: [PATCH 061/219] v1.3 --- .../CWE-502/YAMLUnsafeYamlDeserialization.ql | 20 +++--- .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 4 +- .../YAMLUnsafeYamlDeserialization.expected | 72 +++++-------------- .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 4 +- 4 files changed, 34 insertions(+), 66 deletions(-) diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql index 7612c556d90..a3f42a9c84e 100644 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql @@ -12,10 +12,8 @@ * external/cwe/cwe-502 */ -import codeql.ruby.AST import codeql.ruby.ApiGraphs import codeql.ruby.DataFlow -import codeql.ruby.dataflow.RemoteFlowSources import codeql.ruby.TaintTracking import DataFlow::PathGraph import codeql.ruby.security.UnsafeDeserializationCustomizations @@ -38,26 +36,28 @@ class YamlUnsafeLoadArgument extends YamlSink { API::getTopLevelMember(["YAML", "Psych"]) .getAMethodCall("unsafe_load_file") .getKeywordArgument("filename") + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["parse", "parse_stream", "parse_file"]) + .getAMethodCall("to_ruby") } } class Configuration extends TaintTracking::Configuration { - Configuration() { this = "UnsafeDeserialization" } + Configuration() { this = "UnsafeYAMLDeserialization" } override predicate isSource(DataFlow::Node source) { - // for detecting The CVE we should uncomment following line instead of current RemoteFlowSource + // to detect CVE-2022-32224, we should uncomment following line instead of current UnsafeDeserialization::Source // source instanceof DataFlow::LocalSourceNode source instanceof UnsafeDeserialization::Source } override predicate isSink(DataFlow::Node sink) { - // for detecting The CVE we should uncomment following line + // after changing the isSource for detecting CVE-2022-32224 + // uncomment the following line only see the CVE sink not other files similar sinks // sink.getLocation().getFile().toString().matches("%yaml_column%") and - sink instanceof YamlSink or - sink = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["parse", "parse_stream", "parse_file"]) - .getAMethodCall("to_ruby") + sink instanceof YamlSink } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb index 58ea8024350..6e836a0a049 100644 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb +++ b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb @@ -11,10 +11,12 @@ class UsersController < ActionController::Base Psych.unsafe_load(params[:yaml_string]) Psych.unsafe_load_file(params[:yaml_file]) Psych.load_stream(params[:yaml_string]) - Psych.parse_stream(params[:yaml_string]).to_ruby + parse_output = Psych.parse_stream(params[:yaml_string]) + parse_output.to_ruby Psych.parse(params[:yaml_string]).to_ruby Psych.parse_file(params[:yaml_file]).to_ruby end end + diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected index e274fb6f005..c01afdfbe69 100644 --- a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected +++ b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected @@ -2,24 +2,12 @@ edges | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | -| file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | -| file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | -| file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | -| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | -| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | -| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | -| file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | nodes | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | @@ -27,44 +15,20 @@ nodes | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | semmle.label | ...[...] : | -| file://:0:0:0:0 | parameter self of [] : | semmle.label | parameter self of [] : | -| file://:0:0:0:0 | parameter self of [](:yaml_file) : | semmle.label | parameter self of [](:yaml_file) : | -| file://:0:0:0:0 | parameter self of [](:yaml_string) : | semmle.label | parameter self of [](:yaml_string) : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | subpaths #select | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_file) | potentially untrusted source | | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:24:14:29 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:24:14:43 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:14:5:14:52 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:17:15:22 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:15:17:15:36 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_string) : | YAMLUnsafeYamlDeserialization.rb:15:5:15:45 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_string) | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:22:16:27 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:22:16:39 | ...[...] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | file://:0:0:0:0 | parameter self of [] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [] | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | file://:0:0:0:0 | parameter self of [](:yaml_file) : | YAMLUnsafeYamlDeserialization.rb:16:5:16:48 | call to to_ruby | This file extraction depends on a $@. | file://:0:0:0:0 | parameter self of [](:yaml_file) | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb index 58ea8024350..6e836a0a049 100644 --- a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb +++ b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb @@ -11,10 +11,12 @@ class UsersController < ActionController::Base Psych.unsafe_load(params[:yaml_string]) Psych.unsafe_load_file(params[:yaml_file]) Psych.load_stream(params[:yaml_string]) - Psych.parse_stream(params[:yaml_string]).to_ruby + parse_output = Psych.parse_stream(params[:yaml_string]) + parse_output.to_ruby Psych.parse(params[:yaml_string]).to_ruby Psych.parse_file(params[:yaml_file]).to_ruby end end + From 0521ffe175243a5bd9071c2f9bb231ced31d3ece Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Fri, 24 Feb 2023 13:13:06 +0100 Subject: [PATCH 062/219] v1.4 correct dirs uppercase issue --- .../YAMLUnsafeYamlDeserialization.qhelp | 20 +++++ .../cwe-502/YAMLUnsafeYamlDeserialization.ql | 88 +++++++++++++++++++ .../cwe-502/YAMLUnsafeYamlDeserialization.rb | 22 +++++ .../YAMLUnsafeYamlDeserialization.expected | 34 +++++++ .../YAMLUnsafeYamlDeserialization.qlref | 1 + .../cwe-502/YAMLUnsafeYamlDeserialization.rb | 22 +++++ 6 files changed, 187 insertions(+) create mode 100644 ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp create mode 100644 ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql create mode 100644 ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp new file mode 100644 index 00000000000..821747e0b52 --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp @@ -0,0 +1,20 @@ +<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> +<qhelp> + <overview> + <p> + Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. + Unsafe deserializing the malicious serialized yaml document through the Psych (YAML) library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. + </p> + </overview> + <recommendation> + <p> + After Psych(YAML) 4.0.0, the load method is same as safe_load method. + This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. + Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. + </p> + </recommendation> + <example> + <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> + <sample src="YAMLUnsafeYamlDeserialization.rb" /> + </example> +</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql new file mode 100644 index 00000000000..a3f42a9c84e --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql @@ -0,0 +1,88 @@ +/** + * @name Deserialization of user-controlled data by YAML + * @description Deserializing user-controlled data may allow attackers to + * execute arbitrary code. + * @kind path-problem + * @problem.severity warning + * @security-severity 9.8 + * @precision high + * @id rb/YAML-unsafe-deserialization + * @tags security + * experimental + * external/cwe/cwe-502 + */ + +import codeql.ruby.ApiGraphs +import codeql.ruby.DataFlow +import codeql.ruby.TaintTracking +import DataFlow::PathGraph +import codeql.ruby.security.UnsafeDeserializationCustomizations + +abstract class YamlSink extends DataFlow::Node { } + +class YamlUnsafeLoadArgument extends YamlSink { + YamlUnsafeLoadArgument() { + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) + .getArgument(0) + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load", "load_stream"]) + .getKeywordArgument("yaml") + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall("unsafe_load_file") + .getKeywordArgument("filename") + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["parse", "parse_stream", "parse_file"]) + .getAMethodCall("to_ruby") + } +} + +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "UnsafeYAMLDeserialization" } + + override predicate isSource(DataFlow::Node source) { + // to detect CVE-2022-32224, we should uncomment following line instead of current UnsafeDeserialization::Source + // source instanceof DataFlow::LocalSourceNode + source instanceof UnsafeDeserialization::Source + } + + override predicate isSink(DataFlow::Node sink) { + // after changing the isSource for detecting CVE-2022-32224 + // uncomment the following line only see the CVE sink not other files similar sinks + // sink.getLocation().getFile().toString().matches("%yaml_column%") and + sink instanceof YamlSink + } + + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = + API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + or + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("filename") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + } +} + +from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This file extraction depends on a $@.", source.getNode(), + "potentially untrusted source" diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..6e836a0a049 --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb @@ -0,0 +1,22 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # safe + Psych.load(params[:yaml_string]) + Psych.load_file(params[:yaml_file]) + Psych.parse_stream(params[:yaml_string]) + Psych.parse(params[:yaml_string]) + Psych.parse_file(params[:yaml_file]) + # unsafe + Psych.unsafe_load(params[:yaml_string]) + Psych.unsafe_load_file(params[:yaml_file]) + Psych.load_stream(params[:yaml_string]) + parse_output = Psych.parse_stream(params[:yaml_string]) + parse_output.to_ruby + Psych.parse(params[:yaml_string]).to_ruby + Psych.parse_file(params[:yaml_file]).to_ruby + + end +end + + diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected new file mode 100644 index 00000000000..c01afdfbe69 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected @@ -0,0 +1,34 @@ +edges +| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | +nodes +| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | +| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | +subpaths +#select +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref new file mode 100644 index 00000000000..7e9e87117f9 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref @@ -0,0 +1 @@ +experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..6e836a0a049 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb @@ -0,0 +1,22 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # safe + Psych.load(params[:yaml_string]) + Psych.load_file(params[:yaml_file]) + Psych.parse_stream(params[:yaml_string]) + Psych.parse(params[:yaml_string]) + Psych.parse_file(params[:yaml_file]) + # unsafe + Psych.unsafe_load(params[:yaml_string]) + Psych.unsafe_load_file(params[:yaml_file]) + Psych.load_stream(params[:yaml_string]) + parse_output = Psych.parse_stream(params[:yaml_string]) + parse_output.to_ruby + Psych.parse(params[:yaml_string]).to_ruby + Psych.parse_file(params[:yaml_file]).to_ruby + + end +end + + From 4360a56b45483b658e583f5a8684ce96b80d5b73 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Sat, 25 Feb 2023 20:49:48 +0100 Subject: [PATCH 063/219] v2 add plist.parse_xml as a dangerous sink and enhancements on documents --- .../YAMLUnsafeYamlDeserialization.qhelp | 20 ----- .../CWE-502/YAMLUnsafeYamlDeserialization.ql | 88 ------------------- .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 22 ----- .../PlistUnsafeYamlDeserialization.qhelp | 25 ++++++ .../cwe-502/PlistUnsafeYamlDeserialization.ql | 68 ++++++++++++++ .../cwe-502/PlistUnsafeYamlDeserialization.rb | 13 +++ .../YAMLUnsafeYamlDeserialization.qhelp | 6 ++ .../cwe-502/YAMLUnsafeYamlDeserialization.ql | 14 +-- .../YAMLUnsafeYamlDeserialization.expected | 34 ------- .../YAMLUnsafeYamlDeserialization.qlref | 1 - .../CWE-502/YAMLUnsafeYamlDeserialization.rb | 22 ----- .../PlistUnsafeYamlDeserialization.expected | 12 +++ .../PlistUnsafeYamlDeserialization.qlref | 1 + .../cwe-502/PlistUnsafeYamlDeserialization.rb | 13 +++ .../YAMLUnsafeYamlDeserialization.expected | 12 +-- .../YAMLUnsafeYamlDeserialization.qlref | 2 +- 16 files changed, 152 insertions(+), 201 deletions(-) delete mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp delete mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql delete mode 100644 ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb create mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp create mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql create mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb delete mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected delete mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref delete mode 100644 ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp deleted file mode 100644 index 821747e0b52..00000000000 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.qhelp +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> -<qhelp> - <overview> - <p> - Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. - Unsafe deserializing the malicious serialized yaml document through the Psych (YAML) library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. - </p> - </overview> - <recommendation> - <p> - After Psych(YAML) 4.0.0, the load method is same as safe_load method. - This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. - Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. - </p> - </recommendation> - <example> - <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> - <sample src="YAMLUnsafeYamlDeserialization.rb" /> - </example> -</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql deleted file mode 100644 index a3f42a9c84e..00000000000 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @name Deserialization of user-controlled data by YAML - * @description Deserializing user-controlled data may allow attackers to - * execute arbitrary code. - * @kind path-problem - * @problem.severity warning - * @security-severity 9.8 - * @precision high - * @id rb/YAML-unsafe-deserialization - * @tags security - * experimental - * external/cwe/cwe-502 - */ - -import codeql.ruby.ApiGraphs -import codeql.ruby.DataFlow -import codeql.ruby.TaintTracking -import DataFlow::PathGraph -import codeql.ruby.security.UnsafeDeserializationCustomizations - -abstract class YamlSink extends DataFlow::Node { } - -class YamlUnsafeLoadArgument extends YamlSink { - YamlUnsafeLoadArgument() { - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) - .getArgument(0) - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load", "load_stream"]) - .getKeywordArgument("yaml") - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall("unsafe_load_file") - .getKeywordArgument("filename") - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["parse", "parse_stream", "parse_file"]) - .getAMethodCall("to_ruby") - } -} - -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "UnsafeYAMLDeserialization" } - - override predicate isSource(DataFlow::Node source) { - // to detect CVE-2022-32224, we should uncomment following line instead of current UnsafeDeserialization::Source - // source instanceof DataFlow::LocalSourceNode - source instanceof UnsafeDeserialization::Source - } - - override predicate isSink(DataFlow::Node sink) { - // after changing the isSource for detecting CVE-2022-32224 - // uncomment the following line only see the CVE sink not other files similar sinks - // sink.getLocation().getFile().toString().matches("%yaml_column%") and - sink instanceof YamlSink - } - - override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = - API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - or - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("filename") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - } -} - -from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink -where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "This file extraction depends on a $@.", source.getNode(), - "potentially untrusted source" diff --git a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb deleted file mode 100644 index 6e836a0a049..00000000000 --- a/ruby/ql/src/experimental/CWE-502/YAMLUnsafeYamlDeserialization.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'yaml' -class UsersController < ActionController::Base - def example - # safe - Psych.load(params[:yaml_string]) - Psych.load_file(params[:yaml_file]) - Psych.parse_stream(params[:yaml_string]) - Psych.parse(params[:yaml_string]) - Psych.parse_file(params[:yaml_file]) - # unsafe - Psych.unsafe_load(params[:yaml_string]) - Psych.unsafe_load_file(params[:yaml_file]) - Psych.load_stream(params[:yaml_string]) - parse_output = Psych.parse_stream(params[:yaml_string]) - parse_output.to_ruby - Psych.parse(params[:yaml_string]).to_ruby - Psych.parse_file(params[:yaml_file]).to_ruby - - end -end - - diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp new file mode 100644 index 00000000000..80ec6c51dc0 --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp @@ -0,0 +1,25 @@ +<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> +<qhelp> + <overview> + <p> + Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. + Unsafe deserializing the malicious serialized xml document through the Plist library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. + </p> + </overview> + <recommendation> + <p> + This vulnerability can be prevented by using <code>Plist.parse_xml</code>. + </p> + </recommendation> + <example> + <p>In the example below, you can see safe and unsafe call of this dangerous method that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. + </p> + <sample src="PlistUnsafeYamlDeserialization.rb" /> + </example> + <references> + <li> + Security considerations from library documentation + <a href="https://github.com/patsplat/plist#label-Security+considerations">patsplat/plist</a>. + </li> + </references> +</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql new file mode 100644 index 00000000000..02d554cffb6 --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql @@ -0,0 +1,68 @@ +/** + * @name Unsafe Deserialization of user-controlled data by Plist + * @description Deserializing user-controlled data may allow attackers to + * execute arbitrary code. + * @kind path-problem + * @problem.severity warning + * @security-severity 9.8 + * @precision high + * @id rb/Plist-unsafe-deserialization + * @tags security + * experimental + * external/cwe/cwe-502 + */ + +import codeql.ruby.ApiGraphs +import codeql.ruby.DataFlow +import codeql.ruby.TaintTracking +import codeql.ruby.CFG +import DataFlow::PathGraph +import codeql.ruby.security.UnsafeDeserializationCustomizations + +abstract class PlistUnsafeSinks extends DataFlow::Node { } + +/** + * check whether an input argument has desired "key: value" input or not. + * borrowed from UnsafeDeserialization module with some changes + */ +predicate checkkeyBalue(CfgNodes::ExprNodes::PairCfgNode p, string key, string value) { + p.getKey().getConstantValue().isStringlikeValue(key) and + DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().toString() = value +} + +/** + * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is + * the default), considered a sink for unsafe deserialization. + * borrowed from UnsafeDeserialization module with some changes + */ +class UnsafePlistParsexmlArgument extends PlistUnsafeSinks { + UnsafePlistParsexmlArgument() { + exists(DataFlow::CallNode plistParsexml | + plistParsexml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") + | + this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and + // Exclude calls that explicitly pass a safe mode option. + checkkeyBalue(plistParsexml.getArgument(1).asExpr(), "marshal", "true") + or + this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and + plistParsexml.getNumberOfArguments() = 1 + ) + } +} + +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "PlistUnsafeDeserialization" } + + override predicate isSource(DataFlow::Node source) { + // to detect CVE-2021-33575, we should uncomment following line instead of current UnsafeDeserialization::Source + // source instanceof DataFlow::LocalSourceNode + source instanceof UnsafeDeserialization::Source + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof PlistUnsafeSinks } +} + +from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Unsafe deserialization depends on a $@.", source.getNode(), + "potentially untrusted source" diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..63f64b5cd22 --- /dev/null +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb @@ -0,0 +1,13 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # not safe + result = Plist.parse_xml(params[:yaml_string]) + result = Plist.parse_xml(params[:yaml_string], marshal: true) + + # safe + result = Plist.parse_xml(params[:yaml_string], marshal: false) + end +end + + diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp index 821747e0b52..c3a74527483 100644 --- a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp @@ -17,4 +17,10 @@ <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> <sample src="YAMLUnsafeYamlDeserialization.rb" /> </example> + <references> + <li> + You can read that how unsafe yaml load methods can lead to code executions. + <a href="https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html">Universal Deserialisation Gadget for Ruby 2.x-3.x </a>. + </li> + </references> </qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql index a3f42a9c84e..5cb720d19da 100644 --- a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql @@ -1,5 +1,5 @@ /** - * @name Deserialization of user-controlled data by YAML + * @name Unsafe Deserialization of user-controlled data by YAML * @description Deserializing user-controlled data may allow attackers to * execute arbitrary code. * @kind path-problem @@ -18,10 +18,10 @@ import codeql.ruby.TaintTracking import DataFlow::PathGraph import codeql.ruby.security.UnsafeDeserializationCustomizations -abstract class YamlSink extends DataFlow::Node { } +abstract class YamlUnsafeSinks extends DataFlow::Node { } -class YamlUnsafeLoadArgument extends YamlSink { - YamlUnsafeLoadArgument() { +class YamlUnsafeArgument extends YamlUnsafeSinks { + YamlUnsafeArgument() { this = API::getTopLevelMember(["YAML", "Psych"]) .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) @@ -45,7 +45,7 @@ class YamlUnsafeLoadArgument extends YamlSink { } class Configuration extends TaintTracking::Configuration { - Configuration() { this = "UnsafeYAMLDeserialization" } + Configuration() { this = "YamlUnsafeDeserialization" } override predicate isSource(DataFlow::Node source) { // to detect CVE-2022-32224, we should uncomment following line instead of current UnsafeDeserialization::Source @@ -57,7 +57,7 @@ class Configuration extends TaintTracking::Configuration { // after changing the isSource for detecting CVE-2022-32224 // uncomment the following line only see the CVE sink not other files similar sinks // sink.getLocation().getFile().toString().matches("%yaml_column%") and - sink instanceof YamlSink + sink instanceof YamlUnsafeSinks } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { @@ -84,5 +84,5 @@ class Configuration extends TaintTracking::Configuration { from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "This file extraction depends on a $@.", source.getNode(), +select sink.getNode(), source, sink, "Unsafe deserialization depends on a $@.", source.getNode(), "potentially untrusted source" diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected deleted file mode 100644 index c01afdfbe69..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.expected +++ /dev/null @@ -1,34 +0,0 @@ -edges -| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | -nodes -| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | -subpaths -#select -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref deleted file mode 100644 index 7e9e87117f9..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb deleted file mode 100644 index 6e836a0a049..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/CWE-502/YAMLUnsafeYamlDeserialization.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'yaml' -class UsersController < ActionController::Base - def example - # safe - Psych.load(params[:yaml_string]) - Psych.load_file(params[:yaml_file]) - Psych.parse_stream(params[:yaml_string]) - Psych.parse(params[:yaml_string]) - Psych.parse_file(params[:yaml_file]) - # unsafe - Psych.unsafe_load(params[:yaml_string]) - Psych.unsafe_load_file(params[:yaml_file]) - Psych.load_stream(params[:yaml_string]) - parse_output = Psych.parse_stream(params[:yaml_string]) - parse_output.to_ruby - Psych.parse(params[:yaml_string]).to_ruby - Psych.parse_file(params[:yaml_file]).to_ruby - - end -end - - diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected new file mode 100644 index 00000000000..f5da2a260c4 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected @@ -0,0 +1,12 @@ +edges +| PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | +| PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | +nodes +| PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | semmle.label | call to params : | +| PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] | +| PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | semmle.label | call to params : | +| PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] | +subpaths +#select +| PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params | potentially untrusted source | +| PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref new file mode 100644 index 00000000000..74d9d37315a --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref @@ -0,0 +1 @@ +experimental/cwe-502/PlistUnsafeYamlDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb new file mode 100644 index 00000000000..63f64b5cd22 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb @@ -0,0 +1,13 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # not safe + result = Plist.parse_xml(params[:yaml_string]) + result = Plist.parse_xml(params[:yaml_string], marshal: true) + + # safe + result = Plist.parse_xml(params[:yaml_string], marshal: false) + end +end + + diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected index c01afdfbe69..489602044a7 100644 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected @@ -26,9 +26,9 @@ nodes | YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | subpaths #select -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | This file extraction depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | +| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref index 7e9e87117f9..87fe2520217 100644 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref @@ -1 +1 @@ -experimental/CWE-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file +experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file From b9296d3df88084252074f69bae97e986095b3b83 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Sat, 25 Feb 2023 23:08:31 +0100 Subject: [PATCH 064/219] v2.1 fix file names --- ...qhelp => PlistUnsafeDeserialization.qhelp} | 0 ...ation.ql => PlistUnsafeDeserialization.ql} | 0 ...ation.rb => PlistUnsafeDeserialization.rb} | 0 ....qhelp => YAMLUnsafeDeserialization.qhelp} | 0 ...zation.ql => YAMLUnsafeDeserialization.ql} | 0 ...zation.rb => YAMLUnsafeDeserialization.rb} | 0 .../PlistUnsafeDeserialization.expected | 12 +++++++ .../cwe-502/PlistUnsafeDeserialization.qlref | 1 + ...ation.rb => PlistUnsafeDeserialization.rb} | 0 .../PlistUnsafeYamlDeserialization.expected | 12 ------- .../PlistUnsafeYamlDeserialization.qlref | 1 - .../YAMLUnsafeDeserialization.expected | 34 +++++++++++++++++++ .../cwe-502/YAMLUnsafeDeserialization.qlref | 1 + ...zation.rb => YAMLUnsafeDeserialization.rb} | 0 .../YAMLUnsafeYamlDeserialization.expected | 34 ------------------- .../YAMLUnsafeYamlDeserialization.qlref | 1 - 16 files changed, 48 insertions(+), 48 deletions(-) rename ruby/ql/src/experimental/cwe-502/{PlistUnsafeYamlDeserialization.qhelp => PlistUnsafeDeserialization.qhelp} (100%) rename ruby/ql/src/experimental/cwe-502/{PlistUnsafeYamlDeserialization.ql => PlistUnsafeDeserialization.ql} (100%) rename ruby/ql/src/experimental/cwe-502/{PlistUnsafeYamlDeserialization.rb => PlistUnsafeDeserialization.rb} (100%) rename ruby/ql/src/experimental/cwe-502/{YAMLUnsafeYamlDeserialization.qhelp => YAMLUnsafeDeserialization.qhelp} (100%) rename ruby/ql/src/experimental/cwe-502/{YAMLUnsafeYamlDeserialization.ql => YAMLUnsafeDeserialization.ql} (100%) rename ruby/ql/src/experimental/cwe-502/{YAMLUnsafeYamlDeserialization.rb => YAMLUnsafeDeserialization.rb} (100%) create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref rename ruby/ql/test/query-tests/experimental/Security/cwe-502/{PlistUnsafeYamlDeserialization.rb => PlistUnsafeDeserialization.rb} (100%) delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected create mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref rename ruby/ql/test/query-tests/experimental/Security/cwe-502/{YAMLUnsafeYamlDeserialization.rb => YAMLUnsafeDeserialization.rb} (100%) delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp similarity index 100% rename from ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.qhelp rename to ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql similarity index 100% rename from ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.ql rename to ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/src/experimental/cwe-502/PlistUnsafeYamlDeserialization.rb rename to ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp similarity index 100% rename from ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.qhelp rename to ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql similarity index 100% rename from ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql rename to ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/src/experimental/cwe-502/YAMLUnsafeYamlDeserialization.rb rename to ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.rb diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected new file mode 100644 index 00000000000..967ef978a3b --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected @@ -0,0 +1,12 @@ +edges +| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | +| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | +nodes +| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | semmle.label | call to params : | +| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] | +| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | semmle.label | call to params : | +| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] | +subpaths +#select +| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | potentially untrusted source | +| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref new file mode 100644 index 00000000000..f7bfbada7b5 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref @@ -0,0 +1 @@ +experimental/cwe-502/PlistUnsafeDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.rb rename to ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.rb diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected deleted file mode 100644 index f5da2a260c4..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.expected +++ /dev/null @@ -1,12 +0,0 @@ -edges -| PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | -| PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | -nodes -| PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | semmle.label | call to params : | -| PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] | -| PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | semmle.label | call to params : | -| PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] | -subpaths -#select -| PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeYamlDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeYamlDeserialization.rb:5:30:5:35 | call to params | potentially untrusted source | -| PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeYamlDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeYamlDeserialization.rb:6:30:6:35 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref deleted file mode 100644 index 74d9d37315a..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeYamlDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/cwe-502/PlistUnsafeYamlDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected new file mode 100644 index 00000000000..9a9bd05e514 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected @@ -0,0 +1,34 @@ +edges +| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | +| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | +| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | +| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | +| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | +| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | +| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | +| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | +nodes +| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | +| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | +| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | +subpaths +#select +| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | +| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | +| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | +| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | +| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | +| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref new file mode 100644 index 00000000000..e06e0921159 --- /dev/null +++ b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref @@ -0,0 +1 @@ +experimental/cwe-502/YAMLUnsafeDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.rb rename to ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected deleted file mode 100644 index 489602044a7..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.expected +++ /dev/null @@ -1,34 +0,0 @@ -edges -| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | -nodes -| YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | -| YAMLUnsafeYamlDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | -subpaths -#select -| YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeYamlDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeYamlDeserialization.rb:13:23:13:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeYamlDeserialization.rb:15:5:15:24 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeYamlDeserialization.rb:16:5:16:45 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | -| YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeYamlDeserialization.rb:17:5:17:48 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeYamlDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref deleted file mode 100644 index 87fe2520217..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeYamlDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/cwe-502/YAMLUnsafeYamlDeserialization.ql \ No newline at end of file From ad7e107ff57da219b2abc185fc8e80020b302082 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Wed, 1 Mar 2023 08:55:17 +0100 Subject: [PATCH 065/219] add the new YAML/PLIST sinks into the existing rb/unsafe-deserialization query --- .../UnsafeDeserializationCustomizations.qll | 59 ++++++++++++++++++- .../security/UnsafeDeserializationQuery.qll | 22 +++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll index 45e0888eacd..96f7e87d7a2 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll @@ -75,13 +75,41 @@ module UnsafeDeserialization { } /** - * An argument in a call to `YAML.load`, considered a sink + * An argument in a call to `YAML.unsafe_*` and `YAML.load_stream` , considered sinks * for unsafe deserialization. The `YAML` module is an alias of `Psych` in * recent versions of Ruby. */ class YamlLoadArgument extends Sink { YamlLoadArgument() { - this = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("load").getArgument(0) + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) + .getArgument(0) + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["unsafe_load", "load_stream"]) + .getKeywordArgument("yaml") + or + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall("unsafe_load_file") + .getKeywordArgument("filename") + } + } + + /** + * An argument in a call to `YAML.parse*`, considered sinks + * for unsafe deserialization if there is a call to `to_ruby` on returned value of them, + * so this need some additional taint steps. The `YAML` module is an alias of `Psych` in + * recent versions of Ruby. + */ + class YamlParseArgument extends Sink { + YamlParseArgument() { + this = + API::getTopLevelMember(["YAML", "Psych"]) + .getAMethodCall(["parse", "parse_stream", "parse_file"]) + .getAMethodCall("to_ruby") } } @@ -208,4 +236,31 @@ module UnsafeDeserialization { ) } } + + /** + * check whether an input argument has desired "key: value" input or not. + */ + predicate checkkeyValue(CfgNodes::ExprNodes::PairCfgNode p, string key, string value) { + p.getKey().getConstantValue().isStringlikeValue(key) and + DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().toString() = value + } + + /** + * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is + * the default), considered a sink for unsafe deserialization. + */ + class UnsafePlistParsexmlArgument extends Sink { + UnsafePlistParsexmlArgument() { + exists(DataFlow::CallNode plistParsexml | + plistParsexml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") + | + this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and + // Exclude calls that explicitly pass a safe mode option. + checkkeyValue(plistParsexml.getArgument(1).asExpr(), "marshal", "true") + or + this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and + plistParsexml.getNumberOfArguments() = 1 + ) + } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll index dc6293dc10e..fed9160ccd9 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll @@ -9,6 +9,7 @@ private import codeql.ruby.AST private import codeql.ruby.DataFlow private import codeql.ruby.TaintTracking +private import codeql.ruby.ApiGraphs import UnsafeDeserializationCustomizations /** @@ -23,6 +24,27 @@ class Configuration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserialization::Sink } + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = + API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + or + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and + ( + nodeFrom = yaml_parser_methods.getArgument(0) or + nodeFrom = yaml_parser_methods.getKeywordArgument("filename") + ) and + nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") + ) + } + override predicate isSanitizer(DataFlow::Node node) { super.isSanitizer(node) or node instanceof UnsafeDeserialization::Sanitizer From e76ed9454ab924a1b9a1f2a99711180938ade110 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Wed, 1 Mar 2023 10:45:45 +0100 Subject: [PATCH 066/219] v3 add global taint steps for to_ruby of YAML/Psych --- ruby/ql/lib/codeql/ruby/Frameworks.qll | 1 + ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll | 30 +++++++++++++++++++ .../security/UnsafeDeserializationQuery.qll | 21 ------------- 3 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll diff --git a/ruby/ql/lib/codeql/ruby/Frameworks.qll b/ruby/ql/lib/codeql/ruby/Frameworks.qll index 29eacf22e33..e6f2d9681f3 100644 --- a/ruby/ql/lib/codeql/ruby/Frameworks.qll +++ b/ruby/ql/lib/codeql/ruby/Frameworks.qll @@ -33,3 +33,4 @@ private import codeql.ruby.frameworks.Sinatra private import codeql.ruby.frameworks.Twirp private import codeql.ruby.frameworks.Sqlite3 private import codeql.ruby.frameworks.Pg +private import codeql.ruby.frameworks.Yaml diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll new file mode 100644 index 00000000000..d1fe6547e56 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll @@ -0,0 +1,30 @@ +/** + * add additional steps for to_ruby method of YAML/Psych library + */ + +private import codeql.ruby.dataflow.FlowSteps +private import codeql.ruby.DataFlow +private import codeql.ruby.ApiGraphs + +private class YamlParseStep extends AdditionalTaintStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = + API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and + ( + pred = yaml_parser_methods.getArgument(0) or + pred = yaml_parser_methods.getKeywordArgument("yaml") + ) and + succ = yaml_parser_methods.getAMethodCall("to_ruby") + ) + or + exists(DataFlow::CallNode yaml_parser_methods | + yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and + ( + pred = yaml_parser_methods.getArgument(0) or + pred = yaml_parser_methods.getKeywordArgument("filename") + ) and + succ = yaml_parser_methods.getAMethodCall("to_ruby") + ) + } +} diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll index fed9160ccd9..c4c5a39e451 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll @@ -24,27 +24,6 @@ class Configuration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserialization::Sink } - override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = - API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - or - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("filename") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - } - override predicate isSanitizer(DataFlow::Node node) { super.isSanitizer(node) or node instanceof UnsafeDeserialization::Sanitizer From 335441ce041893314eb377e154f4d11876f3eb6f Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Mon, 24 Apr 2023 10:43:09 +0200 Subject: [PATCH 067/219] v4: make variable names camelCase, some inhancement, remove some duplicates --- ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll | 41 ++++++++++------ .../UnsafeDeserializationCustomizations.qll | 48 ++++++++----------- .../security/UnsafeDeserializationQuery.qll | 1 - .../cwe-502/PlistUnsafeDeserialization.qhelp | 7 ++- .../cwe-502/PlistUnsafeDeserialization.ql | 25 +++------- .../cwe-502/PlistUnsafeDeserialization.rb | 6 ++- .../cwe-502/UnsafeDeserialization.qhelp | 23 +++++++++ .../examples/PlistUnsafeDeserialization.rb | 17 +++++++ .../examples/YAMLUnsafeDeserialization.rb | 22 +++++++++ 9 files changed, 123 insertions(+), 67 deletions(-) create mode 100644 ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb create mode 100644 ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll index d1fe6547e56..81afdcbed7b 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll @@ -1,30 +1,43 @@ /** - * add additional steps for to_ruby method of YAML/Psych library + * Provides modeling for the `YAML` and `Psych` libraries. */ private import codeql.ruby.dataflow.FlowSteps private import codeql.ruby.DataFlow private import codeql.ruby.ApiGraphs +/** + * A taint step related to the result of `YAML.parse` calls, or similar. + *In the following example, this step will propagate taint from + *`source` to `sink`: + * + *```rb + *x = source + *result = YAML.parse(x) + *sink result.to_ruby # Unsafe call + * ``` + */ private class YamlParseStep extends AdditionalTaintStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = - API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and + exists(DataFlow::CallNode yamlParserMethod | + yamlParserMethod = yamlNode().getAMethodCall(["parse", "parse_stream"]) and ( - pred = yaml_parser_methods.getArgument(0) or - pred = yaml_parser_methods.getKeywordArgument("yaml") + pred = yamlParserMethod.getArgument(0) or + pred = yamlParserMethod.getKeywordArgument("yaml") ) and - succ = yaml_parser_methods.getAMethodCall("to_ruby") - ) - or - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and + succ = yamlParserMethod.getAMethodCall("to_ruby") + or + yamlParserMethod = yamlNode().getAMethodCall("parse_file") and ( - pred = yaml_parser_methods.getArgument(0) or - pred = yaml_parser_methods.getKeywordArgument("filename") + pred = yamlParserMethod.getArgument(0) or + pred = yamlParserMethod.getKeywordArgument("filename") ) and - succ = yaml_parser_methods.getAMethodCall("to_ruby") + succ = yamlParserMethod.getAMethodCall("to_ruby") ) } } + +/** + * YAML/Psych Top level Class member + */ +private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) } diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll index 96f7e87d7a2..fcaceed1b3a 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll @@ -78,26 +78,27 @@ module UnsafeDeserialization { * An argument in a call to `YAML.unsafe_*` and `YAML.load_stream` , considered sinks * for unsafe deserialization. The `YAML` module is an alias of `Psych` in * recent versions of Ruby. + * the `this = yamlNode().getAMethodCall("load").getArgument(0)` is safe + * in recent versions of YAML library, so it will be removed in future. */ class YamlLoadArgument extends Sink { YamlLoadArgument() { - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) - .getArgument(0) + this = yamlNode().getAMethodCall("load").getArgument(0) or this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load", "load_stream"]) - .getKeywordArgument("yaml") + yamlNode().getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]).getArgument(0) or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall("unsafe_load_file") - .getKeywordArgument("filename") + this = yamlNode().getAMethodCall(["unsafe_load", "load_stream"]).getKeywordArgument("yaml") + or + this = yamlNode().getAMethodCall("unsafe_load_file").getKeywordArgument("filename") } } + /** + * YAML/Psych Top level Class member + */ + private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) } + /** * An argument in a call to `YAML.parse*`, considered sinks * for unsafe deserialization if there is a call to `to_ruby` on returned value of them, @@ -107,9 +108,7 @@ module UnsafeDeserialization { class YamlParseArgument extends Sink { YamlParseArgument() { this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["parse", "parse_stream", "parse_file"]) - .getAMethodCall("to_ruby") + yamlNode().getAMethodCall(["parse", "parse_stream", "parse_file"]).getAMethodCall("to_ruby") } } @@ -237,29 +236,20 @@ module UnsafeDeserialization { } } - /** - * check whether an input argument has desired "key: value" input or not. - */ - predicate checkkeyValue(CfgNodes::ExprNodes::PairCfgNode p, string key, string value) { - p.getKey().getConstantValue().isStringlikeValue(key) and - DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().toString() = value - } - /** * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is * the default), considered a sink for unsafe deserialization. */ class UnsafePlistParsexmlArgument extends Sink { UnsafePlistParsexmlArgument() { - exists(DataFlow::CallNode plistParsexml | - plistParsexml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") + exists(DataFlow::CallNode plistParseXml | + plistParseXml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") | - this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and - // Exclude calls that explicitly pass a safe mode option. - checkkeyValue(plistParsexml.getArgument(1).asExpr(), "marshal", "true") + this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and + plistParseXml.getKeywordArgument("marshal").getConstantValue().isBoolean(true) or - this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and - plistParsexml.getNumberOfArguments() = 1 + this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and + plistParseXml.getNumberOfArguments() = 1 ) } } diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll index c4c5a39e451..dc6293dc10e 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll @@ -9,7 +9,6 @@ private import codeql.ruby.AST private import codeql.ruby.DataFlow private import codeql.ruby.TaintTracking -private import codeql.ruby.ApiGraphs import UnsafeDeserializationCustomizations /** diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp index 80ec6c51dc0..45c4220c1b4 100644 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp @@ -8,18 +8,17 @@ </overview> <recommendation> <p> - This vulnerability can be prevented by using <code>Plist.parse_xml</code>. + This vulnerability in Plist can be prevented by calling <code>Plist.parse_xml FileOrXmlString, marshal: false</code>. </p> </recommendation> <example> - <p>In the example below, you can see safe and unsafe call of this dangerous method that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. + <p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. </p> <sample src="PlistUnsafeYamlDeserialization.rb" /> </example> <references> <li> - Security considerations from library documentation - <a href="https://github.com/patsplat/plist#label-Security+considerations">patsplat/plist</a>. + Security considerations from library documentation: <a href="https://github.com/patsplat/plist#label-Security+considerations">patsplat/plist Repository</a>. </li> </references> </qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql index 02d554cffb6..4ba55824598 100644 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql @@ -6,7 +6,7 @@ * @problem.severity warning * @security-severity 9.8 * @precision high - * @id rb/Plist-unsafe-deserialization + * @id rb/plist-unsafe-deserialization * @tags security * experimental * external/cwe/cwe-502 @@ -21,31 +21,20 @@ import codeql.ruby.security.UnsafeDeserializationCustomizations abstract class PlistUnsafeSinks extends DataFlow::Node { } -/** - * check whether an input argument has desired "key: value" input or not. - * borrowed from UnsafeDeserialization module with some changes - */ -predicate checkkeyBalue(CfgNodes::ExprNodes::PairCfgNode p, string key, string value) { - p.getKey().getConstantValue().isStringlikeValue(key) and - DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().toString() = value -} - /** * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is * the default), considered a sink for unsafe deserialization. - * borrowed from UnsafeDeserialization module with some changes */ class UnsafePlistParsexmlArgument extends PlistUnsafeSinks { UnsafePlistParsexmlArgument() { - exists(DataFlow::CallNode plistParsexml | - plistParsexml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") + exists(DataFlow::CallNode plistParseXml | + plistParseXml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") | - this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and - // Exclude calls that explicitly pass a safe mode option. - checkkeyBalue(plistParsexml.getArgument(1).asExpr(), "marshal", "true") + this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and + plistParseXml.getKeywordArgument("marshal").getConstantValue().isBoolean(true) or - this = [plistParsexml.getArgument(0), plistParsexml.getKeywordArgument("filename_or_xml")] and - plistParsexml.getNumberOfArguments() = 1 + this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and + plistParseXml.getNumberOfArguments() = 1 ) } } diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb index 63f64b5cd22..433873d6fa0 100644 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb @@ -1,12 +1,16 @@ -require 'yaml' +require 'plist' class UsersController < ActionController::Base def example # not safe + config = true result = Plist.parse_xml(params[:yaml_string]) + result = Plist.parse_xml(params[:yaml_string], marshal: config) result = Plist.parse_xml(params[:yaml_string], marshal: true) # safe + config = false result = Plist.parse_xml(params[:yaml_string], marshal: false) + result = Plist.parse_xml(params[:yaml_string], marshal: config) end end diff --git a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp index 406ba24935b..9ee9234770e 100644 --- a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp +++ b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp @@ -17,6 +17,17 @@ libraries that support it, such as the Ruby standard library's <code>JSON</code> module, ensure that the parser is configured to disable deserialization of arbitrary objects. </p> + +<p> +YAML/Psych recommendation: +After Psych(YAML) 4.0.0, the load method is same as safe_load method. +This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. +Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. +</p> + +<p> +This vulnerability in Plist can be prevented by calling <code>Plist.parse_xml FileOrXmlString, marshal: false</code>. +</p> </recommendation> <example> @@ -27,6 +38,14 @@ on data from an HTTP request. Since these methods are capable of deserializing to arbitrary objects, this is inherently unsafe. </p> <sample src="examples/UnsafeDeserializationBad.rb"/> + +<p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> +<sample src="examples/YAMLUnsafeYamlDeserialization.rb"/> + +<p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. +</p> +<sample src="examples/PlistUnsafeYamlDeserialization.rb"/> + <p> Using <code>JSON.parse</code> and <code>YAML.safe_load</code> instead, as in the following example, removes the vulnerability. Similarly, calling @@ -55,6 +74,10 @@ Ruby documentation: <a href="https://ruby-doc.org/stdlib-3.0.2/libdoc/json/rdoc/ <li> Ruby documentation: <a href="https://ruby-doc.org/stdlib-3.0.2/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security">security guidance on the YAML library</a>. </li> +<li> +You can read that how unsafe yaml load methods can lead to code executions: +<a href="https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html">Universal Deserialisation Gadget for Ruby 2.x-3.x </a>. +</li> </references> </qhelp> diff --git a/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb b/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb new file mode 100644 index 00000000000..433873d6fa0 --- /dev/null +++ b/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb @@ -0,0 +1,17 @@ +require 'plist' +class UsersController < ActionController::Base + def example + # not safe + config = true + result = Plist.parse_xml(params[:yaml_string]) + result = Plist.parse_xml(params[:yaml_string], marshal: config) + result = Plist.parse_xml(params[:yaml_string], marshal: true) + + # safe + config = false + result = Plist.parse_xml(params[:yaml_string], marshal: false) + result = Plist.parse_xml(params[:yaml_string], marshal: config) + end +end + + diff --git a/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb b/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb new file mode 100644 index 00000000000..6e836a0a049 --- /dev/null +++ b/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb @@ -0,0 +1,22 @@ +require 'yaml' +class UsersController < ActionController::Base + def example + # safe + Psych.load(params[:yaml_string]) + Psych.load_file(params[:yaml_file]) + Psych.parse_stream(params[:yaml_string]) + Psych.parse(params[:yaml_string]) + Psych.parse_file(params[:yaml_file]) + # unsafe + Psych.unsafe_load(params[:yaml_string]) + Psych.unsafe_load_file(params[:yaml_file]) + Psych.load_stream(params[:yaml_string]) + parse_output = Psych.parse_stream(params[:yaml_string]) + parse_output.to_ruby + Psych.parse(params[:yaml_string]).to_ruby + Psych.parse_file(params[:yaml_file]).to_ruby + + end +end + + From 40e24b6b94508d98dde7090dcd439714775f8bd0 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Thu, 27 Apr 2023 06:35:34 +0200 Subject: [PATCH 068/219] v4.1 fix file names in qhelp --- .../src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp | 2 +- .../src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp | 2 +- .../src/queries/security/cwe-502/UnsafeDeserialization.qhelp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp index 45c4220c1b4..9863402d583 100644 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp +++ b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp @@ -14,7 +14,7 @@ <example> <p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. </p> - <sample src="PlistUnsafeYamlDeserialization.rb" /> + <sample src="PlistUnsafeDeserialization.rb" /> </example> <references> <li> diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp index c3a74527483..c644f495271 100644 --- a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp +++ b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp @@ -15,7 +15,7 @@ </recommendation> <example> <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> - <sample src="YAMLUnsafeYamlDeserialization.rb" /> + <sample src="YAMLUnsafeDeserialization.rb" /> </example> <references> <li> diff --git a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp index 9ee9234770e..1ebf32750a1 100644 --- a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp +++ b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp @@ -40,11 +40,11 @@ to arbitrary objects, this is inherently unsafe. <sample src="examples/UnsafeDeserializationBad.rb"/> <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> -<sample src="examples/YAMLUnsafeYamlDeserialization.rb"/> +<sample src="examples/YAMLUnsafeDeserialization.rb"/> <p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. </p> -<sample src="examples/PlistUnsafeYamlDeserialization.rb"/> +<sample src="examples/PlistUnsafeDeserialization.rb"/> <p> Using <code>JSON.parse</code> and <code>YAML.safe_load</code> instead, as in the From d727d573d5ce139e8356bfca8765fc4dbcc9caa4 Mon Sep 17 00:00:00 2001 From: amammad <amg2027amg@gmail.com> Date: Thu, 27 Apr 2023 06:48:15 +0200 Subject: [PATCH 069/219] v4.2 write exact version of yaml.load default loader change --- .../ruby/security/UnsafeDeserializationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll index fcaceed1b3a..9dea66252e5 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll @@ -79,7 +79,7 @@ module UnsafeDeserialization { * for unsafe deserialization. The `YAML` module is an alias of `Psych` in * recent versions of Ruby. * the `this = yamlNode().getAMethodCall("load").getArgument(0)` is safe - * in recent versions of YAML library, so it will be removed in future. + * in psych/yaml library after [v4.0.0](https://github.com/ruby/psych/releases/tag/v4.0.0), so it will be removed in future. */ class YamlLoadArgument extends Sink { YamlLoadArgument() { From b8c3cba4ff0fa9819982425cca1bf41dcbd0e2c0 Mon Sep 17 00:00:00 2001 From: Harry Maclean <hmac@github.com> Date: Fri, 26 May 2023 14:48:16 +0000 Subject: [PATCH 070/219] Ruby: Consolidate unsafe deserialization queries Merge the experimental YAMLUnsafeDeserialization and PlistUnsafeDeserialization queries into the generate UnsafeDeserialization query in the default suite. These queries look for some specific sinks that we now find in the general query. Also apply some small code and comment refactors. --- ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll | 34 +++---- .../UnsafeDeserializationCustomizations.qll | 25 +++--- .../cwe-502/PlistUnsafeDeserialization.qhelp | 24 ----- .../cwe-502/PlistUnsafeDeserialization.ql | 57 ------------ .../cwe-502/PlistUnsafeDeserialization.rb | 17 ---- .../cwe-502/YAMLUnsafeDeserialization.qhelp | 26 ------ .../cwe-502/YAMLUnsafeDeserialization.ql | 88 ------------------- .../cwe-502/UnsafeDeserialization.qhelp | 22 +++-- .../PlistUnsafeDeserialization.expected | 12 --- .../cwe-502/PlistUnsafeDeserialization.qlref | 1 - .../YAMLUnsafeDeserialization.expected | 34 ------- .../cwe-502/YAMLUnsafeDeserialization.qlref | 1 - .../cwe-502/YAMLUnsafeDeserialization.rb | 22 ----- .../PlistUnsafeDeserialization.rb | 0 .../UnsafeDeserialization.expected | 42 +++++++++ .../YAMLUnsafeDeserialization.rb | 0 16 files changed, 75 insertions(+), 330 deletions(-) delete mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp delete mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql delete mode 100644 ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb delete mode 100644 ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp delete mode 100644 ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref delete mode 100644 ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb rename ruby/ql/test/query-tests/{experimental/Security/cwe-502 => security/cwe-502/unsafe-deserialization}/PlistUnsafeDeserialization.rb (100%) rename ruby/ql/{src/experimental/cwe-502 => test/query-tests/security/cwe-502/unsafe-deserialization}/YAMLUnsafeDeserialization.rb (100%) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll index 81afdcbed7b..65596df7fe2 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Yaml.qll @@ -8,36 +8,28 @@ private import codeql.ruby.ApiGraphs /** * A taint step related to the result of `YAML.parse` calls, or similar. - *In the following example, this step will propagate taint from - *`source` to `sink`: + * In the following example, this step will propagate taint from + * `source` to `sink`: * - *```rb - *x = source - *result = YAML.parse(x) - *sink result.to_ruby # Unsafe call + * ```rb + * x = source + * result = YAML.parse(x) + * sink result.to_ruby # Unsafe call * ``` */ private class YamlParseStep extends AdditionalTaintStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(DataFlow::CallNode yamlParserMethod | - yamlParserMethod = yamlNode().getAMethodCall(["parse", "parse_stream"]) and + succ = yamlParserMethod.getAMethodCall("to_ruby") and ( - pred = yamlParserMethod.getArgument(0) or - pred = yamlParserMethod.getKeywordArgument("yaml") - ) and - succ = yamlParserMethod.getAMethodCall("to_ruby") - or - yamlParserMethod = yamlNode().getAMethodCall("parse_file") and - ( - pred = yamlParserMethod.getArgument(0) or - pred = yamlParserMethod.getKeywordArgument("filename") - ) and - succ = yamlParserMethod.getAMethodCall("to_ruby") + yamlParserMethod = yamlNode().getAMethodCall(["parse", "parse_stream"]) and + pred = [yamlParserMethod.getArgument(0), yamlParserMethod.getKeywordArgument("yaml")] + or + yamlParserMethod = yamlNode().getAMethodCall("parse_file") and + pred = [yamlParserMethod.getArgument(0), yamlParserMethod.getKeywordArgument("filename")] + ) ) } } -/** - * YAML/Psych Top level Class member - */ private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) } diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll index 9dea66252e5..e38a38af2dc 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll @@ -75,14 +75,13 @@ module UnsafeDeserialization { } /** - * An argument in a call to `YAML.unsafe_*` and `YAML.load_stream` , considered sinks + * An argument in a call to `YAML.unsafe_*` and `YAML.load_stream` , considered a sink * for unsafe deserialization. The `YAML` module is an alias of `Psych` in * recent versions of Ruby. - * the `this = yamlNode().getAMethodCall("load").getArgument(0)` is safe - * in psych/yaml library after [v4.0.0](https://github.com/ruby/psych/releases/tag/v4.0.0), so it will be removed in future. */ class YamlLoadArgument extends Sink { YamlLoadArgument() { + // Note: this is safe in psych/yaml >= 4.0.0. this = yamlNode().getAMethodCall("load").getArgument(0) or this = @@ -94,16 +93,11 @@ module UnsafeDeserialization { } } - /** - * YAML/Psych Top level Class member - */ private API::Node yamlNode() { result = API::getTopLevelMember(["YAML", "Psych"]) } /** - * An argument in a call to `YAML.parse*`, considered sinks - * for unsafe deserialization if there is a call to `to_ruby` on returned value of them, - * so this need some additional taint steps. The `YAML` module is an alias of `Psych` in - * recent versions of Ruby. + * An argument in a call to `YAML.parse*`, considered a sink for unsafe deserialization + * if there is a call to `to_ruby` on the returned value. */ class YamlParseArgument extends Sink { YamlParseArgument() { @@ -237,7 +231,7 @@ module UnsafeDeserialization { } /** - * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is + * An argument in a call to `Plist.parse_xml` where `marshal` is `true` (which is * the default), considered a sink for unsafe deserialization. */ class UnsafePlistParsexmlArgument extends Sink { @@ -246,10 +240,11 @@ module UnsafeDeserialization { plistParseXml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") | this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and - plistParseXml.getKeywordArgument("marshal").getConstantValue().isBoolean(true) - or - this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and - plistParseXml.getNumberOfArguments() = 1 + ( + plistParseXml.getKeywordArgument("marshal").getConstantValue().isBoolean(true) + or + plistParseXml.getNumberOfArguments() = 1 + ) ) } } diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp deleted file mode 100644 index 9863402d583..00000000000 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.qhelp +++ /dev/null @@ -1,24 +0,0 @@ -<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> -<qhelp> - <overview> - <p> - Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. - Unsafe deserializing the malicious serialized xml document through the Plist library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. - </p> - </overview> - <recommendation> - <p> - This vulnerability in Plist can be prevented by calling <code>Plist.parse_xml FileOrXmlString, marshal: false</code>. - </p> - </recommendation> - <example> - <p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. - </p> - <sample src="PlistUnsafeDeserialization.rb" /> - </example> - <references> - <li> - Security considerations from library documentation: <a href="https://github.com/patsplat/plist#label-Security+considerations">patsplat/plist Repository</a>. - </li> - </references> -</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql deleted file mode 100644 index 4ba55824598..00000000000 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.ql +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @name Unsafe Deserialization of user-controlled data by Plist - * @description Deserializing user-controlled data may allow attackers to - * execute arbitrary code. - * @kind path-problem - * @problem.severity warning - * @security-severity 9.8 - * @precision high - * @id rb/plist-unsafe-deserialization - * @tags security - * experimental - * external/cwe/cwe-502 - */ - -import codeql.ruby.ApiGraphs -import codeql.ruby.DataFlow -import codeql.ruby.TaintTracking -import codeql.ruby.CFG -import DataFlow::PathGraph -import codeql.ruby.security.UnsafeDeserializationCustomizations - -abstract class PlistUnsafeSinks extends DataFlow::Node { } - -/** - * An argument in a call to `Plist.parse_xml` where the marshal is `true` (which is - * the default), considered a sink for unsafe deserialization. - */ -class UnsafePlistParsexmlArgument extends PlistUnsafeSinks { - UnsafePlistParsexmlArgument() { - exists(DataFlow::CallNode plistParseXml | - plistParseXml = API::getTopLevelMember("Plist").getAMethodCall("parse_xml") - | - this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and - plistParseXml.getKeywordArgument("marshal").getConstantValue().isBoolean(true) - or - this = [plistParseXml.getArgument(0), plistParseXml.getKeywordArgument("filename_or_xml")] and - plistParseXml.getNumberOfArguments() = 1 - ) - } -} - -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "PlistUnsafeDeserialization" } - - override predicate isSource(DataFlow::Node source) { - // to detect CVE-2021-33575, we should uncomment following line instead of current UnsafeDeserialization::Source - // source instanceof DataFlow::LocalSourceNode - source instanceof UnsafeDeserialization::Source - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof PlistUnsafeSinks } -} - -from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink -where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Unsafe deserialization depends on a $@.", source.getNode(), - "potentially untrusted source" diff --git a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb b/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb deleted file mode 100644 index 433873d6fa0..00000000000 --- a/ruby/ql/src/experimental/cwe-502/PlistUnsafeDeserialization.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'plist' -class UsersController < ActionController::Base - def example - # not safe - config = true - result = Plist.parse_xml(params[:yaml_string]) - result = Plist.parse_xml(params[:yaml_string], marshal: config) - result = Plist.parse_xml(params[:yaml_string], marshal: true) - - # safe - config = false - result = Plist.parse_xml(params[:yaml_string], marshal: false) - result = Plist.parse_xml(params[:yaml_string], marshal: config) - end -end - - diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp deleted file mode 100644 index c644f495271..00000000000 --- a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.qhelp +++ /dev/null @@ -1,26 +0,0 @@ -<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> -<qhelp> - <overview> - <p> - Processing an unvalidated user input can allow an attacker to execute arbitrary code in your application. - Unsafe deserializing the malicious serialized yaml document through the Psych (YAML) library, making it possible to execute some code or execute arbitrary code with the help of a complete gadget chain. - </p> - </overview> - <recommendation> - <p> - After Psych(YAML) 4.0.0, the load method is same as safe_load method. - This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. - Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. - </p> - </recommendation> - <example> - <p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> - <sample src="YAMLUnsafeDeserialization.rb" /> - </example> - <references> - <li> - You can read that how unsafe yaml load methods can lead to code executions. - <a href="https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html">Universal Deserialisation Gadget for Ruby 2.x-3.x </a>. - </li> - </references> -</qhelp> \ No newline at end of file diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql b/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql deleted file mode 100644 index 5cb720d19da..00000000000 --- a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.ql +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @name Unsafe Deserialization of user-controlled data by YAML - * @description Deserializing user-controlled data may allow attackers to - * execute arbitrary code. - * @kind path-problem - * @problem.severity warning - * @security-severity 9.8 - * @precision high - * @id rb/YAML-unsafe-deserialization - * @tags security - * experimental - * external/cwe/cwe-502 - */ - -import codeql.ruby.ApiGraphs -import codeql.ruby.DataFlow -import codeql.ruby.TaintTracking -import DataFlow::PathGraph -import codeql.ruby.security.UnsafeDeserializationCustomizations - -abstract class YamlUnsafeSinks extends DataFlow::Node { } - -class YamlUnsafeArgument extends YamlUnsafeSinks { - YamlUnsafeArgument() { - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load_file", "unsafe_load", "load_stream"]) - .getArgument(0) - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["unsafe_load", "load_stream"]) - .getKeywordArgument("yaml") - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall("unsafe_load_file") - .getKeywordArgument("filename") - or - this = - API::getTopLevelMember(["YAML", "Psych"]) - .getAMethodCall(["parse", "parse_stream", "parse_file"]) - .getAMethodCall("to_ruby") - } -} - -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "YamlUnsafeDeserialization" } - - override predicate isSource(DataFlow::Node source) { - // to detect CVE-2022-32224, we should uncomment following line instead of current UnsafeDeserialization::Source - // source instanceof DataFlow::LocalSourceNode - source instanceof UnsafeDeserialization::Source - } - - override predicate isSink(DataFlow::Node sink) { - // after changing the isSource for detecting CVE-2022-32224 - // uncomment the following line only see the CVE sink not other files similar sinks - // sink.getLocation().getFile().toString().matches("%yaml_column%") and - sink instanceof YamlUnsafeSinks - } - - override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = - API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall(["parse", "parse_stream"]) and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("yaml") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - or - exists(DataFlow::CallNode yaml_parser_methods | - yaml_parser_methods = API::getTopLevelMember(["YAML", "Psych"]).getAMethodCall("parse_file") and - ( - nodeFrom = yaml_parser_methods.getArgument(0) or - nodeFrom = yaml_parser_methods.getKeywordArgument("filename") - ) and - nodeTo = yaml_parser_methods.getAMethodCall("to_ruby") - ) - } -} - -from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink -where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Unsafe deserialization depends on a $@.", source.getNode(), - "potentially untrusted source" diff --git a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp index 1ebf32750a1..17f03853570 100644 --- a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp +++ b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp @@ -19,14 +19,19 @@ deserialization of arbitrary objects. </p> <p> -YAML/Psych recommendation: -After Psych(YAML) 4.0.0, the load method is same as safe_load method. -This vulnerability can be prevented by using YAML.load (same as <code>YAML.safe_load</code>), <code>YAML.load_file</code> (same as <code>YAML.safe_load_file</code>) instead of <code>YAML.unsafe_*</code> methods. -Be careful that <code>YAML.load_stream</code> don't use safe_load method, Also Be careful the <code>to_ruby</code> method of Psych get called on a trusted parsed (<code>YAML.parse*</code>) yaml document. +If deserializing an untrusted YAML document using the <code>psych</code> gem +prior to version 4.0.0, the <code>load</code> method is vulnerable. Use +<code>safe_load</code> instead. With <code>psych</code> version 4.0.0 and later, +the <code>load</code> is safe. The same applies to <code>load_file</code>. +<code>load_stream</code> is vulnerable in all versions. The safe versions of these +methods (<code>safe_load</code> and <code>safe_load_file</code>) are not vulnerable +in any known version. </p> <p> -This vulnerability in Plist can be prevented by calling <code>Plist.parse_xml FileOrXmlString, marshal: false</code>. +To safely deserialize <a href="https://en.wikipedia.org/wiki/Property_list">Property List</a> +files using the <code>plist</code> gem, ensure that you pass <code>marshal: false</code> +when calling <code>Plist.parse_xml</code>. </p> </recommendation> @@ -39,13 +44,6 @@ to arbitrary objects, this is inherently unsafe. </p> <sample src="examples/UnsafeDeserializationBad.rb"/> -<p>In the example below, you can see safe and unsafe methods get called by a remote user input. You can give correct authorization to users, or you can use safe methods for loading yaml documents.</p> -<sample src="examples/YAMLUnsafeDeserialization.rb"/> - -<p>In the example below, you can see safe and unsafe Plist dangerous method calls that can be abused by a remote user input. You can use "marshal: false" as an arugument for <code>Plist.parse_xml</code> to use it safe. -</p> -<sample src="examples/PlistUnsafeDeserialization.rb"/> - <p> Using <code>JSON.parse</code> and <code>YAML.safe_load</code> instead, as in the following example, removes the vulnerability. Similarly, calling diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected deleted file mode 100644 index 967ef978a3b..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.expected +++ /dev/null @@ -1,12 +0,0 @@ -edges -| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | -| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | -nodes -| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | semmle.label | call to params : | -| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] | -| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | semmle.label | call to params : | -| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] | -subpaths -#select -| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params : | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | potentially untrusted source | -| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params : | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref deleted file mode 100644 index f7bfbada7b5..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/cwe-502/PlistUnsafeDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected deleted file mode 100644 index 9a9bd05e514..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.expected +++ /dev/null @@ -1,34 +0,0 @@ -edges -| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | -| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | -| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | -| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | -| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | -| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | -| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | -| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | -| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | -nodes -| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | -| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] : | semmle.label | ...[...] : | -| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | -| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | semmle.label | call to params : | -| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] : | semmle.label | ...[...] : | -subpaths -#select -| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params : | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | potentially untrusted source | -| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params : | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | potentially untrusted source | -| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params : | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | potentially untrusted source | -| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params : | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | potentially untrusted source | -| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params : | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | potentially untrusted source | -| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params : | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | potentially untrusted source | diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref deleted file mode 100644 index e06e0921159..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/cwe-502/YAMLUnsafeDeserialization.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb b/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb deleted file mode 100644 index 6e836a0a049..00000000000 --- a/ruby/ql/test/query-tests/experimental/Security/cwe-502/YAMLUnsafeDeserialization.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'yaml' -class UsersController < ActionController::Base - def example - # safe - Psych.load(params[:yaml_string]) - Psych.load_file(params[:yaml_file]) - Psych.parse_stream(params[:yaml_string]) - Psych.parse(params[:yaml_string]) - Psych.parse_file(params[:yaml_file]) - # unsafe - Psych.unsafe_load(params[:yaml_string]) - Psych.unsafe_load_file(params[:yaml_file]) - Psych.load_stream(params[:yaml_string]) - parse_output = Psych.parse_stream(params[:yaml_string]) - parse_output.to_ruby - Psych.parse(params[:yaml_string]).to_ruby - Psych.parse_file(params[:yaml_file]).to_ruby - - end -end - - diff --git a/ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.rb b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/PlistUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/test/query-tests/experimental/Security/cwe-502/PlistUnsafeDeserialization.rb rename to ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/PlistUnsafeDeserialization.rb diff --git a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.expected b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.expected index 6fbbb14ef8a..b1f1d701a73 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.expected +++ b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.expected @@ -1,4 +1,6 @@ edges +| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | +| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | | UnsafeDeserialization.rb:10:5:10:19 | serialized_data | UnsafeDeserialization.rb:11:27:11:41 | serialized_data | | UnsafeDeserialization.rb:10:23:10:50 | call to decode64 | UnsafeDeserialization.rb:10:5:10:19 | serialized_data | | UnsafeDeserialization.rb:10:39:10:44 | call to params | UnsafeDeserialization.rb:10:39:10:50 | ...[...] | @@ -29,7 +31,21 @@ edges | UnsafeDeserialization.rb:87:5:87:13 | yaml_data | UnsafeDeserialization.rb:88:25:88:33 | yaml_data | | UnsafeDeserialization.rb:87:17:87:22 | call to params | UnsafeDeserialization.rb:87:17:87:28 | ...[...] | | UnsafeDeserialization.rb:87:17:87:28 | ...[...] | UnsafeDeserialization.rb:87:5:87:13 | yaml_data | +| YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | +| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | +| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | +| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | +| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] | +| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] | +| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | +| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] | +| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | nodes +| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | semmle.label | call to params | +| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] | +| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | semmle.label | call to params | +| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] | | UnsafeDeserialization.rb:10:5:10:19 | serialized_data | semmle.label | serialized_data | | UnsafeDeserialization.rb:10:23:10:50 | call to decode64 | semmle.label | call to decode64 | | UnsafeDeserialization.rb:10:39:10:44 | call to params | semmle.label | call to params | @@ -74,8 +90,27 @@ nodes | UnsafeDeserialization.rb:98:24:98:32 | call to read | semmle.label | call to read | | UnsafeDeserialization.rb:101:24:101:27 | call to gets | semmle.label | call to gets | | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | semmle.label | call to readlines | +| YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:14:39:14:58 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:16:17:16:36 | ...[...] | semmle.label | ...[...] | +| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | semmle.label | call to to_ruby | +| YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | semmle.label | call to params | +| YAMLUnsafeDeserialization.rb:17:22:17:39 | ...[...] | semmle.label | ...[...] | subpaths #select +| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | user-provided value | +| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | user-provided value | | UnsafeDeserialization.rb:11:27:11:41 | serialized_data | UnsafeDeserialization.rb:10:39:10:44 | call to params | UnsafeDeserialization.rb:11:27:11:41 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:10:39:10:44 | call to params | user-provided value | | UnsafeDeserialization.rb:17:30:17:44 | serialized_data | UnsafeDeserialization.rb:16:39:16:44 | call to params | UnsafeDeserialization.rb:17:30:17:44 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:16:39:16:44 | call to params | user-provided value | | UnsafeDeserialization.rb:23:24:23:32 | json_data | UnsafeDeserialization.rb:22:17:22:22 | call to params | UnsafeDeserialization.rb:23:24:23:32 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:22:17:22:22 | call to params | user-provided value | @@ -91,3 +126,10 @@ subpaths | UnsafeDeserialization.rb:98:24:98:32 | call to read | UnsafeDeserialization.rb:98:24:98:32 | call to read | UnsafeDeserialization.rb:98:24:98:32 | call to read | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:98:24:98:32 | call to read | value from stdin | | UnsafeDeserialization.rb:101:24:101:27 | call to gets | UnsafeDeserialization.rb:101:24:101:27 | call to gets | UnsafeDeserialization.rb:101:24:101:27 | call to gets | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:101:24:101:27 | call to gets | value from stdin | | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | value from stdin | +| YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | YAMLUnsafeDeserialization.rb:13:23:13:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:13:23:13:28 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | YAMLUnsafeDeserialization.rb:15:5:15:24 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:14:39:14:44 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | YAMLUnsafeDeserialization.rb:16:5:16:45 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:16:17:16:22 | call to params | user-provided value | +| YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | YAMLUnsafeDeserialization.rb:17:5:17:48 | call to to_ruby | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:17:22:17:27 | call to params | user-provided value | diff --git a/ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.rb b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/YAMLUnsafeDeserialization.rb similarity index 100% rename from ruby/ql/src/experimental/cwe-502/YAMLUnsafeDeserialization.rb rename to ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/YAMLUnsafeDeserialization.rb From 562065f29e6fd387534e517942e89f907117a290 Mon Sep 17 00:00:00 2001 From: Harry Maclean <hmac@github.com> Date: Sat, 27 May 2023 00:59:36 +0000 Subject: [PATCH 071/219] Ruby: Add change note --- ruby/ql/lib/change-notes/2023-05-27-unsafe-deserialization.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2023-05-27-unsafe-deserialization.md diff --git a/ruby/ql/lib/change-notes/2023-05-27-unsafe-deserialization.md b/ruby/ql/lib/change-notes/2023-05-27-unsafe-deserialization.md new file mode 100644 index 00000000000..4039e7c90dc --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-05-27-unsafe-deserialization.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Additional sinks for `rb/unsafe-deserialization` have been added. This includes various methods from the `yaml` and `plist` gems, which deserialize YAML and Property List data, respectively. From e515981c81d1fd82d586de9bc4afa8f5e4988470 Mon Sep 17 00:00:00 2001 From: Harry Maclean <hmac@github.com> Date: Sat, 27 May 2023 12:01:00 +0000 Subject: [PATCH 072/219] Ruby: Remove unused examples --- .../examples/PlistUnsafeDeserialization.rb | 17 -------------- .../examples/YAMLUnsafeDeserialization.rb | 22 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb delete mode 100644 ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb diff --git a/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb b/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb deleted file mode 100644 index 433873d6fa0..00000000000 --- a/ruby/ql/src/queries/security/cwe-502/examples/PlistUnsafeDeserialization.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'plist' -class UsersController < ActionController::Base - def example - # not safe - config = true - result = Plist.parse_xml(params[:yaml_string]) - result = Plist.parse_xml(params[:yaml_string], marshal: config) - result = Plist.parse_xml(params[:yaml_string], marshal: true) - - # safe - config = false - result = Plist.parse_xml(params[:yaml_string], marshal: false) - result = Plist.parse_xml(params[:yaml_string], marshal: config) - end -end - - diff --git a/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb b/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb deleted file mode 100644 index 6e836a0a049..00000000000 --- a/ruby/ql/src/queries/security/cwe-502/examples/YAMLUnsafeDeserialization.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'yaml' -class UsersController < ActionController::Base - def example - # safe - Psych.load(params[:yaml_string]) - Psych.load_file(params[:yaml_file]) - Psych.parse_stream(params[:yaml_string]) - Psych.parse(params[:yaml_string]) - Psych.parse_file(params[:yaml_file]) - # unsafe - Psych.unsafe_load(params[:yaml_string]) - Psych.unsafe_load_file(params[:yaml_file]) - Psych.load_stream(params[:yaml_string]) - parse_output = Psych.parse_stream(params[:yaml_string]) - parse_output.to_ruby - Psych.parse(params[:yaml_string]).to_ruby - Psych.parse_file(params[:yaml_file]).to_ruby - - end -end - - From ca1024e2858c6f541c5adef4e0405dbc6b7625f1 Mon Sep 17 00:00:00 2001 From: Harry Maclean <hmac@github.com> Date: Mon, 29 May 2023 03:46:30 +0000 Subject: [PATCH 073/219] Ruby: Reword unsafe deserialization qhelp --- .../security/cwe-502/UnsafeDeserialization.qhelp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp index 17f03853570..8bacb266423 100644 --- a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp +++ b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp @@ -19,13 +19,12 @@ deserialization of arbitrary objects. </p> <p> -If deserializing an untrusted YAML document using the <code>psych</code> gem -prior to version 4.0.0, the <code>load</code> method is vulnerable. Use -<code>safe_load</code> instead. With <code>psych</code> version 4.0.0 and later, -the <code>load</code> is safe. The same applies to <code>load_file</code>. -<code>load_stream</code> is vulnerable in all versions. The safe versions of these -methods (<code>safe_load</code> and <code>safe_load_file</code>) are not vulnerable -in any known version. +If deserializing an untrusted YAML document using the <code>psych</code> gem, +prefer the <code>safe_load</code> and <code>safe_load_file</code> methods over +<code>load</code> and <code>load_file</code>, as the former will safely +handle untrusted data. Avoid passing untrusted data to the <code>load_stream</code> +method. In <code>psych</code> version 4.0.0 and above, the <code>load</code> can +safely be used. </p> <p> From e70e3e52dcf7456465fdc6f59e687f08293c40d2 Mon Sep 17 00:00:00 2001 From: Harry Maclean <hmac@github.com> Date: Mon, 29 May 2023 04:05:42 +0000 Subject: [PATCH 074/219] Ruby: fix typo in qhelp --- .../ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp index 8bacb266423..e361b62338e 100644 --- a/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp +++ b/ruby/ql/src/queries/security/cwe-502/UnsafeDeserialization.qhelp @@ -23,7 +23,7 @@ If deserializing an untrusted YAML document using the <code>psych</code> gem, prefer the <code>safe_load</code> and <code>safe_load_file</code> methods over <code>load</code> and <code>load_file</code>, as the former will safely handle untrusted data. Avoid passing untrusted data to the <code>load_stream</code> -method. In <code>psych</code> version 4.0.0 and above, the <code>load</code> can +method. In <code>psych</code> version 4.0.0 and above, the <code>load</code> method can safely be used. </p> From d50617202746b8cbb8558f8486975a804e9a71fd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 May 2023 09:11:00 +0100 Subject: [PATCH 075/219] Swift: Change note. --- swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md diff --git a/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md b/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md new file mode 100644 index 00000000000..03de16f4269 --- /dev/null +++ b/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Incorporated the cross-language `SensitiveDataHeuristics.qll` heuristics library into the Swift `SensitiveExprs.qll` library. This adds a number of new heuristics enhancing detection from the library. \ No newline at end of file From 560aa43953a14843f0661420c40f13c1c66b0dae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 May 2023 14:20:17 +0100 Subject: [PATCH 076/219] Swift: Repair for AccountID / AccountKey. --- swift/ql/lib/codeql/swift/security/SensitiveExprs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index 71a250229e7..d750e673121 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -35,7 +35,7 @@ class SensitiveCredential extends SensitiveDataType, TCredential { result = HeuristicNames::maybeSensitiveRegexp(classification) ) or - result = "(?is).*(license.?key).*" + result = "(?is).*(account|accnt|license).?(id|key).*" } } From b343dcaadd01e19b610269b2bbbb1e709e509f57 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 31 May 2023 08:06:04 +0200 Subject: [PATCH 077/219] put string/object in the alert-message for sql-injection --- .../ql/src/Security/CWE-089/SqlInjection.ql | 9 +- .../ql/src/Security/CWE-089/SqlInjection.ql | 12 +- .../CWE-089/typed/SqlInjection.expected | 6 +- .../CWE-089/untyped/SqlInjection.expected | 250 +++++++++--------- 4 files changed, 139 insertions(+), 138 deletions(-) diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/Security/CWE-089/SqlInjection.ql index 6b0502f611f..f7a40bb91f9 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.ql @@ -18,12 +18,13 @@ import semmle.javascript.security.dataflow.SqlInjectionQuery as SqlInjection import semmle.javascript.security.dataflow.NosqlInjectionQuery as NosqlInjection import DataFlow::PathGraph -from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string type where ( - cfg instanceof SqlInjection::Configuration or - cfg instanceof NosqlInjection::Configuration + cfg instanceof SqlInjection::Configuration and type = "string" + or + cfg instanceof NosqlInjection::Configuration and type = "object" ) and cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "This query depends on a $@.", source.getNode(), +select sink.getNode(), source, sink, "This query " + type + " depends on a $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-089/SqlInjection.ql b/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-089/SqlInjection.ql index a2c4a4158bc..e82b9d40d5b 100644 --- a/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-089/SqlInjection.ql +++ b/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-089/SqlInjection.ql @@ -20,13 +20,13 @@ import semmle.javascript.security.dataflow.NosqlInjectionQuery as NosqlInjection import DataFlow::PathGraph import semmle.javascript.heuristics.AdditionalSources -from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string type where ( - cfg instanceof SqlInjection::Configuration or - cfg instanceof NosqlInjection::Configuration + cfg instanceof SqlInjection::Configuration and type = "string" + or + cfg instanceof NosqlInjection::Configuration and type = "object" ) and - cfg.hasFlowPath(source, sink) and - source.getNode() instanceof HeuristicSource -select sink.getNode(), source, sink, "This query depends on a $@.", source.getNode(), + cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "This query " + type + " depends on a $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/test/query-tests/Security/CWE-089/typed/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/typed/SqlInjection.expected index f6a8d8862f6..acf7e712ee2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/typed/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/typed/SqlInjection.expected @@ -37,6 +37,6 @@ edges | typedClient.ts:23:33:23:33 | v | typedClient.ts:23:27:23:35 | { id: v } | | typedClient.ts:23:33:23:33 | v | typedClient.ts:23:27:23:35 | { id: v } | #select -| typedClient.ts:14:24:14:32 | { id: v } | typedClient.ts:13:22:13:29 | req.body | typedClient.ts:14:24:14:32 | { id: v } | This query depends on a $@. | typedClient.ts:13:22:13:29 | req.body | user-provided value | -| typedClient.ts:22:27:22:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:22:27:22:35 | { id: v } | This query depends on a $@. | typedClient.ts:21:22:21:29 | req.body | user-provided value | -| typedClient.ts:23:27:23:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:23:27:23:35 | { id: v } | This query depends on a $@. | typedClient.ts:21:22:21:29 | req.body | user-provided value | +| typedClient.ts:14:24:14:32 | { id: v } | typedClient.ts:13:22:13:29 | req.body | typedClient.ts:14:24:14:32 | { id: v } | This query object depends on a $@. | typedClient.ts:13:22:13:29 | req.body | user-provided value | +| typedClient.ts:22:27:22:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:22:27:22:35 | { id: v } | This query object depends on a $@. | typedClient.ts:21:22:21:29 | req.body | user-provided value | +| typedClient.ts:23:27:23:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:23:27:23:35 | { id: v } | This query object depends on a $@. | typedClient.ts:21:22:21:29 | req.body | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index be40ab490ad..6eba7711032 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -928,128 +928,128 @@ edges | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | #select -| graphql.js:10:34:20:5 | `\\n ... }\\n ` | graphql.js:8:16:8:28 | req.params.id | graphql.js:10:34:20:5 | `\\n ... }\\n ` | This query depends on a $@. | graphql.js:8:16:8:28 | req.params.id | user-provided value | -| graphql.js:27:30:27:40 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:27:30:27:40 | `foo ${id}` | This query depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | -| graphql.js:30:32:30:42 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:30:32:30:42 | `foo ${id}` | This query depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | -| graphql.js:33:18:33:28 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:33:18:33:28 | `foo ${id}` | This query depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | -| graphql.js:44:14:44:24 | `foo ${id}` | graphql.js:39:16:39:28 | req.params.id | graphql.js:44:14:44:24 | `foo ${id}` | This query depends on a $@. | graphql.js:39:16:39:28 | req.params.id | user-provided value | -| graphql.js:48:44:48:54 | `foo ${id}` | graphql.js:39:16:39:28 | req.params.id | graphql.js:48:44:48:54 | `foo ${id}` | This query depends on a $@. | graphql.js:39:16:39:28 | req.params.id | user-provided value | -| graphql.js:56:39:56:49 | `foo ${id}` | graphql.js:55:16:55:28 | req.params.id | graphql.js:56:39:56:49 | `foo ${id}` | This query depends on a $@. | graphql.js:55:16:55:28 | req.params.id | user-provided value | -| graphql.js:58:66:58:76 | `foo ${id}` | graphql.js:55:16:55:28 | req.params.id | graphql.js:58:66:58:76 | `foo ${id}` | This query depends on a $@. | graphql.js:55:16:55:28 | req.params.id | user-provided value | -| graphql.js:75:46:75:64 | "{ foo" + id + " }" | graphql.js:74:14:74:25 | req.query.id | graphql.js:75:46:75:64 | "{ foo" + id + " }" | This query depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value | -| graphql.js:84:14:90:8 | `{\\n ... }` | graphql.js:74:14:74:25 | req.query.id | graphql.js:84:14:90:8 | `{\\n ... }` | This query depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value | -| graphql.js:120:38:120:48 | `foo ${id}` | graphql.js:119:16:119:28 | req.params.id | graphql.js:120:38:120:48 | `foo ${id}` | This query depends on a $@. | graphql.js:119:16:119:28 | req.params.id | user-provided value | -| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | This query depends on a $@. | html-sanitizer.js:13:39:13:44 | param1 | user-provided value | -| json-schema-validator.js:33:22:33:26 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:33:22:33:26 | query | This query depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value | -| json-schema-validator.js:35:18:35:22 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:35:18:35:22 | query | This query depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value | -| json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | -| json-schema-validator.js:59:22:59:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:59:22:59:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | -| json-schema-validator.js:61:22:61:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:61:22:61:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | -| ldap.js:28:30:28:34 | opts1 | ldap.js:20:21:20:27 | req.url | ldap.js:28:30:28:34 | opts1 | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | -| ldap.js:32:5:32:61 | { filte ... e}))` } | ldap.js:20:21:20:27 | req.url | ldap.js:32:5:32:61 | { filte ... e}))` } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | -| ldap.js:66:30:66:53 | { filte ... ilter } | ldap.js:20:21:20:27 | req.url | ldap.js:66:30:66:53 | { filte ... ilter } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | -| ldap.js:68:27:68:42 | `cn=${username}` | ldap.js:20:21:20:27 | req.url | ldap.js:68:27:68:42 | `cn=${username}` | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | -| marsdb-flow-to.js:14:17:14:21 | query | marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:14:17:14:21 | query | This query depends on a $@. | marsdb-flow-to.js:11:17:11:24 | req.body | user-provided value | -| marsdb.js:16:12:16:16 | query | marsdb.js:13:17:13:24 | req.body | marsdb.js:16:12:16:16 | query | This query depends on a $@. | marsdb.js:13:17:13:24 | req.body | user-provided value | -| minimongo.js:18:12:18:16 | query | minimongo.js:15:17:15:24 | req.body | minimongo.js:18:12:18:16 | query | This query depends on a $@. | minimongo.js:15:17:15:24 | req.body | user-provided value | -| mongodb.js:18:16:18:20 | query | mongodb.js:13:19:13:26 | req.body | mongodb.js:18:16:18:20 | query | This query depends on a $@. | mongodb.js:13:19:13:26 | req.body | user-provided value | -| mongodb.js:32:18:32:45 | { title ... itle) } | mongodb.js:26:19:26:26 | req.body | mongodb.js:32:18:32:45 | { title ... itle) } | This query depends on a $@. | mongodb.js:26:19:26:26 | req.body | user-provided value | -| mongodb.js:54:16:54:20 | query | mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | This query depends on a $@. | mongodb.js:49:19:49:33 | req.query.title | user-provided value | -| mongodb.js:65:12:65:16 | query | mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query | This query depends on a $@. | mongodb.js:60:16:60:30 | req.query.title | user-provided value | -| mongodb.js:77:14:77:26 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:77:14:77:26 | { tags: tag } | This query depends on a $@. | mongodb.js:70:13:70:25 | req.query.tag | user-provided value | -| mongodb.js:85:12:85:24 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:85:12:85:24 | { tags: tag } | This query depends on a $@. | mongodb.js:70:13:70:25 | req.query.tag | user-provided value | -| mongodb.js:112:14:112:18 | query | mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | This query depends on a $@. | mongodb.js:107:17:107:29 | queries.title | user-provided value | -| mongodb_bodySafe.js:29:16:29:20 | query | mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | This query depends on a $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | user-provided value | -| mongoose.js:24:24:24:30 | [query] | mongoose.js:21:19:21:26 | req.body | mongoose.js:24:24:24:30 | [query] | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:27:20:27:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:27:20:27:24 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:30:25:30:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:30:25:30:29 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:33:24:33:28 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:33:24:33:28 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:36:31:36:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:36:31:36:35 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:39:19:39:23 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:39:19:39:23 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:42:22:42:26 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:42:22:42:26 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:45:31:45:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:45:31:45:35 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:48:31:48:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:48:31:48:35 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:51:31:51:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:51:31:51:35 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:54:25:54:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:54:25:54:29 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:57:21:57:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:57:21:57:25 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:60:25:60:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:60:25:60:29 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:63:21:63:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:63:21:63:25 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:65:32:65:36 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:65:32:65:36 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:67:27:67:31 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:67:27:67:31 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:68:8:68:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:68:8:68:12 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:71:20:71:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:71:20:71:24 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:72:16:72:20 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:72:16:72:20 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:73:8:73:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:73:8:73:12 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:74:7:74:11 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:74:7:74:11 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:75:16:75:20 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:75:16:75:20 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:77:10:77:14 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:77:10:77:14 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:82:46:82:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:82:46:82:50 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:83:47:83:51 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:83:47:83:51 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:85:46:85:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:85:46:85:50 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:87:51:87:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:87:51:87:55 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:89:46:89:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:89:46:89:50 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:92:46:92:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:92:46:92:50 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:94:51:94:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:94:51:94:55 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:96:46:96:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:96:46:96:50 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:111:14:111:18 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:111:14:111:18 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:113:31:113:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:113:31:113:35 | query | This query depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | -| mongoose.js:116:22:116:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:116:22:116:25 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:117:21:117:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:117:21:117:24 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:118:21:118:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:118:21:118:24 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:119:18:119:21 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:119:18:119:21 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:120:22:120:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:120:22:120:25 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:121:16:121:19 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:121:16:121:19 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:122:19:122:22 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:122:19:122:22 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:123:20:123:21 | id | mongoose.js:115:11:115:22 | req.query.id | mongoose.js:123:20:123:21 | id | This query depends on a $@. | mongoose.js:115:11:115:22 | req.query.id | user-provided value | -| mongoose.js:124:28:124:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:124:28:124:31 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:125:28:125:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:125:28:125:31 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:126:28:126:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:126:28:126:31 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:127:18:127:21 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:127:18:127:21 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:128:22:128:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:128:22:128:25 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:129:21:129:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:129:21:129:24 | cond | This query depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | -| mongoose.js:130:16:130:26 | { _id: id } | mongoose.js:115:11:115:22 | req.query.id | mongoose.js:130:16:130:26 | { _id: id } | This query depends on a $@. | mongoose.js:115:11:115:22 | req.query.id | user-provided value | -| mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query depends on a $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | user-provided value | -| mongooseModelClient.js:11:16:11:24 | { id: v } | mongooseModelClient.js:10:22:10:29 | req.body | mongooseModelClient.js:11:16:11:24 | { id: v } | This query depends on a $@. | mongooseModelClient.js:10:22:10:29 | req.body | user-provided value | -| mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | This query depends on a $@. | mongooseModelClient.js:12:22:12:29 | req.body | user-provided value | -| mysql.js:15:18:15:65 | 'SELECT ... + temp | mysql.js:6:16:6:31 | req.params.value | mysql.js:15:18:15:65 | 'SELECT ... + temp | This query depends on a $@. | mysql.js:6:16:6:31 | req.params.value | user-provided value | -| mysql.js:19:26:19:73 | 'SELECT ... + temp | mysql.js:6:16:6:31 | req.params.value | mysql.js:19:26:19:73 | 'SELECT ... + temp | This query depends on a $@. | mysql.js:6:16:6:31 | req.params.value | user-provided value | -| pg-promise-types.ts:8:17:8:21 | taint | pg-promise-types.ts:7:17:7:28 | req.params.x | pg-promise-types.ts:8:17:8:21 | taint | This query depends on a $@. | pg-promise-types.ts:7:17:7:28 | req.params.x | user-provided value | -| pg-promise.js:9:10:9:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:9:10:9:14 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:10:11:10:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:10:11:10:15 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:11:17:11:21 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:11:17:11:21 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:12:10:12:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:12:10:12:14 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:13:12:13:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:13:12:13:16 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:14:18:14:22 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:14:18:14:22 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:15:11:15:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:15:11:15:15 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:16:10:16:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:16:10:16:14 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:17:16:17:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:17:16:17:20 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:18:12:18:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:18:12:18:16 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:19:13:19:17 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:19:13:19:17 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:22:11:22:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:22:11:22:15 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | This query depends on a $@. | pg-promise.js:30:13:30:25 | req.params.id | user-provided value | -| pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | This query depends on a $@. | pg-promise.js:34:13:34:25 | req.params.id | user-provided value | -| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on a $@. | pg-promise.js:39:7:39:19 | req.params.id | user-provided value | -| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on a $@. | pg-promise.js:40:7:40:21 | req.params.name | user-provided value | -| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query depends on a $@. | pg-promise.js:41:7:41:20 | req.params.foo | user-provided value | -| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | This query depends on a $@. | pg-promise.js:39:7:39:19 | req.params.id | user-provided value | -| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | This query depends on a $@. | pg-promise.js:40:7:40:21 | req.params.name | user-provided value | -| pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | This query depends on a $@. | pg-promise.js:47:11:47:23 | req.params.id | user-provided value | -| pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | This query depends on a $@. | pg-promise.js:54:11:54:23 | req.params.id | user-provided value | -| pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | This query depends on a $@. | pg-promise.js:56:14:56:29 | req.params.title | user-provided value | -| pg-promise.js:60:20:60:24 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:60:20:60:24 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:63:23:63:27 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:63:23:63:27 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| pg-promise.js:64:16:64:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:64:16:64:20 | query | This query depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | -| redis.js:10:16:10:27 | req.body.key | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | This query depends on a $@. | redis.js:10:16:10:23 | req.body | user-provided value | -| redis.js:18:16:18:18 | key | redis.js:12:15:12:22 | req.body | redis.js:18:16:18:18 | key | This query depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | -| redis.js:19:43:19:45 | key | redis.js:12:15:12:22 | req.body | redis.js:19:43:19:45 | key | This query depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | -| redis.js:25:14:25:16 | key | redis.js:12:15:12:22 | req.body | redis.js:25:14:25:16 | key | This query depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | -| redis.js:30:23:30:25 | key | redis.js:12:15:12:22 | req.body | redis.js:30:23:30:25 | key | This query depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | -| redis.js:32:28:32:30 | key | redis.js:12:15:12:22 | req.body | redis.js:32:28:32:30 | key | This query depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | -| redis.js:39:16:39:18 | key | redis.js:38:17:38:24 | req.body | redis.js:39:16:39:18 | key | This query depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | -| redis.js:43:27:43:29 | key | redis.js:38:17:38:24 | req.body | redis.js:43:27:43:29 | key | This query depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | -| redis.js:46:34:46:36 | key | redis.js:38:17:38:24 | req.body | redis.js:46:34:46:36 | key | This query depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | -| socketio.js:11:12:11:53 | `INSERT ... andle}` | socketio.js:10:25:10:30 | handle | socketio.js:11:12:11:53 | `INSERT ... andle}` | This query depends on a $@. | socketio.js:10:25:10:30 | handle | user-provided value | -| tst2.js:9:27:9:84 | "select ... d + "'" | tst2.js:9:66:9:78 | req.params.id | tst2.js:9:27:9:84 | "select ... d + "'" | This query depends on a $@. | tst2.js:9:66:9:78 | req.params.id | user-provided value | -| tst3.js:9:14:9:19 | query1 | tst3.js:8:16:8:34 | req.params.category | tst3.js:9:14:9:19 | query1 | This query depends on a $@. | tst3.js:8:16:8:34 | req.params.category | user-provided value | -| tst4.js:8:10:8:66 | 'SELECT ... d + '"' | tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | This query depends on a $@. | tst4.js:8:46:8:60 | $routeParams.id | user-provided value | -| tst.js:10:10:10:64 | 'SELECT ... d + '"' | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | This query depends on a $@. | tst.js:10:46:10:58 | req.params.id | user-provided value | +| graphql.js:10:34:20:5 | `\\n ... }\\n ` | graphql.js:8:16:8:28 | req.params.id | graphql.js:10:34:20:5 | `\\n ... }\\n ` | This query string depends on a $@. | graphql.js:8:16:8:28 | req.params.id | user-provided value | +| graphql.js:27:30:27:40 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:27:30:27:40 | `foo ${id}` | This query string depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | +| graphql.js:30:32:30:42 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:30:32:30:42 | `foo ${id}` | This query string depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | +| graphql.js:33:18:33:28 | `foo ${id}` | graphql.js:26:16:26:28 | req.params.id | graphql.js:33:18:33:28 | `foo ${id}` | This query string depends on a $@. | graphql.js:26:16:26:28 | req.params.id | user-provided value | +| graphql.js:44:14:44:24 | `foo ${id}` | graphql.js:39:16:39:28 | req.params.id | graphql.js:44:14:44:24 | `foo ${id}` | This query string depends on a $@. | graphql.js:39:16:39:28 | req.params.id | user-provided value | +| graphql.js:48:44:48:54 | `foo ${id}` | graphql.js:39:16:39:28 | req.params.id | graphql.js:48:44:48:54 | `foo ${id}` | This query string depends on a $@. | graphql.js:39:16:39:28 | req.params.id | user-provided value | +| graphql.js:56:39:56:49 | `foo ${id}` | graphql.js:55:16:55:28 | req.params.id | graphql.js:56:39:56:49 | `foo ${id}` | This query string depends on a $@. | graphql.js:55:16:55:28 | req.params.id | user-provided value | +| graphql.js:58:66:58:76 | `foo ${id}` | graphql.js:55:16:55:28 | req.params.id | graphql.js:58:66:58:76 | `foo ${id}` | This query string depends on a $@. | graphql.js:55:16:55:28 | req.params.id | user-provided value | +| graphql.js:75:46:75:64 | "{ foo" + id + " }" | graphql.js:74:14:74:25 | req.query.id | graphql.js:75:46:75:64 | "{ foo" + id + " }" | This query string depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value | +| graphql.js:84:14:90:8 | `{\\n ... }` | graphql.js:74:14:74:25 | req.query.id | graphql.js:84:14:90:8 | `{\\n ... }` | This query string depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value | +| graphql.js:120:38:120:48 | `foo ${id}` | graphql.js:119:16:119:28 | req.params.id | graphql.js:120:38:120:48 | `foo ${id}` | This query string depends on a $@. | graphql.js:119:16:119:28 | req.params.id | user-provided value | +| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | This query string depends on a $@. | html-sanitizer.js:13:39:13:44 | param1 | user-provided value | +| json-schema-validator.js:33:22:33:26 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:33:22:33:26 | query | This query object depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value | +| json-schema-validator.js:35:18:35:22 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:35:18:35:22 | query | This query object depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value | +| json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | +| json-schema-validator.js:59:22:59:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:59:22:59:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | +| json-schema-validator.js:61:22:61:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:61:22:61:26 | query | This query object depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | +| ldap.js:28:30:28:34 | opts1 | ldap.js:20:21:20:27 | req.url | ldap.js:28:30:28:34 | opts1 | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | +| ldap.js:32:5:32:61 | { filte ... e}))` } | ldap.js:20:21:20:27 | req.url | ldap.js:32:5:32:61 | { filte ... e}))` } | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | +| ldap.js:66:30:66:53 | { filte ... ilter } | ldap.js:20:21:20:27 | req.url | ldap.js:66:30:66:53 | { filte ... ilter } | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | +| ldap.js:68:27:68:42 | `cn=${username}` | ldap.js:20:21:20:27 | req.url | ldap.js:68:27:68:42 | `cn=${username}` | This query string depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | +| marsdb-flow-to.js:14:17:14:21 | query | marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:14:17:14:21 | query | This query object depends on a $@. | marsdb-flow-to.js:11:17:11:24 | req.body | user-provided value | +| marsdb.js:16:12:16:16 | query | marsdb.js:13:17:13:24 | req.body | marsdb.js:16:12:16:16 | query | This query object depends on a $@. | marsdb.js:13:17:13:24 | req.body | user-provided value | +| minimongo.js:18:12:18:16 | query | minimongo.js:15:17:15:24 | req.body | minimongo.js:18:12:18:16 | query | This query object depends on a $@. | minimongo.js:15:17:15:24 | req.body | user-provided value | +| mongodb.js:18:16:18:20 | query | mongodb.js:13:19:13:26 | req.body | mongodb.js:18:16:18:20 | query | This query object depends on a $@. | mongodb.js:13:19:13:26 | req.body | user-provided value | +| mongodb.js:32:18:32:45 | { title ... itle) } | mongodb.js:26:19:26:26 | req.body | mongodb.js:32:18:32:45 | { title ... itle) } | This query object depends on a $@. | mongodb.js:26:19:26:26 | req.body | user-provided value | +| mongodb.js:54:16:54:20 | query | mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | This query object depends on a $@. | mongodb.js:49:19:49:33 | req.query.title | user-provided value | +| mongodb.js:65:12:65:16 | query | mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query | This query object depends on a $@. | mongodb.js:60:16:60:30 | req.query.title | user-provided value | +| mongodb.js:77:14:77:26 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:77:14:77:26 | { tags: tag } | This query object depends on a $@. | mongodb.js:70:13:70:25 | req.query.tag | user-provided value | +| mongodb.js:85:12:85:24 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:85:12:85:24 | { tags: tag } | This query object depends on a $@. | mongodb.js:70:13:70:25 | req.query.tag | user-provided value | +| mongodb.js:112:14:112:18 | query | mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | This query object depends on a $@. | mongodb.js:107:17:107:29 | queries.title | user-provided value | +| mongodb_bodySafe.js:29:16:29:20 | query | mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | This query object depends on a $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | user-provided value | +| mongoose.js:24:24:24:30 | [query] | mongoose.js:21:19:21:26 | req.body | mongoose.js:24:24:24:30 | [query] | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:27:20:27:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:27:20:27:24 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:30:25:30:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:30:25:30:29 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:33:24:33:28 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:33:24:33:28 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:36:31:36:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:36:31:36:35 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:39:19:39:23 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:39:19:39:23 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:42:22:42:26 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:42:22:42:26 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:45:31:45:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:45:31:45:35 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:48:31:48:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:48:31:48:35 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:51:31:51:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:51:31:51:35 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:54:25:54:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:54:25:54:29 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:57:21:57:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:57:21:57:25 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:60:25:60:29 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:60:25:60:29 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:63:21:63:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:63:21:63:25 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:65:32:65:36 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:65:32:65:36 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:67:27:67:31 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:67:27:67:31 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:68:8:68:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:68:8:68:12 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:71:20:71:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:71:20:71:24 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:72:16:72:20 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:72:16:72:20 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:73:8:73:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:73:8:73:12 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:74:7:74:11 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:74:7:74:11 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:75:16:75:20 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:75:16:75:20 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:77:10:77:14 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:77:10:77:14 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:82:46:82:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:82:46:82:50 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:83:47:83:51 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:83:47:83:51 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:85:46:85:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:85:46:85:50 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:87:51:87:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:87:51:87:55 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:89:46:89:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:89:46:89:50 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:92:46:92:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:92:46:92:50 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:94:51:94:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:94:51:94:55 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:96:46:96:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:96:46:96:50 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:111:14:111:18 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:111:14:111:18 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:113:31:113:35 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:113:31:113:35 | query | This query object depends on a $@. | mongoose.js:21:19:21:26 | req.body | user-provided value | +| mongoose.js:116:22:116:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:116:22:116:25 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:117:21:117:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:117:21:117:24 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:118:21:118:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:118:21:118:24 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:119:18:119:21 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:119:18:119:21 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:120:22:120:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:120:22:120:25 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:121:16:121:19 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:121:16:121:19 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:122:19:122:22 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:122:19:122:22 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:123:20:123:21 | id | mongoose.js:115:11:115:22 | req.query.id | mongoose.js:123:20:123:21 | id | This query object depends on a $@. | mongoose.js:115:11:115:22 | req.query.id | user-provided value | +| mongoose.js:124:28:124:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:124:28:124:31 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:125:28:125:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:125:28:125:31 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:126:28:126:31 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:126:28:126:31 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:127:18:127:21 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:127:18:127:21 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:128:22:128:25 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:128:22:128:25 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:129:21:129:24 | cond | mongoose.js:115:32:115:45 | req.query.cond | mongoose.js:129:21:129:24 | cond | This query object depends on a $@. | mongoose.js:115:32:115:45 | req.query.cond | user-provided value | +| mongoose.js:130:16:130:26 | { _id: id } | mongoose.js:115:11:115:22 | req.query.id | mongoose.js:130:16:130:26 | { _id: id } | This query object depends on a $@. | mongoose.js:115:11:115:22 | req.query.id | user-provided value | +| mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query object depends on a $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | user-provided value | +| mongooseModelClient.js:11:16:11:24 | { id: v } | mongooseModelClient.js:10:22:10:29 | req.body | mongooseModelClient.js:11:16:11:24 | { id: v } | This query object depends on a $@. | mongooseModelClient.js:10:22:10:29 | req.body | user-provided value | +| mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | This query object depends on a $@. | mongooseModelClient.js:12:22:12:29 | req.body | user-provided value | +| mysql.js:15:18:15:65 | 'SELECT ... + temp | mysql.js:6:16:6:31 | req.params.value | mysql.js:15:18:15:65 | 'SELECT ... + temp | This query string depends on a $@. | mysql.js:6:16:6:31 | req.params.value | user-provided value | +| mysql.js:19:26:19:73 | 'SELECT ... + temp | mysql.js:6:16:6:31 | req.params.value | mysql.js:19:26:19:73 | 'SELECT ... + temp | This query string depends on a $@. | mysql.js:6:16:6:31 | req.params.value | user-provided value | +| pg-promise-types.ts:8:17:8:21 | taint | pg-promise-types.ts:7:17:7:28 | req.params.x | pg-promise-types.ts:8:17:8:21 | taint | This query string depends on a $@. | pg-promise-types.ts:7:17:7:28 | req.params.x | user-provided value | +| pg-promise.js:9:10:9:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:9:10:9:14 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:10:11:10:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:10:11:10:15 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:11:17:11:21 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:11:17:11:21 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:12:10:12:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:12:10:12:14 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:13:12:13:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:13:12:13:16 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:14:18:14:22 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:14:18:14:22 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:15:11:15:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:15:11:15:15 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:16:10:16:14 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:16:10:16:14 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:17:16:17:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:17:16:17:20 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:18:12:18:16 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:18:12:18:16 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:19:13:19:17 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:19:13:19:17 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:22:11:22:15 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:22:11:22:15 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | pg-promise.js:30:13:30:25 | req.params.id | This query string depends on a $@. | pg-promise.js:30:13:30:25 | req.params.id | user-provided value | +| pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | pg-promise.js:34:13:34:25 | req.params.id | This query string depends on a $@. | pg-promise.js:34:13:34:25 | req.params.id | user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query string depends on a $@. | pg-promise.js:39:7:39:19 | req.params.id | user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query string depends on a $@. | pg-promise.js:40:7:40:21 | req.params.name | user-provided value | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | This query string depends on a $@. | pg-promise.js:41:7:41:20 | req.params.foo | user-provided value | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:39:7:39:19 | req.params.id | This query string depends on a $@. | pg-promise.js:39:7:39:19 | req.params.id | user-provided value | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:40:7:40:21 | req.params.name | This query string depends on a $@. | pg-promise.js:40:7:40:21 | req.params.name | user-provided value | +| pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | pg-promise.js:47:11:47:23 | req.params.id | This query string depends on a $@. | pg-promise.js:47:11:47:23 | req.params.id | user-provided value | +| pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | pg-promise.js:54:11:54:23 | req.params.id | This query string depends on a $@. | pg-promise.js:54:11:54:23 | req.params.id | user-provided value | +| pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | pg-promise.js:56:14:56:29 | req.params.title | This query string depends on a $@. | pg-promise.js:56:14:56:29 | req.params.title | user-provided value | +| pg-promise.js:60:20:60:24 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:60:20:60:24 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:63:23:63:27 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:63:23:63:27 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| pg-promise.js:64:16:64:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:64:16:64:20 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| redis.js:10:16:10:27 | req.body.key | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | This query object depends on a $@. | redis.js:10:16:10:23 | req.body | user-provided value | +| redis.js:18:16:18:18 | key | redis.js:12:15:12:22 | req.body | redis.js:18:16:18:18 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | +| redis.js:19:43:19:45 | key | redis.js:12:15:12:22 | req.body | redis.js:19:43:19:45 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | +| redis.js:25:14:25:16 | key | redis.js:12:15:12:22 | req.body | redis.js:25:14:25:16 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | +| redis.js:30:23:30:25 | key | redis.js:12:15:12:22 | req.body | redis.js:30:23:30:25 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | +| redis.js:32:28:32:30 | key | redis.js:12:15:12:22 | req.body | redis.js:32:28:32:30 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | +| redis.js:39:16:39:18 | key | redis.js:38:17:38:24 | req.body | redis.js:39:16:39:18 | key | This query object depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | +| redis.js:43:27:43:29 | key | redis.js:38:17:38:24 | req.body | redis.js:43:27:43:29 | key | This query object depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | +| redis.js:46:34:46:36 | key | redis.js:38:17:38:24 | req.body | redis.js:46:34:46:36 | key | This query object depends on a $@. | redis.js:38:17:38:24 | req.body | user-provided value | +| socketio.js:11:12:11:53 | `INSERT ... andle}` | socketio.js:10:25:10:30 | handle | socketio.js:11:12:11:53 | `INSERT ... andle}` | This query string depends on a $@. | socketio.js:10:25:10:30 | handle | user-provided value | +| tst2.js:9:27:9:84 | "select ... d + "'" | tst2.js:9:66:9:78 | req.params.id | tst2.js:9:27:9:84 | "select ... d + "'" | This query string depends on a $@. | tst2.js:9:66:9:78 | req.params.id | user-provided value | +| tst3.js:9:14:9:19 | query1 | tst3.js:8:16:8:34 | req.params.category | tst3.js:9:14:9:19 | query1 | This query string depends on a $@. | tst3.js:8:16:8:34 | req.params.category | user-provided value | +| tst4.js:8:10:8:66 | 'SELECT ... d + '"' | tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | This query string depends on a $@. | tst4.js:8:46:8:60 | $routeParams.id | user-provided value | +| tst.js:10:10:10:64 | 'SELECT ... d + '"' | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | This query string depends on a $@. | tst.js:10:46:10:58 | req.params.id | user-provided value | From e24b45b4233724e6756057f87c04593bed583c5f Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 31 May 2023 09:57:38 +0200 Subject: [PATCH 078/219] elaborate on both SQL and NoSQL injection in the js/sql-injection qhelp --- .../Security/CWE-089/SqlInjection.inc.qhelp | 48 ++++++++++++++----- .../CWE-089/examples/NoSqlInjection.js | 18 +++++++ .../CWE-089/examples/NoSqlInjectionFix.js | 21 ++++++++ .../Security/CWE-089/examples/SqlInjection.js | 7 --- .../CWE-089/examples/SqlInjectionFix.js | 12 +++++ 5 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-089/examples/NoSqlInjection.js create mode 100644 javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js create mode 100644 javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index 8cdc2419d47..1d99428b718 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -20,7 +20,13 @@ or prepared statements. <p> For NoSQL queries, make use of an operator like MongoDB's <code>$eq</code> to ensure that untrusted data is interpreted as a literal value and not as -a query object. +a query object. Alternatively, check that the untrusted data is a literal +value and not a query object before using it in a query. +</p> +<p> +For SQL queries, use query parameters or prepared statements to +embed untrusted data into the query string, or use a library like +<code>sqlstring</code> to escape untrusted data. </p> </recommendation> @@ -32,31 +38,47 @@ an HTTP request handler in a web application, whose parameter </p> <p> -The handler constructs two copies of the same SQL query involving -user input taken from the request object, once unsafely using -string concatenation, and once safely using query parameters. +The handler constructs constructs an SQL query string from user input +and executes it as a database query using the <code>pg</code> library. +THe user input may contain quote characters, so this code is vulnerable +to a SQL injection attack. </p> -<p> -In the first case, the query string <code>query1</code> is built by -directly concatenating a user-supplied request parameter with some -string literals. The parameter may include quote characters, so this -code is vulnerable to a SQL injection attack. -</p> +<sample src="examples/SqlInjection.js" /> <p> -In the second case, the parameter is embedded into the query string -<code>query2</code> using query parameters. In this example, we use +To fix this vulnerability, we can use query parameters to embed the +user input into the query string. In this example, we use the API offered by the <code>pg</code> Postgres database connector library, but other libraries offer similar features. This version is immune to injection attacks. </p> -<sample src="examples/SqlInjection.js" /> +<sample src="examples/SqlInjectionFix.js" /> +</example> + +<example> +<p> +In the following example an express handler attempts to delete +a single document from a MongoDB collection. The document to be +deleted is identified by its <code>_id</code> field, which is +constructed from user input. The user input may contain a query +object, so this code is vulnerable to a NoSQL injection attack. +</p> + +<sample src="examples/NoSqlInjection.js" /> + +<p> +To fix this vulnerability, we can check that the user input is a +literal value and not a query object before using it in a query. +</p> + +<sample src="examples/NoSqlInjectionFix.js" /> </example> <references> <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/SQL_injection">SQL injection</a>.</li> <li>MongoDB: <a href="https://docs.mongodb.com/manual/reference/operator/query/eq">$eq operator</a>.</li> +<li>OWASP: <a href="https://owasp.org/www-pdf-archive/GOD16-NOSQL.pdf">NoSQL injection</a>.</li> </references> </qhelp> diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjection.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjection.js new file mode 100644 index 00000000000..8af7550aee4 --- /dev/null +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjection.js @@ -0,0 +1,18 @@ +const express = require("express"); +const mongoose = require("mongoose"); +const Todo = mongoose.model( + "Todo", + new mongoose.Schema({ text: { type: String } }, { timestamps: true }) +); + +const app = express(); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); + +app.delete("/api/delete", async (req, res) => { + let id = req.body.id; + + await Todo.deleteOne({ _id: id }); // BAD: id might be an object with special properties + + res.json({ status: "ok" }); +}); diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js new file mode 100644 index 00000000000..fe982168be1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js @@ -0,0 +1,21 @@ +const express = require("express"); +const mongoose = require("mongoose"); +const Todo = mongoose.model( + "Todo", + new mongoose.Schema({ text: { type: String } }, { timestamps: true }) +); + +const app = express(); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); + +app.delete("/api/delete", async (req, res) => { + let id = req.body.id; + if (typeof id !== "string") { + res.status(400).json({ status: "error" }); + return; + } + await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string + + res.json({ status: "ok" }); +}); diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js index 113a034219c..9c9197e6f58 100644 --- a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js @@ -11,11 +11,4 @@ app.get("search", function handler(req, res) { pool.query(query1, [], function(err, results) { // process results }); - - // GOOD: use parameters - var query2 = - "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; - pool.query(query2, [req.params.category], function(err, results) { - // process results - }); }); diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js new file mode 100644 index 00000000000..4391b83e391 --- /dev/null +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js @@ -0,0 +1,12 @@ +const app = require("express")(), + pg = require("pg"), + pool = new pg.Pool(config); + +app.get("search", function handler(req, res) { + // GOOD: use parameters + var query2 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; + pool.query(query2, [req.params.category], function(err, results) { + // process results + }); +}); From daad2e1bd38756b3f6510f0939b6b0f4676d7707 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 31 May 2023 10:46:25 +0100 Subject: [PATCH 079/219] Swift: Use regexp for function name. --- swift/ql/lib/codeql/swift/elements/decl/Function.qll | 10 ++++++++++ swift/ql/lib/codeql/swift/security/SensitiveExprs.qll | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/elements/decl/Function.qll b/swift/ql/lib/codeql/swift/elements/decl/Function.qll index ad1fa957d94..7fc5b5b2155 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/Function.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/Function.qll @@ -6,6 +6,16 @@ private import codeql.swift.elements.decl.Method */ class Function extends Generated::Function, Callable { override string toString() { result = this.getName() } + + /** + * Gets the name of this function, without the argument list. For example + * a function with name `myFunction(arg:)` has short name `myFunction`. + */ + string getShortName() { + // match as many characters as possible that are not `(`. + // (`*+` is possessive matching) + result = this.getName().regexpCapture("([^(]*+).*", 1) + } } /** diff --git a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll index d750e673121..a991f8e2c37 100644 --- a/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll +++ b/swift/ql/lib/codeql/swift/security/SensitiveExprs.qll @@ -102,7 +102,7 @@ private class SensitiveFunction extends Function { string name; // name of the function, not including the argument list. SensitiveFunction() { - name = this.getName().splitAt("(", 0) and + name = this.getShortName() and name.regexpMatch(sensitiveType.getRegexp()) } From caf250cc1b18bc4000b3a2dd8353664c61b33450 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 31 May 2023 12:54:42 +0100 Subject: [PATCH 080/219] Swift: Update the QLdoc on Callable. --- swift/ql/.generated.list | 4 ++-- swift/ql/lib/codeql/swift/generated/Callable.qll | 2 ++ swift/ql/lib/codeql/swift/generated/Raw.qll | 2 ++ swift/schema.py | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/swift/ql/.generated.list b/swift/ql/.generated.list index 53847acba54..523796c28ad 100644 --- a/swift/ql/.generated.list +++ b/swift/ql/.generated.list @@ -369,7 +369,7 @@ lib/codeql/swift/elements.qll 3df0060edd2b2030f4e4d7d5518afe0073d798474d9b1d6185 lib/codeql/swift/generated/AstNode.qll 02ca56d82801f942ae6265c6079d92ccafdf6b532f6bcebd98a04029ddf696e4 6216fda240e45bd4302fa0cf0f08f5f945418b144659264cdda84622b0420aa2 lib/codeql/swift/generated/AvailabilityInfo.qll c648a66cf45414c85cf9cc69aa05b765a49d0c18cd9c101c34f99a9adc38a1ee 54ba7b07b4177d35e85d19363aa7adcda29cda185a5818e5fcb7c678c093e0ba lib/codeql/swift/generated/AvailabilitySpec.qll fb1255f91bb5e41ad4e9c675a2efbc50d0fb366ea2de68ab7eebd177b0795309 144e0c2e7d6c62ecee43325f7f26dcf437881edf0b75cc1bc898c6c4b61fdeaf -lib/codeql/swift/generated/Callable.qll 9dcf09a2f227dd6f569f007a07fb368d6b928ffd002535bb97118361430d948c 5c203f5f6b4f8b6748e61e09bb46c55442a2fb36f2d1fa950e6f81bdda562709 +lib/codeql/swift/generated/Callable.qll aaa3a8fbf04cb1be4c99de917353dd3a56ce1bce97af745e4c922957b7480e44 1896c0fb1690aef99accdaba0fd906549f5a971d9f663945e4ca6d6e2a21e2e4 lib/codeql/swift/generated/Comment.qll f58b49f6e68c21f87c51e2ff84c8a64b09286d733e86f70d67d3a98fe6260bd6 975bbb599a2a7adc35179f6ae06d9cbc56ea8a03b972ef2ee87604834bc6deb1 lib/codeql/swift/generated/DbFile.qll a49b2a2cb2788cb49c861ebcd458b8daead7b15adb19c3a9f4db3bf39a0051fc a49b2a2cb2788cb49c861ebcd458b8daead7b15adb19c3a9f4db3bf39a0051fc lib/codeql/swift/generated/DbLocation.qll b9baea963d9fa82068986512c0649d1050897654eee3df51dba17cf6b1170873 b9baea963d9fa82068986512c0649d1050897654eee3df51dba17cf6b1170873 @@ -384,7 +384,7 @@ lib/codeql/swift/generated/OtherAvailabilitySpec.qll 0e26a203b26ff0581b7396b0c6d lib/codeql/swift/generated/ParentChild.qll 01b27b48a12955a45ea26d0f7888a160faac9fd5fb57a19e87365318e9b21a30 88090ef26a7ce63f4ba88fa735e2c8207fd1de00076532083d93a7a02553797e lib/codeql/swift/generated/PlatformVersionAvailabilitySpec.qll f82d9ca416fe8bd59b5531b65b1c74c9f317b3297a6101544a11339a1cffce38 7f5c6d3309e66c134107afe55bae76dfc9a72cb7cdd6d4c3706b6b34cee09fa0 lib/codeql/swift/generated/PureSynthConstructors.qll 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98 -lib/codeql/swift/generated/Raw.qll 13cf09f9b2f628831b6b715448779366959a4c44b1b5ffc97397654fc8620486 03d60bdb6543d87a83ca50a3977c98c08d936d435981ae0b373f98ecde7a142b +lib/codeql/swift/generated/Raw.qll 5715979160eac96fe4b54b73cdb88958617b9e3d66928c61029a12fab1c25902 5dbaaf2e03512107fc6e533d1388b7e6c8104ec5bcc43781256d67750d841ce8 lib/codeql/swift/generated/Synth.qll 551fdf7e4b53f9ee1314d1bb42c2638cf82f45bfa1f40a635dfa7b6072e4418c 9ab178464700a19951fc5285acacda4913addee81515d8e072b3d7055935a814 lib/codeql/swift/generated/SynthConstructors.qll 2f801bd8b0db829b0253cd459ed3253c1fdfc55dce68ebc53e7fec138ef0aca4 2f801bd8b0db829b0253cd459ed3253c1fdfc55dce68ebc53e7fec138ef0aca4 lib/codeql/swift/generated/UnknownFile.qll 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6 diff --git a/swift/ql/lib/codeql/swift/generated/Callable.qll b/swift/ql/lib/codeql/swift/generated/Callable.qll index db03af1dbd0..2cfcdeb5c11 100644 --- a/swift/ql/lib/codeql/swift/generated/Callable.qll +++ b/swift/ql/lib/codeql/swift/generated/Callable.qll @@ -10,6 +10,8 @@ module Generated { class Callable extends Synth::TCallable, Element { /** * Gets the name of this callable, if it exists. + * + * The name includes any arguments of the callable, for example `myFunction(arg:)`. */ string getName() { result = Synth::convertCallableToRaw(this).(Raw::Callable).getName() } diff --git a/swift/ql/lib/codeql/swift/generated/Raw.qll b/swift/ql/lib/codeql/swift/generated/Raw.qll index 8ebecc81a15..05e46d484b3 100644 --- a/swift/ql/lib/codeql/swift/generated/Raw.qll +++ b/swift/ql/lib/codeql/swift/generated/Raw.qll @@ -21,6 +21,8 @@ module Raw { class Callable extends @callable, Element { /** * Gets the name of this callable, if it exists. + * + * The name includes any arguments of the callable, for example `myFunction(arg:)`. */ string getName() { callable_names(this, result) } diff --git a/swift/schema.py b/swift/schema.py index ef2c357899f..0ca1e25a6a3 100644 --- a/swift/schema.py +++ b/swift/schema.py @@ -228,7 +228,8 @@ class ParamDecl(VarDecl): """) class Callable(Element): - name: optional[string] | doc("name of this callable") + name: optional[string] | doc("name of this callable") | desc("The name includes any arguments " + "of the callable, for example `myFunction(arg:)`.") self_param: optional[ParamDecl] | child params: list[ParamDecl] | child body: optional["BraceStmt"] | child | desc("The body is absent within protocol declarations.") From 43d6bf04b5c07a0fe8214bfa02b0383b09a6f703 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Fri, 26 May 2023 11:32:12 +0200 Subject: [PATCH 081/219] C#: Make synthetic implicit casts when values are provided using the DefaultParameterValue attribute. --- .../Entities/Expression.cs | 5 ++ .../Entities/Expressions/ImplicitCast.cs | 74 +++++++++++++++---- .../SymbolExtensions.cs | 2 +- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 698be2e2c35..a77c0b30095 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -211,6 +211,11 @@ namespace Semmle.Extraction.CSharp.Entities return Default.CreateGenerated(cx, parent, childIndex, location, ValueAsString(null)); } + if (type.SpecialType is SpecialType.None) + { + return ImplicitCast.CreateGenerated(cx, parent, childIndex, type, defaultValue, location); + } + if (type.SpecialType is SpecialType.System_DateTime) { return DateTimeObjectCreation.CreateGenerated(cx, parent, childIndex, type, defaultValue, location); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index 2d617cdb1b9..20daedc0ae8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -1,3 +1,4 @@ +using System.Linq; using Microsoft.CodeAnalysis; using Semmle.Extraction.Kinds; @@ -11,33 +12,74 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private set; } - public ImplicitCast(ExpressionNodeInfo info) + private ImplicitCast(ExpressionNodeInfo info) : base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue)) { Expr = Factory.Create(new ExpressionNodeInfo(Context, info.Node, this, 0)); } - public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) + private ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) : base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue)) { Expr = Factory.Create(info.SetParent(this, 0)); - var target = Method.Create(Context, method); - if (target is not null) - Context.TrapWriter.Writer.expr_call(this, target); - else - Context.ModelError(info.Node, "Failed to resolve target for operator invocation"); + AddOperatorCall(method); } - /// <summary> - /// Creates a new expression, adding casts as required. - /// </summary> - /// <param name="cx">The extraction context.</param> - /// <param name="node">The expression node.</param> - /// <param name="parent">The parent of the expression.</param> - /// <param name="child">The child number.</param> - /// <param name="type">A type hint.</param> - /// <returns>A new expression.</returns> + private ImplicitCast(ExpressionInfo info, IMethodSymbol method, object value) : base(info) + { + Expr = Literal.CreateGenerated(Context, this, 0, method.Parameters[0].Type, value, info.Location); + + AddOperatorCall(method); + } + + private void AddOperatorCall(IMethodSymbol method) + { + var target = Method.Create(Context, method); + Context.TrapWriter.Writer.expr_call(this, target); + } + + private static IMethodSymbol? GetImplicitConversionMethod(ITypeSymbol type, object value) => + type + .GetMembers() + .Where(m => + m is IMethodSymbol method && + method.GetName() == "op_Implicit" && + method.Parameters.Length == 1 && + method.Parameters[0].Type.Name == value.GetType().Name + ) + .Cast<IMethodSymbol>() + .FirstOrDefault(); + + // Creates a new generated expression with an implicit cast added, if needed. + public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value, + Extraction.Entities.Location location) + { + ExpressionInfo create(ExprKind kind, string? v) => + new ExpressionInfo( + cx, + AnnotatedTypeSymbol.CreateNotAnnotated(type), + location, + kind, + parent, + childIndex, + true, + v); + + var method = GetImplicitConversionMethod(type, value); + if (method is not null) + { + var info = create(ExprKind.OPERATOR_INVOCATION, null); + return new ImplicitCast(info, method, value); + } + else + { + cx.ModelError(location, "Failed to resolve target for implicit operator invocation for a parameter default."); + return new Expression(create(ExprKind.UNKNOWN, ValueAsString(value))); + } + } + + // Creates a new expression, adding casts as required. public static Expression Create(ExpressionNodeInfo info) { var resolvedType = info.ResolvedType; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index cd182fe4640..aaef1702532 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp Nullability = nullability; } - public static AnnotatedTypeSymbol? CreateNotAnnotated(ITypeSymbol symbol) => + public static AnnotatedTypeSymbol? CreateNotAnnotated(ITypeSymbol? symbol) => symbol is null ? (AnnotatedTypeSymbol?)null : new AnnotatedTypeSymbol(symbol, NullableAnnotation.None); } From 83a8e3bdbc1883f42ecc2a050d15315565c74824 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Fri, 26 May 2023 11:32:34 +0200 Subject: [PATCH 082/219] C#: Add some more testcases. --- .../library-tests/parameters/Parameters.cs | 9 ++++++- .../library-tests/parameters/Parameters.cs_ | 9 ++++++- .../library-tests/parameters/Parameters.dll | Bin 6144 -> 6144 bytes .../parameters/Parameters.expected | 13 +++++++++++ .../library-tests/parameters/Parameters.ql | 22 +++++++++++++----- 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/csharp/ql/test/library-tests/parameters/Parameters.cs b/csharp/ql/test/library-tests/parameters/Parameters.cs index ebe17322bad..ee62454b404 100644 --- a/csharp/ql/test/library-tests/parameters/Parameters.cs +++ b/csharp/ql/test/library-tests/parameters/Parameters.cs @@ -25,7 +25,14 @@ public class Parameters public void M17([Optional, DefaultParameterValue(null)] object arg7) => throw null; public void M18([Optional, DefaultParameterValue(3)] int? arg8) => throw null; public void M19([Optional, DecimalConstant(1, 0, 0, 0, 103)] decimal arg9) => throw null; + public void M20([Optional, DefaultParameterValue(7)] MyStruct arg10) => throw null; + public void M21([Optional, DefaultParameterValue("mystring")] MyStruct arg10) => throw null; - public struct MyStruct { } + public struct MyStruct + { + public static implicit operator MyStruct(int i) => new MyStruct(); + public static implicit operator MyStruct(string s) => new MyStruct(); + + } public enum MyEnum { A = 1, B = 2 } } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/parameters/Parameters.cs_ b/csharp/ql/test/library-tests/parameters/Parameters.cs_ index 8fce6f198c3..136e7262b98 100644 --- a/csharp/ql/test/library-tests/parameters/Parameters.cs_ +++ b/csharp/ql/test/library-tests/parameters/Parameters.cs_ @@ -25,7 +25,14 @@ public class ParametersDll public void M17([Optional, DefaultParameterValue(null)] object arg7) => throw null; public void M18([Optional, DefaultParameterValue(3)] int? arg8) => throw null; public void M19([Optional, DecimalConstant(1, 0, 0, 0, 103)] decimal arg9) => throw null; + public void M20([Optional, DefaultParameterValue(7)] MyStruct arg10) => throw null; + public void M21([Optional, DefaultParameterValue("mystring")] MyStruct arg10) => throw null; - public struct MyStruct { } + public struct MyStruct + { + public static implicit operator MyStruct(int i) => new MyStruct(); + public static implicit operator MyStruct(string s) => new MyStruct(); + + } public enum MyEnum { A = 1, B = 2 } } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/parameters/Parameters.dll b/csharp/ql/test/library-tests/parameters/Parameters.dll index b40c91369cbf75bb1c1296e3a7652ad3a7abc331..3358306fc8976442d42361e9615275591f8a928d 100644 GIT binary patch delta 2032 zcmZ{ld2Ccg9LK*iZ})Y3uzg!>>9$*J*+MNy+XYDxIV?wE15H{BXoFzdl{AHxqa~0c z^2(tB6heJU#6S=#S|M_XTIC2B&{Q!o0Tl#8AgF(MVS-mQA%16=R5Wpt`ONS8o#XxH z&FtHbvW~K?8+<E!qGvjvjmU|mo%?2s8=eqF{-1{fGra<NuU99E<g|2etymq7mO__l zq=X-l0^qYWKzQ{|xmPWp@lHwGyDXDO0R77ZQaDZkp$y#0OyU%K=>PlP*RrrSVgu3D zzy`Lx7USAwtxby>+tgF5xtfn{bXF~9GImrvbyj>b+sCPwNa~5riyNp_p%f4Al-?XG zFEfvNFsqsqVa;b1-bO3W{Yf%G78}2bv6hYJrQ#4#Y^CE-W?&;Bj!PR)$PoRLLUEPm zcFip9&(QHrsJY$pFOJ`8DF%h&ZXI8Micf0hXqL*cE+@qGBQNS{K0WkJ#ww{j3Vef1 zQ8>7Uc576h8pCvzQrmRUz%@oO<_n^_qWdhKkl>cDa!3VxY^1QSo12<K6@l8hD=Ftv z4#W^Fv|b>4<aRRI+5y`>j2)QWu^+q0H^}OImC)1KQKl_W*QdIuTKiNt)!II#`kw1k zYBPIoD-6H^mvXO>_u&8&={Bm8Dhd0IdIWFtHXSgkktz*`jarUl2;wcH*5U(%&|}mV zoJSUp8ub#@0Gu#NP`TMSWn?;23FEX;Ww?YKd}!1}TtzNEGHNFKBKX9p1pD&vsZp&Q zHxTEHT8-~;H$FFN6K)_M7meD6KTzP}vXQB{g+aJtRDY@{uH9Dpbr<3Xt+oXYTRu?; zUjbN@N)hU63%o~4z6-#@3FA19avVoFj-$r>+i~x-{)yFc!}ZV!dUB0kZm@RBwG$_O zm_z!pfD|}p{g?M>e~jh~UPOU;nl0LCS9I}|7M;3dr;h!GDv2-D^~NqM8Bt5{T-C)3 zlPM@B9mF*6*R0TtYu0GiY1WfA+R04pCUfyRnU5yYwXuecjR5XKIWmyRpGpAP7|Saa zMkV7s?HAAw@*9$%Q_MJn??;V{>3EdpIL!*}$2F@oYq&xHv(U_0b$ZNP&3aV0?3j<G z>}b+f3z@=Pm(zKYae(P9B{#z5<2PeHiZB%OWC>E?h!XTin9Rj!GKvav7+i8BHj@wF zMRF4MlGC+cOOE8)jdBtXuN>|qKCYa*QX*mE1dfY!+F7Tab?mt=y0p`!oh~(2p5}#p zN1Wzzhs1TphlC{*Pid~V79u8Jw$zwc7>}2QzBWwP2MYeQi{a})15fwPa)O_uq&tif z^lFvFuUCLom0TPovw1M8_3;OGkoSIy>Z*#Bp}w_|tQx@@i?KbDn*6>LP2SnmOT!i~ zc`V+tq`4{4v<&raZSz|in%mVpmJ9Dz_M8=~sy3W&TPb!Vukp^L75jZjA{6m{OsmQC zsjQq99!(pTp_RwA2#wyjehV`E`GSM^sSQN}nnCZiey{rc{L*>TgDbq=;Dce#9r0D- z97I($_s>%VCYP`}-oW%MyO&|F<Bdrl<edL_{P*A949B-Gx-xb2mi<S)=JXXM#@zU& zF}c)3zb`J@HzntrW4~0Ub`LOr%Ul()QZMA>$Y`lI-1+rLFyl{4PM&ZilyyUNmL>fS D+qg<0 delta 1875 zcmZ{leN2^A9LK-sdG5Vjke3IpAaCjg3_{_Kmxu~;A`y|Yfe6CT3egb*ti&Q6aW7tH zI4Py4Kbp=NVJ%-G8Eh4;rDIucHd!w#r?wWkx#ia8YAf4X-}B>vwzi(_e9rIt{hf2} zdCob{xuJqk!I42%?^yen!$avtV_^7nqcUx!a@?+bV3VC;<k`(C$Ji2U?^FFLr2)wE z7-_(bpZ$P88c=p!e5qY)9E!{|?zMm@thCe36~Re2kk!vN9^kCWxPJGpj-Bm2dXUSJ zfQxljLp^2~vm3Ii8mb>*{Uh~SgL+-pGux>3L#Z|&2O^Uw?y6$2Rt%F_ye#|)q_AYL z=&@3PAeJ-Gjphpn0p}qa_`%S=?s`k*nI0T4G?P_|8HWvQ=0SrRGd$=v6#a3fxl?#Z z=oNpB#5bY)9yNYp`;eGY(Rh)dA%xG-ACrDcaQ;TO{FH{nTAPwI6IPLxwr7QRM@ zS+bz=I9;vunpoJxF-jP7HK}GKXL5H`kP9)xHswrt5XIyhe5*>TROnZ~!`xO;*=RBM zA{(cSe)3Oa03OdM2GAHfj{W2bvevIBbRgNsX)81@s6nb-3+ffBeU1wHOr3mfA*tWy ztvQ8A*i>&jDx1oMcOCTrRRqpB>Tw+9i5hcMGgUOk9rZNcL@Xv9wHv1qj}IIb3gSba zk|{?HQ7yqIj#5;~IPWMf77x#~qcZU+SLmXn?!#wD!zD*O%3L}wJF0=XrMTj#?QFLU zUpeYo1h4P_e(T6Sd;>qechn$m@T6XwQ?jI)(7SzxH1Hm2;(f=lEbUm9b}UP``G4o% zEJxGlUpFn3&J{A;5^-|HDI;B|A>G(QDx5I?%T)36gll-76l#S}iqk3V6^6w>%#HP# zire5bgB~ub&x}GYX>l5w4+_hL)xtVqv#^!)U=Nvy5i$*@NIyEn9}s%67)3}xB3ARu zPev(EKnf4Jms_Fz4EnLS2TufP<x(UdUz!$5Tq1l}ST26Gutr$NA-rfnJ9{-to2|lD z$?iZG{SI-u$tX_sIXW*%c7WL&tVE#^z#_~d7=RDA5#X^{qyosoVsaHWlErw6EJG(* zffvd3;@6YK9PlBd0xg_M1%ILlZ4$RRaT^Y*usC6H!pxsjqvDK;GfL+>H627I{#Mf* zF05u5hn1-`&kOgPop2c^$#`Rhs|U+?8}L%#hvy2-MHJ36!h0iPUa-!^l&A>aD_$1; zq;bRab-Yw+7tdbY2+wk*&eaqauuOaudBL#zqOUG*?djRky{&7H&heSt*gX`!c(7_} z`wO>H{>b~>4#ni!V=;AhVr++fB=#M9b=>oAx4u2>b8+QGKV`M@nyIPfgn2IkP5iHF ziqiwlJ^C$tEIBOKnY$imXIq(8e(27H!+n2MANzP}Z`F;fFWXI4Z_&JY%`rK4%=(FA zuim_W?dA<<XIoY|e|dW3N*()$Gm?zbfSnTmyX{Z9JrSF5*EE{eOvESss)h?9{s9Te B9@YQ= diff --git a/csharp/ql/test/library-tests/parameters/Parameters.expected b/csharp/ql/test/library-tests/parameters/Parameters.expected index 4ac08438d3a..820ec37b9ab 100644 --- a/csharp/ql/test/library-tests/parameters/Parameters.expected +++ b/csharp/ql/test/library-tests/parameters/Parameters.expected @@ -5,12 +5,16 @@ noDefaultValue | Parameters.cs:8:17:8:18 | M2 | Parameters.cs:8:24:8:24 | a | 0 | | Parameters.cs:12:17:12:18 | M6 | Parameters.cs:12:29:12:30 | s1 | 0 | | Parameters.cs:13:17:13:18 | M7 | Parameters.cs:13:27:13:28 | e1 | 0 | +| Parameters.cs:33:32:33:39 | implicit conversion | Parameters.cs:33:54:33:54 | i | 0 | +| Parameters.cs:34:32:34:39 | implicit conversion | Parameters.cs:34:57:34:57 | s | 0 | | Parameters.dll:0:0:0:0 | M1 | Parameters.dll:0:0:0:0 | a | 0 | | Parameters.dll:0:0:0:0 | M1 | Parameters.dll:0:0:0:0 | b | 1 | | Parameters.dll:0:0:0:0 | M1 | Parameters.dll:0:0:0:0 | c | 2 | | Parameters.dll:0:0:0:0 | M2 | Parameters.dll:0:0:0:0 | a | 0 | | Parameters.dll:0:0:0:0 | M6 | Parameters.dll:0:0:0:0 | s1 | 0 | | Parameters.dll:0:0:0:0 | M7 | Parameters.dll:0:0:0:0 | e1 | 0 | +| Parameters.dll:0:0:0:0 | implicit conversion | Parameters.dll:0:0:0:0 | i | 0 | +| Parameters.dll:0:0:0:0 | implicit conversion | Parameters.dll:0:0:0:0 | s | 0 | withDefaultValue | Parameters.cs:8:17:8:18 | M2 | Parameters.cs:8:34:8:34 | b | 1 | Parameters.cs:8:38:8:41 | null | null | | Parameters.cs:8:17:8:18 | M2 | Parameters.cs:8:51:8:51 | c | 2 | Parameters.cs:8:55:8:70 | "default string" | default string | @@ -39,6 +43,8 @@ withDefaultValue | Parameters.cs:25:17:25:19 | M17 | Parameters.cs:25:68:25:71 | arg7 | 0 | Parameters.cs:25:21:25:71 | default | null | | Parameters.cs:26:17:26:19 | M18 | Parameters.cs:26:63:26:66 | arg8 | 0 | Parameters.cs:26:21:26:66 | 3 | 3 | | Parameters.cs:27:17:27:19 | M19 | Parameters.cs:27:74:27:77 | arg9 | 0 | Parameters.cs:27:21:27:77 | 10.3 | 10.3 | +| Parameters.cs:28:17:28:19 | M20 | Parameters.cs:28:67:28:71 | arg10 | 0 | Parameters.cs:28:21:28:71 | call to operator implicit conversion | - | +| Parameters.cs:29:17:29:19 | M21 | Parameters.cs:29:76:29:80 | arg10 | 0 | Parameters.cs:29:21:29:80 | call to operator implicit conversion | - | | Parameters.dll:0:0:0:0 | M2 | Parameters.dll:0:0:0:0 | b | 1 | Parameters.dll:0:0:0:0 | default | null | | Parameters.dll:0:0:0:0 | M2 | Parameters.dll:0:0:0:0 | c | 2 | Parameters.dll:0:0:0:0 | "default string" | default string | | Parameters.dll:0:0:0:0 | M3 | Parameters.dll:0:0:0:0 | a | 0 | Parameters.dll:0:0:0:0 | 1 | 1 | @@ -66,8 +72,15 @@ withDefaultValue | Parameters.dll:0:0:0:0 | M17 | Parameters.dll:0:0:0:0 | arg7 | 0 | Parameters.dll:0:0:0:0 | default | null | | Parameters.dll:0:0:0:0 | M18 | Parameters.dll:0:0:0:0 | arg8 | 0 | Parameters.dll:0:0:0:0 | 3 | 3 | | Parameters.dll:0:0:0:0 | M19 | Parameters.dll:0:0:0:0 | arg9 | 0 | Parameters.dll:0:0:0:0 | 10.3 | 10.3 | +| Parameters.dll:0:0:0:0 | M20 | Parameters.dll:0:0:0:0 | arg10 | 0 | Parameters.dll:0:0:0:0 | call to operator implicit conversion | - | +| Parameters.dll:0:0:0:0 | M21 | Parameters.dll:0:0:0:0 | arg10 | 0 | Parameters.dll:0:0:0:0 | call to operator implicit conversion | - | dateTimeDefaults | Parameters.cs:22:17:22:19 | M14 | Parameters.cs:22:64:22:67 | arg4 | Parameters.cs:22:21:22:67 | object creation of type DateTime | DateTime(long) | 14 | | Parameters.cs:23:17:23:19 | M15 | Parameters.cs:23:68:23:71 | arg5 | Parameters.cs:23:21:23:71 | object creation of type DateTime | DateTime(long) | 10001 | | Parameters.dll:0:0:0:0 | M14 | Parameters.dll:0:0:0:0 | arg4 | Parameters.dll:0:0:0:0 | object creation of type DateTime | DateTime(long) | 14 | | Parameters.dll:0:0:0:0 | M15 | Parameters.dll:0:0:0:0 | arg5 | Parameters.dll:0:0:0:0 | object creation of type DateTime | DateTime(long) | 10001 | +implicitConversionDefaults +| Parameters.cs:28:17:28:19 | M20 | Parameters.cs:28:67:28:71 | arg10 | Parameters.cs:28:21:28:71 | call to operator implicit conversion | Parameters.cs:28:21:28:71 | 7 | Int32 | 7 | +| Parameters.cs:29:17:29:19 | M21 | Parameters.cs:29:76:29:80 | arg10 | Parameters.cs:29:21:29:80 | call to operator implicit conversion | Parameters.cs:29:21:29:80 | "mystring" | String | mystring | +| Parameters.dll:0:0:0:0 | M20 | Parameters.dll:0:0:0:0 | arg10 | Parameters.dll:0:0:0:0 | call to operator implicit conversion | Parameters.dll:0:0:0:0 | 7 | Int32 | 7 | +| Parameters.dll:0:0:0:0 | M21 | Parameters.dll:0:0:0:0 | arg10 | Parameters.dll:0:0:0:0 | call to operator implicit conversion | Parameters.dll:0:0:0:0 | "mystring" | String | mystring | diff --git a/csharp/ql/test/library-tests/parameters/Parameters.ql b/csharp/ql/test/library-tests/parameters/Parameters.ql index 09eadc693f0..209cdc12577 100644 --- a/csharp/ql/test/library-tests/parameters/Parameters.ql +++ b/csharp/ql/test/library-tests/parameters/Parameters.ql @@ -16,11 +16,15 @@ query predicate noDefaultValue(Parameterizable container, Parameter p, int i) { not compilerGeneratedAttribute(container) } -query predicate withDefaultValue(Parameterizable container, Parameter p, int i, Expr e, string value) { +private predicate defaultValue(Parameterizable container, Parameter p, int i, Expr e) { fromTestLocation(container) and p.hasDefaultValue() and container.getParameter(i) = p and - p.getDefaultValue() = e and + p.getDefaultValue() = e +} + +query predicate withDefaultValue(Parameterizable container, Parameter p, int i, Expr e, string value) { + defaultValue(container, p, i, e) and (if exists(e.getValue()) then value = e.getValue() else value = "-") and not compilerGeneratedAttribute(container) } @@ -28,11 +32,17 @@ query predicate withDefaultValue(Parameterizable container, Parameter p, int i, query predicate dateTimeDefaults( Parameterizable container, Parameter p, ObjectCreation o, string constructor, string value ) { - fromTestLocation(container) and - p.hasDefaultValue() and - container.getAParameter() = p and - p.getDefaultValue() = o and + defaultValue(container, p, _, o) and o.getTarget().toStringWithTypes() = constructor and o.getAnArgument().getValue() = value and not compilerGeneratedAttribute(container) } + +query predicate implicitConversionDefaults( + Parameterizable container, Parameter p, OperatorCall o, Expr e, string type, string value +) { + defaultValue(container, p, _, o) and + o.getAnArgument() = e and + type = e.getType().toString() and + value = e.getValue() +} From 7d801e05eefb3f5dab363934d4f1d1211d17d620 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 31 May 2023 13:08:20 +0200 Subject: [PATCH 083/219] add an example of using dollar eq --- .../Security/CWE-089/SqlInjection.inc.qhelp | 12 +++++++++-- .../CWE-089/examples/NoSqlInjectionFix.js | 8 ++----- .../CWE-089/examples/NoSqlInjectionFix2.js | 21 +++++++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index 1d99428b718..a30569aaf2c 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -69,8 +69,16 @@ object, so this code is vulnerable to a NoSQL injection attack. <sample src="examples/NoSqlInjection.js" /> <p> -To fix this vulnerability, we can check that the user input is a -literal value and not a query object before using it in a query. +To fix this vulnerability we can use the <code>$eq</code> operator +to ensure that the user input is interpreted as a literal value +and not as a query object: +</p> + +<sample src="examples/NoSqlInjectionFix2.js" /> + +<p> +Alternatively check that the user input is a +literal value and not a query object before using it: </p> <sample src="examples/NoSqlInjectionFix.js" /> diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js index fe982168be1..83f7c255618 100644 --- a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js @@ -11,11 +11,7 @@ app.use(express.urlencoded({ extended: false })); app.delete("/api/delete", async (req, res) => { let id = req.body.id; - if (typeof id !== "string") { - res.status(400).json({ status: "error" }); - return; - } - await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string + await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison res.json({ status: "ok" }); -}); +}); \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js new file mode 100644 index 00000000000..fe982168be1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js @@ -0,0 +1,21 @@ +const express = require("express"); +const mongoose = require("mongoose"); +const Todo = mongoose.model( + "Todo", + new mongoose.Schema({ text: { type: String } }, { timestamps: true }) +); + +const app = express(); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); + +app.delete("/api/delete", async (req, res) => { + let id = req.body.id; + if (typeof id !== "string") { + res.status(400).json({ status: "error" }); + return; + } + await Todo.deleteOne({ _id: id }); // GOOD: id is guaranteed to be a string + + res.json({ status: "ok" }); +}); From 98820780af90934baf54335aa428478c694c7496 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 31 May 2023 13:51:22 +0200 Subject: [PATCH 084/219] show how to use mysql.escape in the sql-injection qhelp --- .../src/Security/CWE-089/SqlInjection.inc.qhelp | 6 ++++++ .../Security/CWE-089/examples/SqlInjectionFix2.js | 15 +++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix2.js diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index a30569aaf2c..cdf090e6914 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -55,6 +55,12 @@ immune to injection attacks. </p> <sample src="examples/SqlInjectionFix.js" /> + +<p> +Alternatively, we can use a library like <code>sqlstring</code> to +escape the user input before embedding it into the query string: +</p> +<sample src="examples/SqlInjectionFix2.js" /> </example> <example> diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix2.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix2.js new file mode 100644 index 00000000000..843426cf732 --- /dev/null +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix2.js @@ -0,0 +1,15 @@ +const app = require("express")(), + pg = require("pg"), + SqlString = require('sqlstring'), + pool = new pg.Pool(config); + +app.get("search", function handler(req, res) { + // GOOD: the category is escaped using mysql.escape + var query1 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + SqlString.escape(req.params.category) + + "' ORDER BY PRICE"; + pool.query(query1, [], function(err, results) { + // process results + }); +}); From 1e081058637d99a48f6714be43d891742995ee5c Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 31 May 2023 13:51:38 +0200 Subject: [PATCH 085/219] less duplicated headers in the sql-injection samples --- .../ql/src/Security/CWE-089/SqlInjection.inc.qhelp | 4 ++-- .../Security/CWE-089/examples/NoSqlInjectionFix.js | 11 ----------- .../Security/CWE-089/examples/NoSqlInjectionFix2.js | 11 ----------- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index cdf090e6914..cdda5100ba3 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -80,14 +80,14 @@ to ensure that the user input is interpreted as a literal value and not as a query object: </p> -<sample src="examples/NoSqlInjectionFix2.js" /> +<sample src="examples/NoSqlInjectionFix.js" /> <p> Alternatively check that the user input is a literal value and not a query object before using it: </p> -<sample src="examples/NoSqlInjectionFix.js" /> +<sample src="examples/NoSqlInjectionFix2.js" /> </example> <references> diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js index 83f7c255618..b1a81344f46 100644 --- a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix.js @@ -1,14 +1,3 @@ -const express = require("express"); -const mongoose = require("mongoose"); -const Todo = mongoose.model( - "Todo", - new mongoose.Schema({ text: { type: String } }, { timestamps: true }) -); - -const app = express(); -app.use(express.json()); -app.use(express.urlencoded({ extended: false })); - app.delete("/api/delete", async (req, res) => { let id = req.body.id; await Todo.deleteOne({ _id: { $eq: id } }); // GOOD: using $eq operator for the comparison diff --git a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js index fe982168be1..0063e73cdfd 100644 --- a/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js +++ b/javascript/ql/src/Security/CWE-089/examples/NoSqlInjectionFix2.js @@ -1,14 +1,3 @@ -const express = require("express"); -const mongoose = require("mongoose"); -const Todo = mongoose.model( - "Todo", - new mongoose.Schema({ text: { type: String } }, { timestamps: true }) -); - -const app = express(); -app.use(express.json()); -app.use(express.urlencoded({ extended: false })); - app.delete("/api/delete", async (req, res) => { let id = req.body.id; if (typeof id !== "string") { From 9aeb2384f35db392daa1fe22d4dde8ec1bd2bb4c Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Thu, 1 Jun 2023 10:20:54 +0200 Subject: [PATCH 086/219] C#: Improve LINQ expression based on review comments. --- .../Entities/Expressions/ImplicitCast.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index 20daedc0ae8..ebd7379ee67 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -42,13 +42,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private static IMethodSymbol? GetImplicitConversionMethod(ITypeSymbol type, object value) => type .GetMembers() - .Where(m => - m is IMethodSymbol method && + .OfType<IMethodSymbol>() + .Where(method => method.GetName() == "op_Implicit" && method.Parameters.Length == 1 && method.Parameters[0].Type.Name == value.GetType().Name ) - .Cast<IMethodSymbol>() .FirstOrDefault(); // Creates a new generated expression with an implicit cast added, if needed. From 7579f182ad310d97c68c49f3cdceaace5724637c Mon Sep 17 00:00:00 2001 From: Maiky <76447395+maikypedia@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:00:35 +0200 Subject: [PATCH 087/219] Add requested changes --- ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll | 22 +++++++++++++++++ .../ql/lib/codeql/ruby/frameworks/Sqlite3.qll | 24 ++++++++++++++++++- .../security/SqlInjectionCustomizations.qll | 21 +++------------- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll index c1c74813b75..1b7c1cde61e 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll @@ -48,4 +48,26 @@ module Mysql2 { override DataFlow::Node getSql() { result = query } } + + /** + * A call to `Mysql2::Client.escape`, considered as a sanitizer for SQL statements. + */ + private class Mysql2EscapeSanitization extends SqlSanitization::Range { + Mysql2EscapeSanitization() { + this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") + } + } + + /** + * Flow summary for `Mysql2::Client.escape()`. + */ + private class EscapeSummary extends SummarizedCallable { + EscapeSummary() { this = "Mysql2::Client.escape()" } + + override MethodCall getACall() { result = any(Mysql2EscapeSanitization c).asExpr().getExpr() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and output = "ReturnValue" and preservesValue = false + } + } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index e051a847993..8a07e211a21 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -77,4 +77,26 @@ module Sqlite3 { override DataFlow::Node getSql() { result = this.getArgument(0) } } -} + + /** + * A call to `SQLite3::Database.quote`, considered as a sanitizer for SQL statements. + */ + private class SQLite3QuoteSanitization extends SqlSanitization { + SQLite3QuoteSanitization() { + this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") + } + } + + /** + * Flow summary for `SQLite3::Database.quote()`. + */ + private class QuoteSummary extends SummarizedCallable { + QuoteSummary() { this = "SQLite3::Database.quote()" } + + override MethodCall getACall() { result = any(SQLite3QuoteSanitization c).asExpr().getExpr() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and output = "ReturnValue" and preservesValue = false + } + } +} \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index e1e1b630d9d..48358fe1d6b 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -52,23 +52,8 @@ module SqlInjection { * sanitizer-guard. */ class StringConstArrayInclusionCallAsSanitizer extends Sanitizer, - StringConstArrayInclusionCallBarrier { } + StringConstArrayInclusionCallBarrier + { } - /** - * A call to `Mysql2::Client.escape`, considered as a sanitizer. - */ - private class Mysql2EscapeSanitization extends Sanitizer { - Mysql2EscapeSanitization() { - this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") - } - } - - /** - * A call to `SQLite3::Database.quote`, considered as a sanitizer. - */ - private class SQLite3EscapeSanitization extends Sanitizer { - SQLite3EscapeSanitization() { - this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") - } - } + private class SqlSanitizationAsSanitizer extends Sanitizer, SqlSanitization { } } From edfdddb24af488d4e9199c6948aaad3e3ce0a79c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:47:05 +0100 Subject: [PATCH 088/219] Swift: Tweak and update the qldoc string. --- swift/ql/.generated.list | 4 ++-- swift/ql/lib/codeql/swift/generated/Callable.qll | 2 +- swift/ql/lib/codeql/swift/generated/Raw.qll | 2 +- swift/schema.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/swift/ql/.generated.list b/swift/ql/.generated.list index 6394bc951c9..3fac0083642 100644 --- a/swift/ql/.generated.list +++ b/swift/ql/.generated.list @@ -368,7 +368,7 @@ lib/codeql/swift/elements.qll 3df0060edd2b2030f4e4d7d5518afe0073d798474d9b1d6185 lib/codeql/swift/generated/AstNode.qll 02ca56d82801f942ae6265c6079d92ccafdf6b532f6bcebd98a04029ddf696e4 6216fda240e45bd4302fa0cf0f08f5f945418b144659264cdda84622b0420aa2 lib/codeql/swift/generated/AvailabilityInfo.qll 1e38e7f52ccbcecd4dd088eae15c482d87911682dabb426332cc0e207fc6bf2f 7c6640530cdbece90d4172e8d6cfd119656860da08bb61ed4ef3a6757723994f lib/codeql/swift/generated/AvailabilitySpec.qll fb1255f91bb5e41ad4e9c675a2efbc50d0fb366ea2de68ab7eebd177b0795309 144e0c2e7d6c62ecee43325f7f26dcf437881edf0b75cc1bc898c6c4b61fdeaf -lib/codeql/swift/generated/Callable.qll c1f214f5ea4da567d3cf2ac4915630ae1e19c939d2aa64cdd5ab06e76de059dc c43fd17a89d016a31584de10e4d4988f3ea10dc26d6b59b3151bb3196e9f0689 +lib/codeql/swift/generated/Callable.qll 5b6d79a4db8d98ea2255f0773d3512ad195e87fe47bab669d6e24668417ab96d 579506e89ad2385739384ab3fecfb1da699d862ee3a9e9a7225b095b0ec279ff lib/codeql/swift/generated/Comment.qll f58b49f6e68c21f87c51e2ff84c8a64b09286d733e86f70d67d3a98fe6260bd6 975bbb599a2a7adc35179f6ae06d9cbc56ea8a03b972ef2ee87604834bc6deb1 lib/codeql/swift/generated/DbFile.qll a49b2a2cb2788cb49c861ebcd458b8daead7b15adb19c3a9f4db3bf39a0051fc a49b2a2cb2788cb49c861ebcd458b8daead7b15adb19c3a9f4db3bf39a0051fc lib/codeql/swift/generated/DbLocation.qll b9baea963d9fa82068986512c0649d1050897654eee3df51dba17cf6b1170873 b9baea963d9fa82068986512c0649d1050897654eee3df51dba17cf6b1170873 @@ -383,7 +383,7 @@ lib/codeql/swift/generated/OtherAvailabilitySpec.qll 0e26a203b26ff0581b7396b0c6d lib/codeql/swift/generated/ParentChild.qll 5c5ff9812efbed0adf465d1c8b9108c893c77ff946f6feaaec7223ad38664079 94038dcd8a5e98b959ce9f09b7b54b745b0df49b91339b9396017a209abe8bb7 lib/codeql/swift/generated/PlatformVersionAvailabilitySpec.qll f82d9ca416fe8bd59b5531b65b1c74c9f317b3297a6101544a11339a1cffce38 7f5c6d3309e66c134107afe55bae76dfc9a72cb7cdd6d4c3706b6b34cee09fa0 lib/codeql/swift/generated/PureSynthConstructors.qll 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98 -lib/codeql/swift/generated/Raw.qll 87402f6b1a0173503a545b57b06c0e320459410834c9adc7a25b2ae53874075e 49e27ddf824decdf21c0531b1ebb3fa007a869ec63bde9f60d08a68fae12acc6 +lib/codeql/swift/generated/Raw.qll 991f95f30bde82ba43237bd9c1a68d3f450038ef828edb89219fbf583dd1956a e3e6c41caac09d532453c28167622fae7057d846f35750873eacd48cd128b957 lib/codeql/swift/generated/Synth.qll 551fdf7e4b53f9ee1314d1bb42c2638cf82f45bfa1f40a635dfa7b6072e4418c 9ab178464700a19951fc5285acacda4913addee81515d8e072b3d7055935a814 lib/codeql/swift/generated/SynthConstructors.qll 2f801bd8b0db829b0253cd459ed3253c1fdfc55dce68ebc53e7fec138ef0aca4 2f801bd8b0db829b0253cd459ed3253c1fdfc55dce68ebc53e7fec138ef0aca4 lib/codeql/swift/generated/UnknownFile.qll 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6 diff --git a/swift/ql/lib/codeql/swift/generated/Callable.qll b/swift/ql/lib/codeql/swift/generated/Callable.qll index 924614643f6..09105447736 100644 --- a/swift/ql/lib/codeql/swift/generated/Callable.qll +++ b/swift/ql/lib/codeql/swift/generated/Callable.qll @@ -11,7 +11,7 @@ module Generated { /** * Gets the name of this callable, if it exists. * - * The name includes any arguments of the callable, for example `myFunction(arg:)`. + * The name includes argument labels of the callable, for example `myFunction(arg:)`. */ string getName() { result = Synth::convertCallableToRaw(this).(Raw::Callable).getName() } diff --git a/swift/ql/lib/codeql/swift/generated/Raw.qll b/swift/ql/lib/codeql/swift/generated/Raw.qll index dc27ea87ef3..38e84cd3093 100644 --- a/swift/ql/lib/codeql/swift/generated/Raw.qll +++ b/swift/ql/lib/codeql/swift/generated/Raw.qll @@ -22,7 +22,7 @@ module Raw { /** * Gets the name of this callable, if it exists. * - * The name includes any arguments of the callable, for example `myFunction(arg:)`. + * The name includes argument labels of the callable, for example `myFunction(arg:)`. */ string getName() { callable_names(this, result) } diff --git a/swift/schema.py b/swift/schema.py index a752562f960..3af02367d8a 100644 --- a/swift/schema.py +++ b/swift/schema.py @@ -235,8 +235,8 @@ class ParamDecl(VarDecl): """) class Callable(Element): - name: optional[string] | doc("name of this callable") | desc("The name includes any arguments " - "of the callable, for example `myFunction(arg:)`.") + name: optional[string] | doc("name of this callable") | desc("The name includes argument " + "labels of the callable, for example `myFunction(arg:)`.") self_param: optional[ParamDecl] | child params: list[ParamDecl] | child body: optional["BraceStmt"] | child | desc("The body is absent within protocol declarations.") From baef99995d2b7990938fa367220416e1d62102ff Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Thu, 1 Jun 2023 14:08:34 +0200 Subject: [PATCH 089/219] JS: Change note --- .../2023-06-01-restrict-regex-search-function.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md diff --git a/javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md b/javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md new file mode 100644 index 00000000000..a43aebff717 --- /dev/null +++ b/javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- +* Fixed an issue where calls to a method named `search` would lead to false positive alerts related to regular expressions. + This happened when the call was incorrectly seen as a call to `String.prototype.search`, since this function converts its first argument + to a regular expression. The analysis is now more restrictive about when to treat `search` calls as regular expression sinks. From 9aeba4f31edcaaa88263f4b8039452581d944ff4 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 17:24:44 +0200 Subject: [PATCH 090/219] changes based on review --- javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp | 2 +- javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index cdda5100ba3..9ee5158bf99 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -40,7 +40,7 @@ an HTTP request handler in a web application, whose parameter <p> The handler constructs constructs an SQL query string from user input and executes it as a database query using the <code>pg</code> library. -THe user input may contain quote characters, so this code is vulnerable +The user input may contain quote characters, so this code is vulnerable to a SQL injection attack. </p> diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js index 4391b83e391..dbe5c4e369a 100644 --- a/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjectionFix.js @@ -5,7 +5,7 @@ const app = require("express")(), app.get("search", function handler(req, res) { // GOOD: use parameters var query2 = - "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1 ORDER BY PRICE"; pool.query(query2, [req.params.category], function(err, results) { // process results }); From 606d601923897f423b6fe7bd5c1590935c649d58 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Thu, 1 Jun 2023 16:26:05 +0100 Subject: [PATCH 091/219] qlformat --- ruby/ql/lib/codeql/ruby/Concepts.qll | 22 +++++++++---------- .../ql/lib/codeql/ruby/frameworks/Sqlite3.qll | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index 0a403734512..d74947482f8 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -78,18 +78,18 @@ module SqlExecution { } } - /** - * A data-flow node that performs SQL sanitization. - */ - class SqlSanitization extends DataFlow::Node instanceof SqlSanitization::Range { } +/** + * A data-flow node that performs SQL sanitization. + */ +class SqlSanitization extends DataFlow::Node instanceof SqlSanitization::Range { } - /** Provides a class for modeling new SQL sanitization APIs. */ - module SqlSanitization { - /** - * A data-flow node that performs SQL sanitization. - */ - abstract class Range extends DataFlow::Node { } - } +/** Provides a class for modeling new SQL sanitization APIs. */ +module SqlSanitization { + /** + * A data-flow node that performs SQL sanitization. + */ + abstract class Range extends DataFlow::Node { } +} /** * A data-flow node that executes a regular expression. diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index 8a07e211a21..70744d6fcc8 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -99,4 +99,4 @@ module Sqlite3 { input = "Argument[0]" and output = "ReturnValue" and preservesValue = false } } -} \ No newline at end of file +} From 6fa9e13a2e76a15fbed57180fe49c9cd8f3fe1c4 Mon Sep 17 00:00:00 2001 From: Alex Ford <alexrford@github.com> Date: Thu, 1 Jun 2023 16:27:20 +0100 Subject: [PATCH 092/219] Ruby: update TaintStep output --- ruby/ql/test/library-tests/dataflow/local/TaintStep.expected | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected index 2bfe1e9a9ab..e75c17e818e 100644 --- a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected @@ -2814,7 +2814,10 @@ | file://:0:0:0:0 | parameter position 0 of File.realdirpath | file://:0:0:0:0 | [summary] to write: return (return) in File.realdirpath | | file://:0:0:0:0 | parameter position 0 of File.realpath | file://:0:0:0:0 | [summary] to write: return (return) in File.realpath | | file://:0:0:0:0 | parameter position 0 of Hash[] | file://:0:0:0:0 | [summary] read: argument position 0.any element in Hash[] | +| file://:0:0:0:0 | parameter position 0 of Mysql2::Client.escape() | file://:0:0:0:0 | [summary] to write: return (return) in Mysql2::Client.escape() | +| file://:0:0:0:0 | parameter position 0 of Mysql2::Client.new() | file://:0:0:0:0 | [summary] to write: return (return) in Mysql2::Client.new() | | file://:0:0:0:0 | parameter position 0 of PG.new() | file://:0:0:0:0 | [summary] to write: return (return) in PG.new() | +| file://:0:0:0:0 | parameter position 0 of SQLite3::Database.quote() | file://:0:0:0:0 | [summary] to write: return (return) in SQLite3::Database.quote() | | file://:0:0:0:0 | parameter position 0 of Sequel.connect | file://:0:0:0:0 | [summary] to write: return (return) in Sequel.connect | | file://:0:0:0:0 | parameter position 0 of String.try_convert | file://:0:0:0:0 | [summary] to write: return (return) in String.try_convert | | file://:0:0:0:0 | parameter position 0 of \| | file://:0:0:0:0 | [summary] read: argument position 0.any element in \| | From 7290e2bfd9cb2e469ef152864588530801ff1192 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Thu, 1 Jun 2023 17:06:34 +0100 Subject: [PATCH 093/219] Java: avoid call to Location.toString() --- .../Implementation Hiding/ExposeRepresentation.ql | 2 +- .../ExposeRepresentation.expected | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql b/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql index 9f24744fa0c..2889de0b5cf 100644 --- a/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +++ b/java/ql/src/Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql @@ -128,4 +128,4 @@ where not exists(Property p | p.getBackingField() = f) select c, c.getName() + " exposes the internal representation stored in field " + f.getName() + - ". The value may be modified $@.", why.getLocation(), whyText + ". The value may be modified $@.", why, whyText diff --git a/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.expected b/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.expected index 0056c25bb53..3162056ab42 100644 --- a/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.expected +++ b/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.expected @@ -1,7 +1,7 @@ -| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:5:5:5:19 | User.java:5:5:5:19 | after this call to getStrings | -| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:13:12:13:26 | User.java:13:12:13:26 | after this call to getStrings | -| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:38:12:38:26 | User.java:38:12:38:26 | after this call to getStrings | -| ExposesRep.java:13:30:13:41 | getStringMap | getStringMap exposes the internal representation stored in field stringMap. The value may be modified $@. | User.java:9:5:9:21 | User.java:9:5:9:21 | after this call to getStringMap | -| ExposesRep.java:17:15:17:24 | setStrings | setStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:22:5:22:6 | User.java:22:5:22:6 | through the variable ss | -| ExposesRep.java:21:15:21:26 | setStringMap | setStringMap exposes the internal representation stored in field stringMap. The value may be modified $@. | User.java:27:5:27:5 | User.java:27:5:27:5 | through the variable m | -| ExposesRep.java:29:14:29:21 | getArray | getArray exposes the internal representation stored in field array. The value may be modified $@. | User.java:31:5:31:18 | User.java:31:5:31:18 | after this call to getArray | +| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:5:5:5:19 | getStrings(...) | after this call to getStrings | +| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:13:12:13:26 | getStrings(...) | after this call to getStrings | +| ExposesRep.java:11:19:11:28 | getStrings | getStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:38:12:38:26 | getStrings(...) | after this call to getStrings | +| ExposesRep.java:13:30:13:41 | getStringMap | getStringMap exposes the internal representation stored in field stringMap. The value may be modified $@. | User.java:9:5:9:21 | getStringMap(...) | after this call to getStringMap | +| ExposesRep.java:17:15:17:24 | setStrings | setStrings exposes the internal representation stored in field strings. The value may be modified $@. | User.java:22:5:22:6 | ss | through the variable ss | +| ExposesRep.java:21:15:21:26 | setStringMap | setStringMap exposes the internal representation stored in field stringMap. The value may be modified $@. | User.java:27:5:27:5 | m | through the variable m | +| ExposesRep.java:29:14:29:21 | getArray | getArray exposes the internal representation stored in field array. The value may be modified $@. | User.java:31:5:31:18 | getArray(...) | after this call to getArray | From 06c83ee14da3b7c764fa044e8b6dc7157247f9e3 Mon Sep 17 00:00:00 2001 From: Jami Cogswell <jcogs33@Jamis-MacBook-Pro.local> Date: Fri, 19 May 2023 11:18:10 -0400 Subject: [PATCH 094/219] Java: add error message for deprecated sink kinds to 'getInvalidModelKind' --- .../code/java/dataflow/ExternalFlow.qll | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 5776d64f402..f933a615c83 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -265,13 +265,72 @@ module ModelValidation { ) } + private class DeprecatedSinkKind extends string { + DeprecatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", + "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", + "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", + "jdbc-url" + ] + } + + private string replacementKind() { + this = "sql" and result = "\"sql-injection\"" + or + this = "url-redirect" and result = "\"url-redirection\"" + or + this = "xpath" and result = "\"xpath-injection\"" + or + this = "ssti" and result = "\"template-injection\"" + or + this = "logging" and result = "\"log-injection\"" + or + this = "groovy" and result = "\"groovy-injection\"" + or + this = "jexl" and result = "\"jexl-injection\"" + or + this = "mvel" and result = "\"mvel-injection\"" + or + this = "xslt" and result = "\"xslt-injection\"" + or + this = "ldap" and result = "\"ldap-injection\"" + or + this = "pending-intent-sent" and result = "\"pending-intents\"" + or + this = "intent-start" and result = "\"intent-redirection\"" + or + this = "set-hostname-verifier" and result = "\"hostname-verification\"" + or + this = "header-splitting" and result = "\"response-splitting\"" + or + this = "xss" and result = "\"html-injection\" or \"js-injection\"" + or + this = "write-file" and result = "\"file-content-store\"" + or + this = "create-file" and result = "\"path-injection\"" + or + this = "read-file" and result = "\"path-injection\"" + or + this = "open-url" and result = "\"request-forgery\"" + or + this = "jdbc-url" and result = "\"request-forgery\"" + } + + string deprecationMessage() { + result = + "The kind \"" + this + "\" is deprecated. Use " + this.replacementKind() + " instead." + } + } + private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind = [ "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", @@ -283,7 +342,10 @@ module ModelValidation { ] and not kind.matches("regex-use%") and not kind.matches("qltest%") and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + if kind instanceof DeprecatedSinkKind + then result = msg + " " + kind.(DeprecatedSinkKind).deprecationMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | From b3d218a50322041d2c4eb275a66afe188e53c702 Mon Sep 17 00:00:00 2001 From: Jami Cogswell <jcogs33@Jamis-MacBook-Pro.local> Date: Mon, 22 May 2023 10:15:34 -0400 Subject: [PATCH 095/219] Java: condense 'replacementKind' code --- .../code/java/dataflow/ExternalFlow.qll | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index f933a615c83..1b0ce54af38 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -277,50 +277,35 @@ module ModelValidation { } private string replacementKind() { - this = "sql" and result = "\"sql-injection\"" + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap"] and + result = this + "-injection" or - this = "url-redirect" and result = "\"url-redirection\"" + this = "url-redirect" and result = "url-redirection" or - this = "xpath" and result = "\"xpath-injection\"" + this = "ssti" and result = "template-injection" or - this = "ssti" and result = "\"template-injection\"" + this = "logging" and result = "log-injection" or - this = "logging" and result = "\"log-injection\"" + this = "pending-intent-sent" and result = "pending-intents" or - this = "groovy" and result = "\"groovy-injection\"" + this = "intent-start" and result = "intent-redirection" or - this = "jexl" and result = "\"jexl-injection\"" + this = "set-hostname-verifier" and result = "hostname-verification" or - this = "mvel" and result = "\"mvel-injection\"" + this = "header-splitting" and result = "response-splitting" or - this = "xslt" and result = "\"xslt-injection\"" + this = "xss" and result = "html-injection\" or \"js-injection" or - this = "ldap" and result = "\"ldap-injection\"" + this = "write-file" and result = "file-content-store" or - this = "pending-intent-sent" and result = "\"pending-intents\"" + this = ["create-file", "read-file"] and result = "path-injection" or - this = "intent-start" and result = "\"intent-redirection\"" - or - this = "set-hostname-verifier" and result = "\"hostname-verification\"" - or - this = "header-splitting" and result = "\"response-splitting\"" - or - this = "xss" and result = "\"html-injection\" or \"js-injection\"" - or - this = "write-file" and result = "\"file-content-store\"" - or - this = "create-file" and result = "\"path-injection\"" - or - this = "read-file" and result = "\"path-injection\"" - or - this = "open-url" and result = "\"request-forgery\"" - or - this = "jdbc-url" and result = "\"request-forgery\"" + this = ["open-url", "jdbc-url"] and result = "request-forgery" } string deprecationMessage() { result = - "The kind \"" + this + "\" is deprecated. Use " + this.replacementKind() + " instead." + "The kind \"" + this + "\" is deprecated. Use \"" + this.replacementKind() + "\" instead." } } From 0355b78f13845ab90ce109dae58f5f5ce4a9bd83 Mon Sep 17 00:00:00 2001 From: Jami Cogswell <jcogs33@Jamis-MacBook-Pro.local> Date: Mon, 22 May 2023 10:34:56 -0400 Subject: [PATCH 096/219] Java: add deprecation deletion comment --- java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 1b0ce54af38..0304e64398f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -247,6 +247,8 @@ module ModelValidation { ) } + /** + */ private string getInvalidModelOutput() { exists(string pred, AccessPath output, AccessPathToken part | sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source" @@ -328,6 +330,7 @@ module ModelValidation { not kind.matches("regex-use%") and not kind.matches("qltest%") and msg = "Invalid kind \"" + kind + "\" in sink model." and + // The deprecation part of this message can be deleted after June 1st, 2024. if kind instanceof DeprecatedSinkKind then result = msg + " " + kind.(DeprecatedSinkKind).deprecationMessage() else result = msg From d10857fbdb8991bd7630fb7eae85e67089a1f47a Mon Sep 17 00:00:00 2001 From: Jami Cogswell <jcogs33@Jamis-MacBook-Pro.local> Date: Mon, 22 May 2023 10:39:59 -0400 Subject: [PATCH 097/219] Java: fix typo blank qldoc --- java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 0304e64398f..cebf330c8e4 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -247,8 +247,6 @@ module ModelValidation { ) } - /** - */ private string getInvalidModelOutput() { exists(string pred, AccessPath output, AccessPathToken part | sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source" From b8cedfa817b6b4bc8d56cad8d3cf6faf4da69b01 Mon Sep 17 00:00:00 2001 From: Jami Cogswell <jcogs33@Jamis-MacBook-Pro.local> Date: Thu, 1 Jun 2023 13:30:27 -0400 Subject: [PATCH 098/219] Java: switch 'deprecated' to 'outdated' --- .../lib/semmle/code/java/dataflow/ExternalFlow.qll | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index cebf330c8e4..ca662ee5610 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -265,8 +265,8 @@ module ModelValidation { ) } - private class DeprecatedSinkKind extends string { - DeprecatedSinkKind() { + private class OutdatedSinkKind extends string { + OutdatedSinkKind() { this = [ "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", @@ -303,9 +303,9 @@ module ModelValidation { this = ["open-url", "jdbc-url"] and result = "request-forgery" } - string deprecationMessage() { + string outdatedMessage() { result = - "The kind \"" + this + "\" is deprecated. Use \"" + this.replacementKind() + "\" instead." + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." } } @@ -328,9 +328,9 @@ module ModelValidation { not kind.matches("regex-use%") and not kind.matches("qltest%") and msg = "Invalid kind \"" + kind + "\" in sink model." and - // The deprecation part of this message can be deleted after June 1st, 2024. - if kind instanceof DeprecatedSinkKind - then result = msg + " " + kind.(DeprecatedSinkKind).deprecationMessage() + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() else result = msg ) or From f4b68fb8c3c7c821770d99c7966e6421a2754986 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 21:51:43 +0200 Subject: [PATCH 099/219] bump TypeScript to stable version --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index cb053bb0e6f..3190b683d34 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "5.1.1-rc" + "typescript": "5.1.3" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 3b0a9476df6..355c257cf69 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== -typescript@5.1.1-rc: - version "5.1.1-rc" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.1-rc.tgz#7be6e85bb4ad36e07e0125e501eb08ed3a6e3769" - integrity sha512-+yHTPe5QCxw5cgN+B81z+k65xTHcwNCRwJN7OGVUe3srPULTZHF7J9QCgrptL7F8mrO7gmsert7XrMksAjutRw== +typescript@5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" + integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== From 97afa5733b86ba10066cec4a5507b08c39d9a772 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 21:52:14 +0200 Subject: [PATCH 100/219] add support for namespaced JSX attributes --- .../ts/extractor/TypeScriptASTConverter.java | 7 +- .../test/library-tests/JSX/printAst.expected | 104 ++++++++++++++++++ .../ql/test/library-tests/JSX/tests.expected | 9 ++ .../ql/test/library-tests/JSX/tstest.tsx | 12 ++ 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java index e34d552b777..7b68106bb3f 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java @@ -1552,8 +1552,13 @@ public class TypeScriptASTConverter { } private Node convertJsxAttribute(JsonObject node, SourceLocation loc) throws ParseError { + JsonObject nameNode = node.get("name").getAsJsonObject(); + if (nameNode.get("name") != null) { + // it's a namespaced attribute + nameNode = nameNode.get("name").getAsJsonObject(); + } return new JSXAttribute( - loc, convertJSXName(convertChild(node, "name")), convertChild(node, "initializer")); + loc, convertJSXName(((Expression)convertNode(nameNode, null))), convertChild(node, "initializer")); // 2 } private Node convertJsxClosingElement(JsonObject node, SourceLocation loc) throws ParseError { diff --git a/javascript/ql/test/library-tests/JSX/printAst.expected b/javascript/ql/test/library-tests/JSX/printAst.expected index 11bf254a890..a34e194cca8 100644 --- a/javascript/ql/test/library-tests/JSX/printAst.expected +++ b/javascript/ql/test/library-tests/JSX/printAst.expected @@ -3,10 +3,14 @@ nodes | file://:0:0:0:0 | (Attributes) | semmle.label | (Attributes) | | file://:0:0:0:0 | (Attributes) | semmle.label | (Attributes) | | file://:0:0:0:0 | (Attributes) | semmle.label | (Attributes) | +| file://:0:0:0:0 | (Attributes) | semmle.label | (Attributes) | +| file://:0:0:0:0 | (Attributes) | semmle.label | (Attributes) | | file://:0:0:0:0 | (Body) | semmle.label | (Body) | | file://:0:0:0:0 | (Body) | semmle.label | (Body) | | file://:0:0:0:0 | (Body) | semmle.label | (Body) | | file://:0:0:0:0 | (Body) | semmle.label | (Body) | +| file://:0:0:0:0 | (Body) | semmle.label | (Body) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | tst.js:1:1:1:32 | [DeclStmt] var href = ... | semmle.label | [DeclStmt] var href = ... | | tst.js:1:1:1:32 | [DeclStmt] var href = ... | semmle.order | 1 | | tst.js:1:5:1:8 | [VarDecl] href | semmle.label | [VarDecl] href | @@ -119,6 +123,42 @@ nodes | tstest.tsx:7:33:7:38 | [JsxElement] <Foo/> | semmle.label | [JsxElement] <Foo/> | | tstest.tsx:7:34:7:36 | [VarRef] Foo | semmle.label | [VarRef] Foo | | tstest.tsx:7:40:7:49 | [Literal] more text | semmle.label | [Literal] more text | +| tstest.tsx:10:1:10:30 | [DeclStmt] const x = ... | semmle.label | [DeclStmt] const x = ... | +| tstest.tsx:10:1:10:30 | [DeclStmt] const x = ... | semmle.order | 15 | +| tstest.tsx:10:7:10:7 | [VarDecl] x | semmle.label | [VarDecl] x | +| tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | semmle.label | [VariableDeclarator] x = <Ba ... llo" /> | +| tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | semmle.label | [JsxElement] <Bar a:b="hello" /> | +| tstest.tsx:10:12:10:14 | [VarRef] Bar | semmle.label | [VarRef] Bar | +| tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | semmle.label | [JsxAttribute] a:b="hello" | +| tstest.tsx:10:18:10:18 | [Label] b | semmle.label | [Label] b | +| tstest.tsx:10:20:10:26 | [Literal] "hello" | semmle.label | [Literal] "hello" | +| tstest.tsx:11:1:11:32 | [DeclStmt] const y = ... | semmle.label | [DeclStmt] const y = ... | +| tstest.tsx:11:1:11:32 | [DeclStmt] const y = ... | semmle.order | 16 | +| tstest.tsx:11:7:11:7 | [VarDecl] y | semmle.label | [VarDecl] y | +| tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | semmle.label | [VariableDeclarator] y = <Ba ... llo" /> | +| tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | semmle.label | [JsxElement] <Bar a ... llo" /> | +| tstest.tsx:11:12:11:14 | [VarRef] Bar | semmle.label | [VarRef] Bar | +| tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | semmle.label | [JsxAttribute] a : b="hello" | +| tstest.tsx:11:20:11:20 | [Label] b | semmle.label | [Label] b | +| tstest.tsx:11:22:11:28 | [Literal] "hello" | semmle.label | [Literal] "hello" | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | semmle.order | 17 | +| tstest.tsx:13:11:13:18 | [Identifier] BarProps | semmle.label | [Identifier] BarProps | +| tstest.tsx:14:5:14:9 | [Literal] "a:b" | semmle.label | [Literal] "a:b" | +| tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | semmle.label | [FieldDeclaration] "a:b": string; | +| tstest.tsx:14:12:14:17 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | semmle.label | [FunctionDeclStmt] functio ... div>; } | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | semmle.order | 18 | +| tstest.tsx:17:10:17:12 | [VarDecl] Bar | semmle.label | [VarDecl] Bar | +| tstest.tsx:17:14:17:18 | [SimpleParameter] props | semmle.label | [SimpleParameter] props | +| tstest.tsx:17:21:17:28 | [LocalTypeAccess] BarProps | semmle.label | [LocalTypeAccess] BarProps | +| tstest.tsx:17:31:19:1 | [BlockStmt] { r ... div>; } | semmle.label | [BlockStmt] { r ... div>; } | +| tstest.tsx:18:5:18:37 | [ReturnStmt] return ... </div>; | semmle.label | [ReturnStmt] return ... </div>; | +| tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | semmle.label | [JsxElement] <div>{p ... }</div> | +| tstest.tsx:18:13:18:15 | [Label] div | semmle.label | [Label] div | +| tstest.tsx:18:18:18:22 | [VarRef] props | semmle.label | [VarRef] props | +| tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | semmle.label | [IndexExpr] props["a:b"] | +| tstest.tsx:18:24:18:28 | [Literal] "a:b" | semmle.label | [Literal] "a:b" | edges | file://:0:0:0:0 | (Attributes) | tst.js:3:4:3:14 | [JsxAttribute] href={href} | semmle.label | 0 | | file://:0:0:0:0 | (Attributes) | tst.js:3:4:3:14 | [JsxAttribute] href={href} | semmle.order | 0 | @@ -136,6 +176,10 @@ edges | file://:0:0:0:0 | (Attributes) | tstest.tsx:3:32:3:45 | [JsxAttribute] {...linkTypes} | semmle.order | 2 | | file://:0:0:0:0 | (Attributes) | tstest.tsx:4:25:4:33 | [JsxAttribute] foo="bar" | semmle.label | 0 | | file://:0:0:0:0 | (Attributes) | tstest.tsx:4:25:4:33 | [JsxAttribute] foo="bar" | semmle.order | 0 | +| file://:0:0:0:0 | (Attributes) | tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | semmle.label | 0 | +| file://:0:0:0:0 | (Attributes) | tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | semmle.order | 0 | +| file://:0:0:0:0 | (Attributes) | tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | semmle.label | 0 | +| file://:0:0:0:0 | (Attributes) | tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | semmle.order | 0 | | file://:0:0:0:0 | (Body) | tst.js:3:47:3:54 | [Literal] Link to | semmle.label | 0 | | file://:0:0:0:0 | (Body) | tst.js:3:47:3:54 | [Literal] Link to | semmle.order | 0 | | file://:0:0:0:0 | (Body) | tst.js:3:56:3:59 | [VarRef] href | semmle.label | 1 | @@ -164,6 +208,10 @@ edges | file://:0:0:0:0 | (Body) | tstest.tsx:7:33:7:38 | [JsxElement] <Foo/> | semmle.order | 1 | | file://:0:0:0:0 | (Body) | tstest.tsx:7:40:7:49 | [Literal] more text | semmle.label | 2 | | file://:0:0:0:0 | (Body) | tstest.tsx:7:40:7:49 | [Literal] more text | semmle.order | 2 | +| file://:0:0:0:0 | (Body) | tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | semmle.label | 0 | +| file://:0:0:0:0 | (Body) | tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tstest.tsx:17:14:17:18 | [SimpleParameter] props | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tstest.tsx:17:14:17:18 | [SimpleParameter] props | semmle.order | 0 | | tst.js:1:1:1:32 | [DeclStmt] var href = ... | tst.js:1:5:1:31 | [VariableDeclarator] href = ... le.com" | semmle.label | 1 | | tst.js:1:1:1:32 | [DeclStmt] var href = ... | tst.js:1:5:1:31 | [VariableDeclarator] href = ... le.com" | semmle.order | 1 | | tst.js:1:5:1:31 | [VariableDeclarator] href = ... le.com" | tst.js:1:5:1:8 | [VarDecl] href | semmle.label | 1 | @@ -304,5 +352,61 @@ edges | tstest.tsx:7:16:7:52 | [JsxFragment] <> frag ... ext </> | file://:0:0:0:0 | (Body) | semmle.order | 1 | | tstest.tsx:7:33:7:38 | [JsxElement] <Foo/> | tstest.tsx:7:34:7:36 | [VarRef] Foo | semmle.label | 0 | | tstest.tsx:7:33:7:38 | [JsxElement] <Foo/> | tstest.tsx:7:34:7:36 | [VarRef] Foo | semmle.order | 0 | +| tstest.tsx:10:1:10:30 | [DeclStmt] const x = ... | tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | semmle.label | 1 | +| tstest.tsx:10:1:10:30 | [DeclStmt] const x = ... | tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | semmle.order | 1 | +| tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | tstest.tsx:10:7:10:7 | [VarDecl] x | semmle.label | 1 | +| tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | tstest.tsx:10:7:10:7 | [VarDecl] x | semmle.order | 1 | +| tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | semmle.label | 2 | +| tstest.tsx:10:7:10:29 | [VariableDeclarator] x = <Ba ... llo" /> | tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | semmle.order | 2 | +| tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | file://:0:0:0:0 | (Attributes) | semmle.label | 2 | +| tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | file://:0:0:0:0 | (Attributes) | semmle.order | 2 | +| tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | tstest.tsx:10:12:10:14 | [VarRef] Bar | semmle.label | 0 | +| tstest.tsx:10:11:10:29 | [JsxElement] <Bar a:b="hello" /> | tstest.tsx:10:12:10:14 | [VarRef] Bar | semmle.order | 0 | +| tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | tstest.tsx:10:18:10:18 | [Label] b | semmle.label | 1 | +| tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | tstest.tsx:10:18:10:18 | [Label] b | semmle.order | 1 | +| tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | tstest.tsx:10:20:10:26 | [Literal] "hello" | semmle.label | 2 | +| tstest.tsx:10:16:10:26 | [JsxAttribute] a:b="hello" | tstest.tsx:10:20:10:26 | [Literal] "hello" | semmle.order | 2 | +| tstest.tsx:11:1:11:32 | [DeclStmt] const y = ... | tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | semmle.label | 1 | +| tstest.tsx:11:1:11:32 | [DeclStmt] const y = ... | tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | semmle.order | 1 | +| tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | tstest.tsx:11:7:11:7 | [VarDecl] y | semmle.label | 1 | +| tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | tstest.tsx:11:7:11:7 | [VarDecl] y | semmle.order | 1 | +| tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | semmle.label | 2 | +| tstest.tsx:11:7:11:31 | [VariableDeclarator] y = <Ba ... llo" /> | tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | semmle.order | 2 | +| tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | file://:0:0:0:0 | (Attributes) | semmle.label | 2 | +| tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | file://:0:0:0:0 | (Attributes) | semmle.order | 2 | +| tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | tstest.tsx:11:12:11:14 | [VarRef] Bar | semmle.label | 0 | +| tstest.tsx:11:11:11:31 | [JsxElement] <Bar a ... llo" /> | tstest.tsx:11:12:11:14 | [VarRef] Bar | semmle.order | 0 | +| tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | tstest.tsx:11:20:11:20 | [Label] b | semmle.label | 1 | +| tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | tstest.tsx:11:20:11:20 | [Label] b | semmle.order | 1 | +| tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | tstest.tsx:11:22:11:28 | [Literal] "hello" | semmle.label | 2 | +| tstest.tsx:11:16:11:28 | [JsxAttribute] a : b="hello" | tstest.tsx:11:22:11:28 | [Literal] "hello" | semmle.order | 2 | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | tstest.tsx:13:11:13:18 | [Identifier] BarProps | semmle.label | 1 | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | tstest.tsx:13:11:13:18 | [Identifier] BarProps | semmle.order | 1 | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | semmle.label | 2 | +| tstest.tsx:13:1:15:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ring; } | tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | semmle.order | 2 | +| tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | tstest.tsx:14:5:14:9 | [Literal] "a:b" | semmle.label | 1 | +| tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | tstest.tsx:14:5:14:9 | [Literal] "a:b" | semmle.order | 1 | +| tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | tstest.tsx:14:12:14:17 | [KeywordTypeExpr] string | semmle.label | 2 | +| tstest.tsx:14:5:14:18 | [FieldDeclaration] "a:b": string; | tstest.tsx:14:12:14:17 | [KeywordTypeExpr] string | semmle.order | 2 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | tstest.tsx:17:10:17:12 | [VarDecl] Bar | semmle.label | 0 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | tstest.tsx:17:10:17:12 | [VarDecl] Bar | semmle.order | 0 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | tstest.tsx:17:31:19:1 | [BlockStmt] { r ... div>; } | semmle.label | 5 | +| tstest.tsx:17:1:19:1 | [FunctionDeclStmt] functio ... div>; } | tstest.tsx:17:31:19:1 | [BlockStmt] { r ... div>; } | semmle.order | 5 | +| tstest.tsx:17:14:17:18 | [SimpleParameter] props | tstest.tsx:17:21:17:28 | [LocalTypeAccess] BarProps | semmle.label | -2 | +| tstest.tsx:17:14:17:18 | [SimpleParameter] props | tstest.tsx:17:21:17:28 | [LocalTypeAccess] BarProps | semmle.order | -2 | +| tstest.tsx:17:31:19:1 | [BlockStmt] { r ... div>; } | tstest.tsx:18:5:18:37 | [ReturnStmt] return ... </div>; | semmle.label | 1 | +| tstest.tsx:17:31:19:1 | [BlockStmt] { r ... div>; } | tstest.tsx:18:5:18:37 | [ReturnStmt] return ... </div>; | semmle.order | 1 | +| tstest.tsx:18:5:18:37 | [ReturnStmt] return ... </div>; | tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | semmle.label | 1 | +| tstest.tsx:18:5:18:37 | [ReturnStmt] return ... </div>; | tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | semmle.order | 1 | +| tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | file://:0:0:0:0 | (Body) | semmle.label | 1 | +| tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | file://:0:0:0:0 | (Body) | semmle.order | 1 | +| tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | tstest.tsx:18:13:18:15 | [Label] div | semmle.label | 0 | +| tstest.tsx:18:12:18:36 | [JsxElement] <div>{p ... }</div> | tstest.tsx:18:13:18:15 | [Label] div | semmle.order | 0 | +| tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | tstest.tsx:18:18:18:22 | [VarRef] props | semmle.label | 1 | +| tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | tstest.tsx:18:18:18:22 | [VarRef] props | semmle.order | 1 | +| tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | tstest.tsx:18:24:18:28 | [Literal] "a:b" | semmle.label | 2 | +| tstest.tsx:18:18:18:29 | [IndexExpr] props["a:b"] | tstest.tsx:18:24:18:28 | [Literal] "a:b" | semmle.order | 2 | graphProperties | semmle.graphKind | tree | diff --git a/javascript/ql/test/library-tests/JSX/tests.expected b/javascript/ql/test/library-tests/JSX/tests.expected index 974d5608802..50b00601fbe 100644 --- a/javascript/ql/test/library-tests/JSX/tests.expected +++ b/javascript/ql/test/library-tests/JSX/tests.expected @@ -3,6 +3,7 @@ htmlElements | tst.js:6:1:6:10 | <Foo-Bar/> | | tstest.tsx:3:1:3:106 | <a href ... */}</a> | | tstest.tsx:6:1:6:10 | <Foo-Bar/> | +| tstest.tsx:18:12:18:36 | <div>{p ... }</div> | jsxElementAttribute | tst.js:3:1:3:106 | <a href ... */}</a> | 0 | tst.js:3:4:3:14 | href={href} | | tst.js:3:1:3:106 | <a href ... */}</a> | 1 | tst.js:3:16:3:30 | target="_blank" | @@ -12,6 +13,8 @@ jsxElementAttribute | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 1 | tstest.tsx:3:16:3:30 | target="_blank" | | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 2 | tstest.tsx:3:32:3:45 | {...linkTypes} | | tstest.tsx:4:1:4:35 | <MyComp ... "bar"/> | 0 | tstest.tsx:4:25:4:33 | foo="bar" | +| tstest.tsx:10:11:10:29 | <Bar a:b="hello" /> | 0 | tstest.tsx:10:16:10:26 | a:b="hello" | +| tstest.tsx:11:11:11:31 | <Bar a ... llo" /> | 0 | tstest.tsx:11:16:11:28 | a : b="hello" | jsxElementAttributeName | tst.js:3:1:3:106 | <a href ... */}</a> | 0 | href | | tst.js:3:1:3:106 | <a href ... */}</a> | 1 | target | @@ -19,6 +22,8 @@ jsxElementAttributeName | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 0 | href | | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 1 | target | | tstest.tsx:4:1:4:35 | <MyComp ... "bar"/> | 0 | foo | +| tstest.tsx:10:11:10:29 | <Bar a:b="hello" /> | 0 | b | +| tstest.tsx:11:11:11:31 | <Bar a ... llo" /> | 0 | b | jsxElementBody | tst.js:3:1:3:106 | <a href ... */}</a> | 0 | tst.js:3:47:3:54 | Link to | | tst.js:3:1:3:106 | <a href ... */}</a> | 1 | tst.js:3:56:3:59 | href | @@ -28,6 +33,7 @@ jsxElementBody | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 1 | tstest.tsx:3:56:3:59 | href | | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 2 | tstest.tsx:3:61:3:62 | . | | tstest.tsx:3:1:3:106 | <a href ... */}</a> | 3 | tstest.tsx:3:63:3:102 | {/*TODO ... text*/} | +| tstest.tsx:18:12:18:36 | <div>{p ... }</div> | 0 | tstest.tsx:18:18:18:29 | props["a:b"] | jsxElementName | tst.js:3:1:3:106 | <a href ... */}</a> | tst.js:3:2:3:2 | a | a | | tst.js:4:1:4:35 | <MyComp ... "bar"/> | tst.js:4:2:4:23 | MyCompo ... ncyLink | MyComponents.FancyLink | @@ -39,6 +45,9 @@ jsxElementName | tstest.tsx:5:1:5:6 | <Foo/> | tstest.tsx:5:2:5:4 | Foo | Foo | | tstest.tsx:6:1:6:10 | <Foo-Bar/> | tstest.tsx:6:2:6:8 | Foo-Bar | Foo-Bar | | tstest.tsx:7:33:7:38 | <Foo/> | tstest.tsx:7:34:7:36 | Foo | Foo | +| tstest.tsx:10:11:10:29 | <Bar a:b="hello" /> | tstest.tsx:10:12:10:14 | Bar | Bar | +| tstest.tsx:11:11:11:31 | <Bar a ... llo" /> | tstest.tsx:11:12:11:14 | Bar | Bar | +| tstest.tsx:18:12:18:36 | <div>{p ... }</div> | tstest.tsx:18:13:18:15 | div | div | jsxFragments | tst.js:7:16:7:52 | <> frag ... ext </> | 0 | tst.js:7:18:7:32 | fragment text | | tst.js:7:16:7:52 | <> frag ... ext </> | 1 | tst.js:7:33:7:38 | <Foo/> | diff --git a/javascript/ql/test/library-tests/JSX/tstest.tsx b/javascript/ql/test/library-tests/JSX/tstest.tsx index c1011712e19..966d6ced2fd 100644 --- a/javascript/ql/test/library-tests/JSX/tstest.tsx +++ b/javascript/ql/test/library-tests/JSX/tstest.tsx @@ -5,3 +5,15 @@ var linkTypes = { rel: "noopener noreferrer" }; <Foo/>; // interpreted as a custom component because of capitalisation <Foo-Bar/>; // interpreted as an HTML element because of the dash var fragment = <> fragment text <Foo/> more text </> + +// Both of these are equivalent: +const x = <Bar a:b="hello" />; +const y = <Bar a : b="hello" />; + +interface BarProps { + "a:b": string; +} + +function Bar(props: BarProps) { + return <div>{props["a:b"]}</div>; +} \ No newline at end of file From 8eed1a95f638496442695bb584dd2a8e4aa42d6f Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 23:16:52 +0200 Subject: [PATCH 101/219] stop recursive fromRhs related to getLaterBaseAccess --- javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll index e9828e5bf25..35ba8cfe601 100644 --- a/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll @@ -234,7 +234,8 @@ module AccessPath { or baseName = fromRhs(write.getBase(), root) or - baseName = fromRhs(GetLaterAccess::getLaterBaseAccess(write), root) + baseName = fromRhs(GetLaterAccess::getLaterBaseAccess(write), root) and + not baseName.matches("%.%") ) or exists(GlobalVariable var | From 1b44b59842d0d5d4d2d297b1cea94771584a3491 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 23:20:23 +0200 Subject: [PATCH 102/219] add stress test --- .../library-tests/GlobalAccessPaths/stress.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 javascript/ql/test/library-tests/GlobalAccessPaths/stress.js diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/stress.js b/javascript/ql/test/library-tests/GlobalAccessPaths/stress.js new file mode 100644 index 00000000000..198ccf6e8e2 --- /dev/null +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/stress.js @@ -0,0 +1,33 @@ + +// stress test for global access path computation +var MyObject = {} +MyObject.Foo1 = { inner: MyObject }; +MyObject.Foo2 = { inner: MyObject }; +MyObject.Foo3 = { inner: MyObject }; +MyObject.Foo4 = { inner: MyObject }; +MyObject.Foo5 = { inner: MyObject }; +MyObject.Foo6 = { inner: MyObject }; +MyObject.Foo7 = { inner: MyObject }; +MyObject.Foo8 = { inner: MyObject }; +MyObject.Foo9 = { inner: MyObject }; +MyObject.Fooa = { inner: MyObject }; +MyObject.Foob = { inner: MyObject }; +MyObject.Fooc = { inner: MyObject }; +MyObject.Food = { inner: MyObject }; +MyObject.Fooe = { inner: MyObject }; +MyObject.Foof = { inner: MyObject }; +MyObject.Foog = { inner: MyObject }; +MyObject.Fooh = { inner: MyObject }; +MyObject.Fooi = { inner: MyObject }; +MyObject.Fooj = { inner: MyObject }; +MyObject.Fook = { inner: MyObject }; +MyObject.Fool = { inner: MyObject }; +MyObject.Foom = { inner: MyObject }; +MyObject.Foon = { inner: MyObject }; +MyObject.Fooo = { inner: MyObject }; +MyObject.Foop = { inner: MyObject }; +MyObject.Fooq = { inner: MyObject }; +MyObject.Foor = { inner: MyObject }; +MyObject.Foos = { inner: MyObject }; +MyObject.Foot = { inner: MyObject }; +exports.MyObject = MyObject; \ No newline at end of file From ef7e9a674c034721562b2d5a996b879fe67a1108 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 00:16:55 +0000 Subject: [PATCH 103/219] Add changed framework coverage reports --- .../library-coverage/coverage.csv | 334 +++++++++--------- .../library-coverage/coverage.rst | 18 +- 2 files changed, 176 insertions(+), 176 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 0bd4f53a9a7..4e4b1ab7e1f 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -1,167 +1,167 @@ -package,sink,source,summary,sink:bean-validation,sink:create-file,sink:fragment-injection,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:read-file,sink:regex-use,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:ssti,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-external-storage-dir,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value -android.app,35,,103,,,11,,,,7,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,18,85 -android.content,24,31,154,,,,,,,16,,,,,,,,,,,,,,,,,,,8,,,,,,,4,,27,,63,91 -android.database,59,,41,,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,41, -android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 -android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,41,81 -android.support.v4.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -android.util,6,16,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,16,, -android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,2,, -android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, -androidx.core.app,6,,95,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,12,83 -androidx.fragment.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -androidx.slice,2,5,88,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,5,,27,61 -cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -com.google.common.base,4,,87,,,,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,,63,24 -com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 -com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 -com.google.common.flogger,29,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,,,, -com.google.common.io,8,,73,,2,,,,,,,,,,,,,,,5,,,,,,,,,,,,1,,,,,,,,72,1 -com.google.gson,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,14 -com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, -com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, -com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,, -com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, -com.thoughtworks.xstream,1,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, -com.unboundid.ldap.sdk,17,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,, -com.zaxxer.hikari,2,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -freemarker.cache,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, -freemarker.template,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,, -groovy.lang,26,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -groovy.text,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -groovy.util,5,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -hudson,44,,16,,19,,,,,,,,,,,,,6,,17,,,,,,,,,,,,2,,,,,,,,16, -io.jsonwebtoken,,2,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,4, -io.netty.bootstrap,3,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,, -io.netty.buffer,,,207,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,130,77 -io.netty.channel,9,2,,,,,,,,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,2,, -io.netty.handler.codec,4,13,259,,,,,,,,,,,,,,,3,,1,,,,,,,,,,,,,,,,,,,13,143,116 -io.netty.handler.ssl,2,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,, -io.netty.handler.stream,1,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,, -io.netty.resolver,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -io.netty.util,2,,23,,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,21,2 -jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, -jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 -java.awt,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3 -java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -java.io,44,,45,,18,,,,,,,,,,,,,,,4,,,,,,,,,,,,22,,,,,,,,43,2 -java.lang,18,,92,,,,,,,,,,,,8,,,,,5,,4,,,1,,,,,,,,,,,,,,,56,36 -java.net,13,3,20,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,3,20, -java.nio,38,,31,,22,,,,,,,,,,,,,,,13,,,,,,,,,,,,3,,,,,,,,31, -java.sql,13,,3,,,,,,,,4,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,2,1 -java.util,44,,484,,,,,,,,,,,,34,,,,,,,,5,2,,1,2,,,,,,,,,,,,,44,440 -javafx.scene.web,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, -javax.imageio.stream,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, -javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -javax.management.remote,2,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,, -javax.naming,7,,1,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,,,,1, -javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,, -javax.script,1,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, -javax.servlet,5,21,2,,,,,3,1,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,21,2, -javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, -javax.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -javax.ws.rs.core,3,,149,,,,,1,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 -javax.xml.transform,2,,6,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,6, -javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,, -jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 -kotlin,16,,1843,,11,,,,,,,,,,,,,2,,3,,,,,,,,,,,,,,,,,,,,1836,7 -net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,, -ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,, -okhttp3,4,,47,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,22,25 -org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.compress.archivers.tar,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4, -org.apache.commons.httpclient.util,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.commons.io,111,,560,,93,,,,,,,,,,,,,15,,1,,,,,,,,,,,,2,,,,,,,,546,14 -org.apache.commons.jelly,6,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.jexl2,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.jexl3,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.lang3,6,,424,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,293,131 -org.apache.commons.logging,6,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.net,9,12,,,,,,,,,,,,,,,,6,,3,,,,,,,,,,,,,,,,,,,12,, -org.apache.commons.ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 -org.apache.directory.ldap.client.api,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hadoop.fs,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10, -org.apache.hadoop.hive.metastore,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,,, -org.apache.hc.client5.http.async.methods,84,,,,,,,,,,,,,,,,,84,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.client5.http.classic.methods,37,,,,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.client5.http.fluent,19,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.core5.benchmark,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.hc.core5.http,73,2,45,,,,,,,,,,,,,,,72,,,,,,,,,,,,,,,,,1,,,,2,45, -org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18, -org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 -org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,, -org.apache.http,48,3,94,,,,,,,,,,,,,,,46,,,,,,,,,,,,,,,,,2,,,,3,86,8 -org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,57, -org.apache.log4j,11,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.logging.log4j,359,,8,,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,,,,4,4 -org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.shiro.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.tools.ant,11,,,,3,,,,,,,,,,,,,,,8,,,,,,,,,,,,,,,,,,,,, -org.apache.tools.zip,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.velocity.app,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,, -org.apache.velocity.runtime,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,, -org.codehaus.cargo.container.installer,3,,,,2,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -org.codehaus.groovy.control,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,, -org.eclipse.jetty.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -org.geogebra.web.full.main,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,, -org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,, -org.jboss.logging,324,,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,,,,, -org.jdbi.v3.core,6,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,, -org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 -org.kohsuke.stapler,3,,1,,,,,,,,,,,,,,,1,,1,,,,,,,,,,,1,,,,,,,,,1, -org.mvel2,16,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,,,, -org.openjdk.jmh.runner.options,1,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.scijava.log,13,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,, -org.slf4j,55,,6,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,,,2,4 -org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 -org.springframework.boot.jdbc,1,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 -org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -org.springframework.http,14,,71,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,,,61,10 -org.springframework.jdbc.core,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,, -org.springframework.jdbc.datasource,4,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,, -org.springframework.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.ldap,47,,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, -org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 -org.springframework.util,3,,142,,2,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,90,52 -org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, -org.springframework.web.client,13,3,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,3,, -org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, -org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, -org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.web.util,,,165,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,140,25 -org.thymeleaf,2,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,2, -org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, -play.libs.ws,2,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,, -play.mvc,,13,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,24, -ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 -ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -retrofit2,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, +package,sink,source,summary,sink:bean-validation,sink:file-content-store,sink:fragment-injection,sink:groovy-injection,sink:hostname-verification,sink:html-injection,sink:information-leak,sink:intent-redirection,sink:jexl-injection,sink:jndi-injection,sink:js-injection,sink:ldap-injection,sink:log-injection,sink:mvel-injection,sink:ognl-injection,sink:path-injection,sink:pending-intents,sink:regex-use,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:request-forgery,sink:response-splitting,sink:sql-injection,sink:template-injection,sink:url-redirection,sink:xpath-injection,sink:xslt-injection,source:android-external-storage-dir,source:contentprovider,source:remote,summary:taint,summary:value +android.app,35,,103,,,11,,,,,7,,,,,,,,,17,,,,,,,,,,,,,,,,,,18,85 +android.content,24,31,154,,,,,,,,16,,,,,,,,,,,,,,,,,,,8,,,,,4,27,,63,91 +android.database,59,,41,,,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,41, +android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 +android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,41,81 +android.support.v4.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +android.util,6,16,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,16,, +android.webkit,3,2,,,,,,,2,,,,,1,,,,,,,,,,,,,,,,,,,,,,,2,, +android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1, +androidx.core.app,6,,95,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,12,83 +androidx.fragment.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +androidx.slice,2,5,88,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,5,,27,61 +cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +com.google.common.base,4,,87,,,,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,63,24 +com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 +com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 +com.google.common.flogger,29,,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,, +com.google.common.io,8,,73,,1,,,,,,,,,,,,,,7,,,,,,,,,,,,,,,,,,,72,1 +com.google.gson,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,14 +com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, +com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, +com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,, +com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, +com.thoughtworks.xstream,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +com.unboundid.ldap.sdk,17,,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,, +com.zaxxer.hikari,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, +flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +freemarker.cache,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,, +freemarker.template,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,, +groovy.lang,26,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +groovy.text,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +groovy.util,5,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +hudson,44,,16,,2,,,,,,,,,,,,,,36,,,,,,,,,6,,,,,,,,,,16, +io.jsonwebtoken,,2,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,4, +io.netty.bootstrap,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,, +io.netty.buffer,,,207,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,130,77 +io.netty.channel,9,2,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,2,, +io.netty.handler.codec,4,13,259,,,,,,,,,,,,,,,,1,,,,,,,,,3,,,,,,,,,13,143,116 +io.netty.handler.ssl,2,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,, +io.netty.handler.stream,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +io.netty.resolver,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +io.netty.util,2,,23,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,,,,,,,21,2 +jakarta.faces.context,2,7,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,, +jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,94,55 +java.awt,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3 +java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +java.io,44,,45,,22,,,,,,,,,,,,,,22,,,,,,,,,,,,,,,,,,,43,2 +java.lang,18,,92,,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 +java.net,13,3,20,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,20, +java.nio,38,,31,,3,,,,,,,,,,,,,,35,,,,,,,,,,,,,,,,,,,31, +java.sql,13,,3,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2,1 +java.util,44,,484,,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,44,440 +javafx.scene.web,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +javax.faces.context,2,7,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,, +javax.imageio.stream,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, +javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +javax.management.remote,2,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.naming,7,,1,,,,,,,,,,6,,1,,,,,,,,,,,,,,,,,,,,,,,1, +javax.net.ssl,2,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.script,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,, +javax.servlet,5,21,2,,,,,,,1,,,,,,,,,1,,,,,,,,,,3,,,,,,,,21,2, +javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, +javax.ws.rs.client,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +javax.ws.rs.core,3,,149,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,2,,,,,,94,55 +javax.xml.transform,2,,6,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,1,,,,6, +javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,, +jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +kotlin,16,,1843,,,,,,,,,,,,,,,,14,,,,,,,,,2,,,,,,,,,,1836,7 +net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,, +ognl,6,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, +okhttp3,4,,47,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,22,25 +org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.compress.archivers.tar,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4, +org.apache.commons.httpclient.util,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.commons.io,111,,560,,2,,,,,,,,,,,,,,94,,,,,,,,,15,,,,,,,,,,546,14 +org.apache.commons.jelly,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,, +org.apache.commons.jexl2,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.jexl3,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.lang3,6,,424,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,293,131 +org.apache.commons.logging,6,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.net,9,12,,,,,,,,,,,,,,,,,3,,,,,,,,,6,,,,,,,,,12,, +org.apache.commons.ognl,6,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 +org.apache.directory.ldap.client.api,1,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.hadoop.fs,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10, +org.apache.hadoop.hive.metastore,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,, +org.apache.hc.client5.http.async.methods,84,,,,,,,,,,,,,,,,,,,,,,,,,,,84,,,,,,,,,,, +org.apache.hc.client5.http.classic.methods,37,,,,,,,,,,,,,,,,,,,,,,,,,,,37,,,,,,,,,,, +org.apache.hc.client5.http.fluent,19,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,, +org.apache.hc.core5.benchmark,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.hc.core5.http,73,2,45,,,,,,1,,,,,,,,,,,,,,,,,,,72,,,,,,,,,2,45, +org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18, +org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 +org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,, +org.apache.http,48,3,94,,,,,,2,,,,,,,,,,,,,,,,,,,46,,,,,,,,,3,86,8 +org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,57, +org.apache.log4j,11,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,, +org.apache.logging.log4j,359,,8,,,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,4,4 +org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.shiro.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.tools.ant,11,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,, +org.apache.tools.zip,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.velocity.app,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,, +org.apache.velocity.runtime,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,, +org.codehaus.cargo.container.installer,3,,,,,,,,,,,,,,,,,,2,,,,,,,,,1,,,,,,,,,,, +org.codehaus.groovy.control,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,, +org.eclipse.jetty.client,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +org.geogebra.web.full.main,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,, +org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,, +org.jboss.logging,324,,,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,, +org.jdbi.v3.core,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,, +org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,, +org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 +org.kohsuke.stapler,3,,1,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,1,,,,,,1, +org.mvel2,16,,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,, +org.openjdk.jmh.runner.options,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, +org.scijava.log,13,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,, +org.slf4j,55,,6,,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,2,4 +org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 +org.springframework.boot.jdbc,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 +org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +org.springframework.http,14,,71,,,,,,,,,,,,,,,,,,,,,,,,,14,,,,,,,,,,61,10 +org.springframework.jdbc.core,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,, +org.springframework.jdbc.datasource,4,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,, +org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,, +org.springframework.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.ldap,47,,,,,,,,,,,,33,,14,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, +org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 +org.springframework.util,3,,142,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,90,52 +org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, +org.springframework.web.client,13,3,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,, +org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, +org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, +org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, +org.springframework.web.util,,,165,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,140,25 +org.thymeleaf,2,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,2, +org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, +play.libs.ws,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, +play.mvc,,13,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,24, +ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 +ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +retrofit2,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index b87eeb390fe..644b4aaef6a 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -6,22 +6,22 @@ Java framework & library support :class: fullWidthTable :widths: auto - Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑319` :sub:`Cleartext transmission` + Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑918` :sub:`Request Forgery` Android,``android.*``,52,481,138,,3,67,,, Android extensions,``androidx.*``,5,183,19,,,,,, `Apache Commons Collections <https://commons.apache.org/proper/commons-collections/>`_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,, - `Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,560,111,93,,,,,15 + `Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,560,111,94,,,,,15 `Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,424,6,,,,,, `Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,, `Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,182,122,,3,,,,119 `Apache Log4j 2 <https://logging.apache.org/log4j/2.0/>`_,``org.apache.logging.log4j``,,8,359,,,,,, - `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,41,2,,,,, + `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,41,7,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,, `JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,, - Java Standard Library,``java.*``,3,679,170,40,,9,,,13 - Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,1,4,,1,1,2 - Kotlin Standard Library,``kotlin*``,,1843,16,11,,,,,2 - `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,113,2,,28,14,,29 - Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,890,520,26,,18,18,,185 - Totals,,255,9182,1973,175,10,122,33,1,365 + Java Standard Library,``java.*``,3,679,170,62,,9,,,17 + Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 + Kotlin Standard Library,``kotlin*``,,1843,16,14,,,,,2 + `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,113,3,,28,14,,34 + Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,890,520,60,,18,18,,193 + Totals,,255,9182,1973,242,10,122,33,1,382 From 527fe523a88be1283039ef3cd51091db57b16fb0 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Fri, 19 May 2023 16:42:08 +0200 Subject: [PATCH 104/219] Add PathCreation.qll sinks to models-as-data The old PathCreation sinks can't be removed because doing so would cause alert wobble in the path injection queries. See their getReportingNode predicates. --- .../2023-05-19-path-injection-sinks-mad.md | 4 ++++ java/ql/lib/ext/java.io.model.yml | 5 +++++ java/ql/lib/ext/java.nio.file.model.yml | 13 +++++++++---- java/ql/lib/ext/java.nio.model.yml | 1 + .../semmle/code/java/security/TaintedPathQuery.qll | 13 ++----------- java/ql/src/Security/CWE/CWE-022/TaintedPath.ql | 1 + .../ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql | 1 + .../Security/CWE/CWE-073/FilePathInjection.ql | 3 +-- .../security/CWE-073/FilePathInjection.expected | 11 +++++++++++ .../SupportedExternalSinks.expected | 1 + 10 files changed, 36 insertions(+), 17 deletions(-) create mode 100644 java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md diff --git a/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md b/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md new file mode 100644 index 00000000000..5f666a0de4f --- /dev/null +++ b/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kinds `create-file` and `read-file`. diff --git a/java/ql/lib/ext/java.io.model.yml b/java/ql/lib/ext/java.io.model.yml index e0920d7df16..83e57a68c74 100644 --- a/java/ql/lib/ext/java.io.model.yml +++ b/java/ql/lib/ext/java.io.model.yml @@ -3,6 +3,10 @@ extensions: pack: codeql/java-all extensible: sinkModel data: + - ["java.io", "File", False, "File", "(File,String)", "", "Argument[1]", "path-injection", "manual"] # old PathCreation + - ["java.io", "File", False, "File", "(String)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation + - ["java.io", "File", False, "File", "(String,String)", "", "Argument[0..1]", "path-injection", "manual"] # old PathCreation + - ["java.io", "File", False, "File", "(URI)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation - ["java.io", "File", True, "createTempFile", "(String,String,File)", "", "Argument[2]", "path-injection", "ai-manual"] - ["java.io", "File", True, "renameTo", "(File)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.io", "FileInputStream", True, "FileInputStream", "(File)", "", "Argument[0]", "path-injection", "ai-manual"] @@ -11,6 +15,7 @@ extensions: - ["java.io", "FileOutputStream", False, "write", "", "", "Argument[0]", "file-content-store", "manual"] - ["java.io", "FileReader", True, "FileReader", "(File)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.io", "FileReader", True, "FileReader", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["java.io", "FileReader", True, "FileReader", "(String,Charset)", "", "Argument[0]", "path-injection", "manual"] - ["java.io", "FileSystem", True, "createDirectory", "(File)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.io", "FileWriter", False, "FileWriter", "", "", "Argument[0]", "path-injection", "manual"] - ["java.io", "PrintStream", False, "PrintStream", "(File)", "", "Argument[0]", "path-injection", "manual"] diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index e4519fbc071..475ddc43eef 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -3,11 +3,9 @@ extensions: pack: codeql/java-all extensible: sinkModel data: - - ["java.nio.file", "Files", False, "copy", "(Path,OutputStream)", "", "Argument[0]", "path-injection", "manual"] - - ["java.nio.file", "Files", False, "copy", "(Path,Path,CopyOption[])", "", "Argument[0]", "path-injection", "manual"] - - ["java.nio.file", "Files", False, "copy", "(Path,Path,CopyOption[])", "", "Argument[1]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "copy", "(InputStream,Path,CopyOption[])", "", "Argument[0]", "file-content-store", "manual"] - - ["java.nio.file", "Files", False, "copy", "(InputStream,Path,CopyOption[])", "", "Argument[1]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "", "", "Argument[1]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createDirectories", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createDirectory", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "path-injection", "manual"] @@ -40,6 +38,13 @@ extensions: - ["java.nio.file", "Files", True, "delete", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", True, "newInputStream", "(Path,OpenOption[])", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", True, "newOutputStream", "(Path,OpenOption[])", "", "Argument[0]", "path-injection", "ai-manual"] + - ["java.nio.file", "FileSystem", False, "getPath", "", "", "Argument[0..1]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Path", False, "of", "(String,String[])", "", "Argument[0..1]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Path", False, "of", "(URI)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Path", False, "resolve", "(String)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Path", False, "resolveSibling", "(String)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Paths", False, "get", "(String,String[])", "", "Argument[0..1]", "path-injection", "manual"] # old PathCreation + - ["java.nio.file", "Paths", False, "get", "(URI)", "", "Argument[0]", "path-injection", "manual"] # old PathCreation - ["java.nio.file", "SecureDirectoryStream", True, "deleteDirectory", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "SecureDirectoryStream", True, "deleteFile", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - addsTo: diff --git a/java/ql/lib/ext/java.nio.model.yml b/java/ql/lib/ext/java.nio.model.yml index 1548dc2c649..9fbe1b253ec 100644 --- a/java/ql/lib/ext/java.nio.model.yml +++ b/java/ql/lib/ext/java.nio.model.yml @@ -6,6 +6,7 @@ extensions: - ["java.nio", "ByteBuffer", False, "array", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.nio", "ByteBuffer", False, "get", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.nio", "ByteBuffer", False, "wrap", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["java.nio", "Paths", False, "get", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "manual"] # old PathCreation - addsTo: pack: codeql/java-all diff --git a/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll b/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll index 4fa64846c91..a90a23c2165 100644 --- a/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll +++ b/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll @@ -5,7 +5,6 @@ import semmle.code.java.frameworks.Networking import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSources private import semmle.code.java.dataflow.ExternalFlow -import semmle.code.java.security.PathCreation import semmle.code.java.security.PathSanitizer /** @@ -55,11 +54,7 @@ private class TaintPreservingUriCtorParam extends Parameter { module TaintedPathConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(PathCreation p).getAnInput() - or - sinkNode(sink, "path-injection") - } + predicate isSink(DataFlow::Node sink) { sinkNode(sink, "path-injection") } predicate isBarrier(DataFlow::Node sanitizer) { sanitizer.getType() instanceof BoxedType or @@ -82,11 +77,7 @@ module TaintedPathFlow = TaintTracking::Global<TaintedPathConfig>; module TaintedPathLocalConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput } - predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(PathCreation p).getAnInput() - or - sinkNode(sink, "path-injection") - } + predicate isSink(DataFlow::Node sink) { sinkNode(sink, "path-injection") } predicate isBarrier(DataFlow::Node sanitizer) { sanitizer.getType() instanceof BoxedType or diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 2d73514d97b..96e8e66c7cd 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -14,6 +14,7 @@ */ import java +import semmle.code.java.security.PathCreation import semmle.code.java.security.TaintedPathQuery import TaintedPathFlow::PathGraph diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql index c017b8a3aa9..8e56121883f 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql @@ -14,6 +14,7 @@ */ import java +import semmle.code.java.security.PathCreation import semmle.code.java.security.TaintedPathQuery import TaintedPathLocalFlow::PathGraph diff --git a/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql index 8e113837bca..ba3411e4da2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql @@ -16,7 +16,6 @@ import java import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.ExternalFlow import semmle.code.java.dataflow.FlowSources -import semmle.code.java.security.PathCreation import JFinalController import semmle.code.java.security.PathSanitizer import InjectFilePathFlow::PathGraph @@ -52,7 +51,7 @@ module InjectFilePathConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(PathCreation p).getAnInput() and + sinkNode(sink, "path-injection") and not sink instanceof NormalizedPathNode } diff --git a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.expected index 5720de5c4b9..cd2b49f28c1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.expected @@ -2,7 +2,12 @@ edges | FilePathInjection.java:21:21:21:34 | getPara(...) : String | FilePathInjection.java:26:47:26:59 | finalFilePath | | FilePathInjection.java:64:21:64:34 | getPara(...) : String | FilePathInjection.java:72:47:72:59 | finalFilePath | | FilePathInjection.java:87:21:87:34 | getPara(...) : String | FilePathInjection.java:95:47:95:59 | finalFilePath | +| FilePathInjection.java:177:50:177:58 | file : File | FilePathInjection.java:182:30:182:33 | file | | FilePathInjection.java:205:17:205:44 | getParameter(...) : String | FilePathInjection.java:209:24:209:31 | filePath | +| FilePathInjection.java:205:17:205:44 | getParameter(...) : String | FilePathInjection.java:209:24:209:31 | filePath : String | +| FilePathInjection.java:209:15:209:32 | new File(...) : File | FilePathInjection.java:217:19:217:22 | file : File | +| FilePathInjection.java:209:24:209:31 | filePath : String | FilePathInjection.java:209:15:209:32 | new File(...) : File | +| FilePathInjection.java:217:19:217:22 | file : File | FilePathInjection.java:177:50:177:58 | file : File | nodes | FilePathInjection.java:21:21:21:34 | getPara(...) : String | semmle.label | getPara(...) : String | | FilePathInjection.java:26:47:26:59 | finalFilePath | semmle.label | finalFilePath | @@ -10,11 +15,17 @@ nodes | FilePathInjection.java:72:47:72:59 | finalFilePath | semmle.label | finalFilePath | | FilePathInjection.java:87:21:87:34 | getPara(...) : String | semmle.label | getPara(...) : String | | FilePathInjection.java:95:47:95:59 | finalFilePath | semmle.label | finalFilePath | +| FilePathInjection.java:177:50:177:58 | file : File | semmle.label | file : File | +| FilePathInjection.java:182:30:182:33 | file | semmle.label | file | | FilePathInjection.java:205:17:205:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FilePathInjection.java:209:15:209:32 | new File(...) : File | semmle.label | new File(...) : File | | FilePathInjection.java:209:24:209:31 | filePath | semmle.label | filePath | +| FilePathInjection.java:209:24:209:31 | filePath : String | semmle.label | filePath : String | +| FilePathInjection.java:217:19:217:22 | file : File | semmle.label | file : File | subpaths #select | FilePathInjection.java:26:47:26:59 | finalFilePath | FilePathInjection.java:21:21:21:34 | getPara(...) : String | FilePathInjection.java:26:47:26:59 | finalFilePath | External control of file name or path due to $@. | FilePathInjection.java:21:21:21:34 | getPara(...) | user-provided value | | FilePathInjection.java:72:47:72:59 | finalFilePath | FilePathInjection.java:64:21:64:34 | getPara(...) : String | FilePathInjection.java:72:47:72:59 | finalFilePath | External control of file name or path due to $@. | FilePathInjection.java:64:21:64:34 | getPara(...) | user-provided value | | FilePathInjection.java:95:47:95:59 | finalFilePath | FilePathInjection.java:87:21:87:34 | getPara(...) : String | FilePathInjection.java:95:47:95:59 | finalFilePath | External control of file name or path due to $@. | FilePathInjection.java:87:21:87:34 | getPara(...) | user-provided value | +| FilePathInjection.java:182:30:182:33 | file | FilePathInjection.java:205:17:205:44 | getParameter(...) : String | FilePathInjection.java:182:30:182:33 | file | External control of file name or path due to $@. | FilePathInjection.java:205:17:205:44 | getParameter(...) | user-provided value | | FilePathInjection.java:209:24:209:31 | filePath | FilePathInjection.java:205:17:205:44 | getParameter(...) : String | FilePathInjection.java:209:24:209:31 | filePath | External control of file name or path due to $@. | FilePathInjection.java:205:17:205:44 | getParameter(...) | user-provided value | diff --git a/java/ql/test/query-tests/Telemetry/SupportedExternalSinks/SupportedExternalSinks.expected b/java/ql/test/query-tests/Telemetry/SupportedExternalSinks/SupportedExternalSinks.expected index 6cb849601d5..5f0ed7d05df 100644 --- a/java/ql/test/query-tests/Telemetry/SupportedExternalSinks/SupportedExternalSinks.expected +++ b/java/ql/test/query-tests/Telemetry/SupportedExternalSinks/SupportedExternalSinks.expected @@ -1,2 +1,3 @@ +| java.io.File#File(String) | 1 | | java.io.FileWriter#FileWriter(File) | 1 | | java.net.URL#openStream() | 1 | From 77d27992784255876a01f66b8dda07ad974d925d Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Fri, 2 Jun 2023 10:33:44 +0200 Subject: [PATCH 105/219] Update javascript/ql/lib/semmle/javascript/Regexp.qll Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com> --- javascript/ql/lib/semmle/javascript/Regexp.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/Regexp.qll b/javascript/ql/lib/semmle/javascript/Regexp.qll index a20f5343428..de1a3f0d98f 100644 --- a/javascript/ql/lib/semmle/javascript/Regexp.qll +++ b/javascript/ql/lib/semmle/javascript/Regexp.qll @@ -959,7 +959,7 @@ private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) { } /** - * Holds if `call` is a call to `search` whose result is used in a way that suggests it returns a number. + * Holds if `value` is used in a way that suggests it returns a number. */ pragma[inline] private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) { From 7b17b92aca4b703c09530d3beb776f28fa34aca9 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Fri, 2 Jun 2023 10:36:11 +0200 Subject: [PATCH 106/219] Fix typo in spelling of expectation --- csharp/ql/test/TestUtilities/InlineFlowTest.qll | 2 +- go/ql/test/TestUtilities/InlineFlowTest.qll | 2 +- java/ql/test/TestUtilities/InlineFlowTest.qll | 2 +- python/ql/test/experimental/meta/ConceptsTest.qll | 2 +- ruby/ql/test/TestUtilities/InlineFlowTest.qll | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/ql/test/TestUtilities/InlineFlowTest.qll b/csharp/ql/test/TestUtilities/InlineFlowTest.qll index f69b81caf64..a31d531e1b6 100644 --- a/csharp/ql/test/TestUtilities/InlineFlowTest.qll +++ b/csharp/ql/test/TestUtilities/InlineFlowTest.qll @@ -13,7 +13,7 @@ * * ``` * - * To declare expecations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. + * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. * Example of the corresponding test file, e.g. Test.cs * ```csharp * public class Test diff --git a/go/ql/test/TestUtilities/InlineFlowTest.qll b/go/ql/test/TestUtilities/InlineFlowTest.qll index f080de86e16..0726265699f 100644 --- a/go/ql/test/TestUtilities/InlineFlowTest.qll +++ b/go/ql/test/TestUtilities/InlineFlowTest.qll @@ -7,7 +7,7 @@ * import TestUtilities.InlineFlowTest * ``` * - * To declare expecations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. + * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. * Example of the corresponding test file, e.g. Test.java * ```go * public class Test { diff --git a/java/ql/test/TestUtilities/InlineFlowTest.qll b/java/ql/test/TestUtilities/InlineFlowTest.qll index 1731b73f24e..5e37770a279 100644 --- a/java/ql/test/TestUtilities/InlineFlowTest.qll +++ b/java/ql/test/TestUtilities/InlineFlowTest.qll @@ -7,7 +7,7 @@ * import TestUtilities.InlineFlowTest * ``` * - * To declare expecations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. + * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. * Example of the corresponding test file, e.g. Test.java * ```java * public class Test { diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 3f76315e8b1..27c8cb99ab4 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -317,7 +317,7 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest { location = response.getLocation() and element = response.toString() and // Ensure that an expectation value such as "mimetype=text/html; charset=utf-8" is parsed as a - // single expectation with tag mimetype, and not as two expecations with tags mimetype and + // single expectation with tag mimetype, and not as two expectations with tags mimetype and // charset. ( if exists(response.getMimetype().indexOf(" ")) diff --git a/ruby/ql/test/TestUtilities/InlineFlowTest.qll b/ruby/ql/test/TestUtilities/InlineFlowTest.qll index dbac70ede0a..d653a3e414e 100644 --- a/ruby/ql/test/TestUtilities/InlineFlowTest.qll +++ b/ruby/ql/test/TestUtilities/InlineFlowTest.qll @@ -11,7 +11,7 @@ * select sink, source, sink, "$@", source, source.toString() * ``` * - * To declare expecations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. + * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. * Example of the corresponding test file, e.g. test.rb * ```rb * s = source(1) From cc8aac5435b73b4b7ecf805c2ed12e6607b9cd6e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Tue, 30 May 2023 15:14:03 -0700 Subject: [PATCH 107/219] C++: Use the 'shortestDistances' HOP to count indirections instead of manual recursion. This avoids cyclic problems when we have invalid types. --- .../dataflow/internal/SsaInternalsCommon.qll | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll index 84cdefe7823..8f6b581edcf 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll @@ -139,6 +139,20 @@ class AllocationInstruction extends CallInstruction { AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction } } +private predicate isIndirectionType(Type t) { t instanceof Indirection } + +private predicate hasUnspecifiedBaseType(Indirection t, Type base) { + base = t.getBaseType().getUnspecifiedType() +} + +/** + * Holds if `t2` is the same type as `t1`, but after stripping away `result` number + * of indirections. + * Furthermore, specifies in `t2` been deeply stripped and typedefs has been resolved. + */ +private int getNumberOfIndirectionsImpl(Type t1, Type t2) = + shortestDistances(isIndirectionType/1, hasUnspecifiedBaseType/2)(t1, t2, result) + /** * An abstract class for handling indirections. * @@ -157,7 +171,10 @@ abstract class Indirection extends Type { * For example, the number of indirections of a variable `p` of type * `int**` is `3` (i.e., `p`, `*p` and `**p`). */ - abstract int getNumberOfIndirections(); + final int getNumberOfIndirections() { + result = + getNumberOfIndirectionsImpl(this.getType(), any(Type end | not end instanceof Indirection)) + } /** * Holds if `deref` is an instruction that behaves as a `LoadInstruction` @@ -195,19 +212,11 @@ private class PointerOrArrayOrReferenceTypeIndirection extends Indirection insta PointerOrArrayOrReferenceTypeIndirection() { baseType = PointerOrArrayOrReferenceType.super.getBaseType() } - - override int getNumberOfIndirections() { - result = 1 + countIndirections(this.getBaseType().getUnspecifiedType()) - } } private class PointerWrapperTypeIndirection extends Indirection instanceof PointerWrapper { PointerWrapperTypeIndirection() { baseType = PointerWrapper.super.getBaseType() } - override int getNumberOfIndirections() { - result = 1 + countIndirections(this.getBaseType().getUnspecifiedType()) - } - override predicate isAdditionalDereference(Instruction deref, Operand address) { exists(CallInstruction call | operandForFullyConvertedCall(getAUse(deref), call) and @@ -228,10 +237,6 @@ private module IteratorIndirections { baseType = super.getValueType() } - override int getNumberOfIndirections() { - result = 1 + countIndirections(this.getBaseType().getUnspecifiedType()) - } - override predicate isAdditionalDereference(Instruction deref, Operand address) { exists(CallInstruction call | operandForFullyConvertedCall(getAUse(deref), call) and From 44b6366586d4ae2fb54f847c709a4ca46590a59c Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 09:44:30 +0200 Subject: [PATCH 108/219] delete old deprecations --- csharp/ql/lib/semmle/code/asp/WebConfig.qll | 21 ---- csharp/ql/lib/semmle/code/cil/Types.qll | 5 - csharp/ql/lib/semmle/code/csharp/Type.qll | 10 -- .../csharp/commons/StructuralComparison.qll | 42 -------- .../dataflow/internal/DataFlowPublic.qll | 10 -- .../security/dataflow/ExternalAPIsQuery.qll | 15 --- .../security/dataflow/LDAPInjectionQuery.qll | 3 - .../implementation/internal/TInstruction.qll | 6 -- .../ir/implementation/internal/TOperand.qll | 11 --- .../ir/implementation/raw/Instruction.qll | 6 -- .../raw/internal/IRConstruction.qll | 6 -- .../raw/internal/TranslatedCondition.qll | 3 - .../raw/internal/TranslatedDeclaration.qll | 3 - .../raw/internal/TranslatedElement.qll | 3 - .../raw/internal/TranslatedExpr.qll | 3 - .../raw/internal/TranslatedFunction.qll | 6 -- .../raw/internal/TranslatedInitialization.qll | 9 -- .../raw/internal/TranslatedStmt.qll | 3 - .../unaliased_ssa/Instruction.qll | 6 -- .../internal/SSAConstruction.qll | 12 --- .../unaliased_ssa/internal/SimpleSSA.qll | 6 -- java/ql/lib/semmle/code/java/Expr.qll | 3 - .../controlflow/internal/Preconditions.qll | 9 -- java/ql/lib/semmle/code/java/dataflow/SSA.qll | 3 - .../code/java/dataflow/internal/BaseSSA.qll | 3 - .../semmle/code/java/deadcode/EntryPoints.qll | 3 - .../code/java/frameworks/Networking.qll | 3 - .../semmle/code/java/frameworks/Servlets.qll | 6 -- .../semmle/code/java/frameworks/UnboundId.qll | 14 --- .../jackson/JacksonSerializability.qll | 3 - .../java/frameworks/javaee/PersistenceXML.qll | 3 - .../java/frameworks/javaee/ejb/EJBJarXML.qll | 3 - .../javaee/jsf/JSFFacesContextXML.qll | 6 -- .../java/frameworks/spring/SpringAutowire.qll | 3 - .../java/frameworks/spring/SpringCamel.qll | 24 ----- .../frameworks/spring/SpringComponentScan.qll | 3 - .../java/frameworks/spring/SpringFlex.qll | 5 - .../frameworks/spring/SpringXMLElement.qll | 3 - .../frameworks/struts/StrutsConventions.qll | 3 - .../code/java/frameworks/struts/StrutsXML.qll | 24 ----- .../semmle/code/java/security/Encryption.qll | 3 - .../code/java/security/ExternalAPIs.qll | 15 --- .../semmle/code/java/security/XmlParsers.qll | 87 ----------------- java/ql/lib/semmle/code/xml/WebXML.qll | 9 -- .../Security/CWE/CWE-089/MyBatisCommonLib.qll | 3 - .../semmle/code/xml/StrutsXML.qll | 6 -- .../src/semmle/code/xml/MyBatisMapperXML.qll | 6 -- .../adaptivethreatmodeling/ATMConfig.qll | 3 - .../FunctionBodyFeatures.qll | 6 -- .../ql/lib/Expressions/DOMProperties.qll | 6 -- javascript/ql/lib/semmle/javascript/AST.qll | 6 -- .../ql/lib/semmle/javascript/ApiGraphs.qll | 3 - .../ql/lib/semmle/javascript/DefUse.qll | 68 ------------- javascript/ql/lib/semmle/javascript/E4X.qll | 15 --- javascript/ql/lib/semmle/javascript/JSON.qll | 27 ------ javascript/ql/lib/semmle/javascript/JSX.qll | 27 ------ .../semmle/javascript/JsonStringifiers.qll | 3 - javascript/ql/lib/semmle/javascript/NPM.qll | 9 -- .../ql/lib/semmle/javascript/PrintAst.qll | 51 ---------- .../semmle/javascript/dataflow/DataFlow.qll | 2 - .../javascript/dataflow/TaintTracking.qll | 19 ---- .../javascript/dependencies/Dependencies.qll | 18 ---- .../dependencies/FrameworkLibraries.qll | 21 ---- .../javascript/frameworks/ClientRequests.qll | 6 -- .../semmle/javascript/frameworks/Files.qll | 6 -- .../semmle/javascript/frameworks/Markdown.qll | 3 - .../lib/semmle/javascript/frameworks/Next.qll | 3 - .../semmle/javascript/frameworks/NoSQL.qll | 3 - .../javascript/frameworks/UriLibraries.qll | 24 ----- .../javascript/frameworks/WebSocket.qll | 3 - .../javascript/internal/CachedStages.qll | 3 - .../dataflow/CodeInjectionCustomizations.qll | 6 -- .../javascript/security/dataflow/DOM.qll | 27 ------ .../security/dataflow/DomBasedXssQuery.qll | 6 -- .../ExternalAPIUsedWithUntrustedData.qll | 3 - ...APIUsedWithUntrustedDataCustomizations.qll | 9 -- .../ExternalAPIUsedWithUntrustedDataQuery.qll | 9 -- ...ImproperCodeSanitizationCustomizations.qll | 3 - .../InsecureDownloadCustomizations.qll | 9 -- .../UnsafeHtmlConstructionCustomizations.qll | 6 -- .../javascript/security/dataflow/Xss.qll | 3 - .../dataflow/XssThroughDomCustomizations.qll | 3 - .../ql/src/Declarations/Definitions.qll | 12 --- .../frameworks/ReactJS/ReactName.qll | 3 - .../Validating RAML-based APIs/Osprey.qll | 6 -- .../Validating RAML-based APIs/RAML.qll | 9 -- ruby/ql/lib/codeql/ruby/Concepts.qll | 8 -- ruby/ql/lib/codeql/ruby/ast/Expr.qll | 7 -- ruby/ql/lib/codeql/ruby/ast/Literal.qll | 12 --- ruby/ql/lib/codeql/ruby/ast/Pattern.qll | 16 --- .../lib/codeql/ruby/controlflow/CfgNodes.qll | 7 -- .../ruby/frameworks/StandardLibrary.qll | 97 ------------------- .../ruby/security/ReflectedXSSQuery.qll | 3 - .../codeql/ruby/security/StoredXSSQuery.qll | 3 - ruby/ql/lib/codeql/ruby/security/XSS.qll | 15 --- 95 files changed, 1059 deletions(-) delete mode 100644 ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll diff --git a/csharp/ql/lib/semmle/code/asp/WebConfig.qll b/csharp/ql/lib/semmle/code/asp/WebConfig.qll index 49e42fce5c1..fdc251b4242 100644 --- a/csharp/ql/lib/semmle/code/asp/WebConfig.qll +++ b/csharp/ql/lib/semmle/code/asp/WebConfig.qll @@ -18,9 +18,6 @@ class WebConfigReleaseTransformXml extends XmlFile { WebConfigReleaseTransformXml() { this.getName().matches("%Web.Release.config") } } -/** DEPRECATED: Alias for WebConfigXml */ -deprecated class WebConfigXML = WebConfigXml; - /** A `<configuration>` tag in an ASP.NET configuration file. */ class ConfigurationXmlElement extends XmlElement { ConfigurationXmlElement() { this.getName().toLowerCase() = "configuration" } @@ -31,9 +28,6 @@ class CompilationXmlElement extends XmlElement { CompilationXmlElement() { this.getName().toLowerCase() = "compilation" } } -/** DEPRECATED: Alias for ConfigurationXmlElement */ -deprecated class ConfigurationXMLElement = ConfigurationXmlElement; - /** A `<location>` tag in an ASP.NET configuration file. */ class LocationXmlElement extends XmlElement { LocationXmlElement() { @@ -42,9 +36,6 @@ class LocationXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for LocationXmlElement */ -deprecated class LocationXMLElement = LocationXmlElement; - /** A `<system.web>` tag in an ASP.NET configuration file. */ class SystemWebXmlElement extends XmlElement { SystemWebXmlElement() { @@ -57,9 +48,6 @@ class SystemWebXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for SystemWebXmlElement */ -deprecated class SystemWebXMLElement = SystemWebXmlElement; - /** A `<system.webServer>` tag in an ASP.NET configuration file. */ class SystemWebServerXmlElement extends XmlElement { SystemWebServerXmlElement() { @@ -72,9 +60,6 @@ class SystemWebServerXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for SystemWebServerXmlElement */ -deprecated class SystemWebServerXMLElement = SystemWebServerXmlElement; - /** A `<customErrors>` tag in an ASP.NET configuration file. */ class CustomErrorsXmlElement extends XmlElement { CustomErrorsXmlElement() { @@ -83,9 +68,6 @@ class CustomErrorsXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for CustomErrorsXmlElement */ -deprecated class CustomErrorsXMLElement = CustomErrorsXmlElement; - /** A `<httpRuntime>` tag in an ASP.NET configuration file. */ class HttpRuntimeXmlElement extends XmlElement { HttpRuntimeXmlElement() { @@ -94,9 +76,6 @@ class HttpRuntimeXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for HttpRuntimeXmlElement */ -deprecated class HttpRuntimeXMLElement = HttpRuntimeXmlElement; - /** A `<forms>` tag under `<system.web><authentication>` in an ASP.NET configuration file. */ class FormsElement extends XmlElement { FormsElement() { diff --git a/csharp/ql/lib/semmle/code/cil/Types.qll b/csharp/ql/lib/semmle/code/cil/Types.qll index 0e41fe748f4..2cfc09daf99 100644 --- a/csharp/ql/lib/semmle/code/cil/Types.qll +++ b/csharp/ql/lib/semmle/code/cil/Types.qll @@ -60,11 +60,6 @@ class Class extends ValueOrRefType { Class() { this.isClass() } } -/** A `record`. */ -deprecated class Record extends Class { - Record() { this.isRecord() } -} - /** An `interface`. */ class Interface extends ValueOrRefType { Interface() { this.isInterface() } diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index 8bb92c8c86a..85fde20e07d 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -780,16 +780,6 @@ class Class extends RefType, @class_type { override string getAPrimaryQlClass() { result = "Class" } } -/** - * DEPRECATED: Use `RecordClass` instead. - */ -deprecated class Record extends Class { - Record() { this.isRecord() } - - /** Gets the clone method of this record. */ - RecordCloneMethod getCloneMethod() { result = this.getAMember() } -} - /** * A `record`, for example * diff --git a/csharp/ql/lib/semmle/code/csharp/commons/StructuralComparison.qll b/csharp/ql/lib/semmle/code/csharp/commons/StructuralComparison.qll index 21102edb755..ca009448c10 100644 --- a/csharp/ql/lib/semmle/code/csharp/commons/StructuralComparison.qll +++ b/csharp/ql/lib/semmle/code/csharp/commons/StructuralComparison.qll @@ -200,45 +200,3 @@ predicate sameGvn(ControlFlowElement x, ControlFlowElement y) { pragma[only_bind_into](toGvn(pragma[only_bind_out](x))) = pragma[only_bind_into](toGvn(pragma[only_bind_out](y))) } - -/** - * DEPRECATED: Use `sameGvn` instead. - * - * A configuration for performing structural comparisons of program elements - * (expressions and statements). - * - * The predicate `candidate()` must be overridden, in order to identify the - * elements for which to perform structural comparison. - * - * Each use of the library is identified by a unique string value. - */ -abstract deprecated class StructuralComparisonConfiguration extends string { - bindingset[this] - StructuralComparisonConfiguration() { any() } - - /** - * Holds if elements `x` and `y` are candidates for testing structural - * equality. - * - * Subclasses are expected to override this predicate to identify the - * top-level elements which they want to compare. Care should be - * taken to avoid identifying too many pairs of elements, as in general - * there are very many structurally equal subtrees in a program, and - * in order to keep the computation feasible we must focus attention. - * - * Note that this relation is not expected to be symmetric -- it's - * fine to include a pair `(x, y)` but not `(y, x)`. - * In fact, not including the symmetrically implied fact will save - * half the computation time on the structural comparison. - */ - abstract predicate candidate(ControlFlowElement x, ControlFlowElement y); - - /** - * Holds if elements `x` and `y` structurally equal. `x` and `y` must be - * flagged as candidates for structural equality, that is, - * `candidate(x, y)` must hold. - */ - predicate same(ControlFlowElement x, ControlFlowElement y) { - this.candidate(x, y) and sameGvn(x, y) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index b22712087f2..b3599e3404e 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -106,16 +106,6 @@ class ParameterNode extends Node instanceof ParameterNodeImpl { result = c.asCallable().getParameter(ppos.getPosition()) ) } - - /** - * DEPRECATED - * - * Holds if this node is the parameter of callable `c` at the specified - * (zero-based) position. - */ - deprecated predicate isParameterOf(DataFlowCallable c, int i) { - super.isParameterOf(c, any(ParameterPosition pos | i = pos.getPosition())) - } } /** A definition, viewed as a node in a data flow graph. */ diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll index 235897f0742..975dae84fcb 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll @@ -14,9 +14,6 @@ private import semmle.code.csharp.dataflow.FlowSummary */ abstract class SafeExternalApiCallable extends Callable { } -/** DEPRECATED: Alias for SafeExternalApiCallable */ -deprecated class SafeExternalAPICallable = SafeExternalApiCallable; - private class SummarizedCallableSafe extends SafeExternalApiCallable instanceof SummarizedCallable { } @@ -87,9 +84,6 @@ class ExternalApiDataNode extends DataFlow::Node { } } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** * DEPRECATED: Use `RemoteSourceToExternalApi` instead. * @@ -113,9 +107,6 @@ private module RemoteSourceToExternalApiConfig implements DataFlow::ConfigSig { /** A module for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ module RemoteSourceToExternalApi = TaintTracking::Global<RemoteSourceToExternalApiConfig>; -/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ -deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; - /** A node representing untrusted data being passed to an external API. */ class UntrustedExternalApiDataNode extends ExternalApiDataNode { UntrustedExternalApiDataNode() { RemoteSourceToExternalApi::flow(_, this) } @@ -124,9 +115,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { DataFlow::Node getAnUntrustedSource() { RemoteSourceToExternalApi::flow(result, this) } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** An external API which is used with untrusted data. */ private newtype TExternalApi = /** An untrusted API method `m` where untrusted data is passed at `index`. */ @@ -161,6 +149,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { ) } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll index 9171bae41b4..3f9c5947b68 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll @@ -149,9 +149,6 @@ class LdapEncodeSanitizer extends Sanitizer { } } -/** DEPRECATED: Alias for LdapEncodeSanitizer */ -deprecated class LDAPEncodeSanitizer = LdapEncodeSanitizer; - private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { } private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index 169de03c2dc..bb3eb683653 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -73,9 +73,6 @@ module UnaliasedSsaInstructions { } } -/** DEPRECATED: Alias for UnaliasedSsaInstructions */ -deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions; - /** * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the * aliased SSA stage. @@ -107,6 +104,3 @@ module AliasedSsaInstructions { result = TAliasedSsaUnreachedInstruction(irFunc) } } - -/** DEPRECATED: Alias for AliasedSsaInstructions */ -deprecated module AliasedSSAInstructions = AliasedSsaInstructions; diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll index 6327c603901..cf8a6a9b7b1 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll @@ -59,20 +59,12 @@ private module Shared { class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand; - /** DEPRECATED: Alias for TNonSsaMemoryOperand */ - deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand; - /** * Returns the non-Phi memory operand with the specified parameters. */ TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { result = Internal::TNonSsaMemoryOperand(useInstr, tag) } - - /** DEPRECATED: Alias for nonSsaMemoryOperand */ - deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { - result = nonSsaMemoryOperand(useInstr, tag) - } } /** @@ -156,6 +148,3 @@ module UnaliasedSsaOperands { */ TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } } - -/** DEPRECATED: Alias for UnaliasedSsaOperands */ -deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands; diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 0aa7c552638..1b5ea432946 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction { */ final Language::AST getAst() { result = Construction::getInstructionAst(this) } - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Gets the location of the source code for this instruction. */ @@ -463,9 +460,6 @@ class VariableInstruction extends Instruction { * Gets the AST variable that this instruction's IR variable refers to, if one exists. */ final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } - - /** DEPRECATED: Alias for getAstVariable */ - deprecated Language::Variable getASTVariable() { result = this.getAstVariable() } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index c75c279226d..8297fedb28e 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -378,12 +378,6 @@ private module Cached { result = getInstructionTranslatedElement(instruction).getAst() } - /** DEPRECATED: Alias for getInstructionAst */ - cached - deprecated Language::AST getInstructionAST(Instruction instruction) { - result = getInstructionAst(instruction) - } - cached CSharpType getInstructionResultType(Instruction instruction) { getInstructionTranslatedElement(instruction) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll index 43db3c90065..afe98fdb410 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll @@ -17,9 +17,6 @@ abstract class TranslatedCondition extends ConditionBase { final override Language::AST getAst() { result = expr } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final Expr getExpr() { result = expr } final override Callable getFunction() { result = expr.getEnclosingCallable() } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll index 20d2b1e3459..23242c75c74 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -30,9 +30,6 @@ abstract class TranslatedLocalDeclaration extends TranslatedElement, TTranslated final override string toString() { result = expr.toString() } final override Language::AST getAst() { result = expr } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 4c5ab431dd5..c314d79e3ea 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -366,9 +366,6 @@ abstract class TranslatedElement extends TTranslatedElement { */ abstract Language::AST getAst(); - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Get the first instruction to be executed in the evaluation of this element. */ diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 67ebf19b766..68070261227 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -63,9 +63,6 @@ abstract class TranslatedExpr extends TranslatedExprBase { final override Language::AST getAst() { result = expr } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final override Callable getFunction() { result = expr.getEnclosingCallable() } /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll index 24f340a8718..f0970984d46 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll @@ -30,9 +30,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final override Language::AST getAst() { result = callable } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - /** * Gets the function being translated. */ @@ -287,9 +284,6 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter { final override Language::AST getAst() { result = param } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final override Callable getFunction() { result = param.getCallable() } final override Instruction getFirstInstruction() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll index bc127680ca4..c7cb9232d55 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -52,9 +52,6 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn final override Language::AST getAst() { result = expr } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - /** * Gets the expression that is doing the initialization. */ @@ -210,9 +207,6 @@ abstract class TranslatedElementInitialization extends TranslatedElement { final override Language::AST getAst() { result = initList } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final override Callable getFunction() { result = initList.getEnclosingCallable() } final override Instruction getFirstInstruction() { @@ -319,9 +313,6 @@ abstract class TranslatedConstructorCallFromConstructor extends TranslatedElemen final override Language::AST getAst() { result = call } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final override TranslatedElement getChild(int id) { id = 0 and result = this.getConstructorCall() } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll index 1afc48d0409..71d8c42e170 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll @@ -26,9 +26,6 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt { final override Language::AST getAst() { result = stmt } - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } - final override Callable getFunction() { result = stmt.getEnclosingCallable() } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 0aa7c552638..1b5ea432946 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction { */ final Language::AST getAst() { result = Construction::getInstructionAst(this) } - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Gets the location of the source code for this instruction. */ @@ -463,9 +460,6 @@ class VariableInstruction extends Instruction { * Gets the AST variable that this instruction's IR variable refers to, if one exists. */ final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } - - /** DEPRECATED: Alias for getAstVariable */ - deprecated Language::Variable getASTVariable() { result = this.getAstVariable() } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index dc785f3e0b1..63dc4142a13 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -422,12 +422,6 @@ private module Cached { ) } - /** DEPRECATED: Alias for getInstructionAst */ - cached - deprecated Language::AST getInstructionAST(Instruction instr) { - result = getInstructionAst(instr) - } - cached Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() @@ -993,9 +987,6 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { // We don't support reusing SSA for any location that could create a `Chi` instruction. } -/** DEPRECATED: Alias for canReuseSsaForMemoryResult */ -deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; - /** * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSsa` module, which is then imported by PrintSSA. @@ -1005,9 +996,6 @@ module DebugSsa { import DefUse } -/** DEPRECATED: Alias for DebugSsa */ -deprecated module DebugSSA = DebugSsa; - import CachedForDebugging cached diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index f5b0b3af930..5c33ecf5f99 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -46,9 +46,6 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) { not allocationEscapes(var) } -/** DEPRECATED: Alias for canReuseSsaForVariable */ -deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1; - private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) } private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var } @@ -80,9 +77,6 @@ class MemoryLocation extends TMemoryLocation { predicate canReuseSsaForOldResult(Instruction instr) { none() } -/** DEPRECATED: Alias for canReuseSsaForOldResult */ -deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1; - /** * Represents a set of `MemoryLocation`s that cannot overlap with * `MemoryLocation`s outside of the set. The `VirtualVariable` will be diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 0e0d0acea3f..92c81650bc3 100644 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -1809,9 +1809,6 @@ class LValue extends VarAccess { * are source expressions of the assignment. */ Expr getRhs() { exists(Assignment e | e.getDest() = this and e.getSource() = result) } - - /** DEPRECATED: Alias for getRhs */ - deprecated Expr getRHS() { result = this.getRhs() } } /** diff --git a/java/ql/lib/semmle/code/java/controlflow/internal/Preconditions.qll b/java/ql/lib/semmle/code/java/controlflow/internal/Preconditions.qll index 6b7736cb70d..3563176f4b0 100644 --- a/java/ql/lib/semmle/code/java/controlflow/internal/Preconditions.qll +++ b/java/ql/lib/semmle/code/java/controlflow/internal/Preconditions.qll @@ -6,15 +6,6 @@ import java -/** - * DEPRECATED: Use `conditionCheckMethodArgument` instead. - * Holds if `m` is a non-overridable method that checks that its first argument - * is equal to `checkTrue` and throws otherwise. - */ -deprecated predicate conditionCheckMethod(Method m, boolean checkTrue) { - conditionCheckMethodArgument(m, 0, checkTrue) -} - /** * Holds if `m` is a non-overridable method that checks that its zero-indexed `argument` * is equal to `checkTrue` and throws otherwise. diff --git a/java/ql/lib/semmle/code/java/dataflow/SSA.qll b/java/ql/lib/semmle/code/java/dataflow/SSA.qll index d4ff7ed0ac7..dd478b2a869 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SSA.qll @@ -931,9 +931,6 @@ class SsaVariable extends TSsaVariable { this = TSsaUntracked(_, result) } - /** DEPRECATED: Alias for getCfgNode */ - deprecated ControlFlowNode getCFGNode() { result = this.getCfgNode() } - /** Gets a textual representation of this SSA variable. */ string toString() { none() } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index 6f53dbd02c1..6e41c803553 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -483,9 +483,6 @@ class BaseSsaVariable extends TBaseSsaVariable { this = TSsaEntryDef(_, result) } - /** DEPRECATED: Alias for getCfgNode */ - deprecated ControlFlowNode getCFGNode() { result = this.getCfgNode() } - string toString() { none() } Location getLocation() { result = this.getCfgNode().getLocation() } diff --git a/java/ql/lib/semmle/code/java/deadcode/EntryPoints.qll b/java/ql/lib/semmle/code/java/deadcode/EntryPoints.qll index 2213960222e..5c037258309 100644 --- a/java/ql/lib/semmle/code/java/deadcode/EntryPoints.qll +++ b/java/ql/lib/semmle/code/java/deadcode/EntryPoints.qll @@ -456,9 +456,6 @@ class ArbitraryXmlEntryPoint extends ReflectivelyConstructedClass { } } -/** DEPRECATED: Alias for ArbitraryXmlEntryPoint */ -deprecated class ArbitraryXMLEntryPoint = ArbitraryXmlEntryPoint; - /** A Selenium PageObject, created by a call to PageFactory.initElements(..). */ class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass instanceof SeleniumPageObject { } diff --git a/java/ql/lib/semmle/code/java/frameworks/Networking.qll b/java/ql/lib/semmle/code/java/frameworks/Networking.qll index 8f86c8f75e7..c473cc9fc09 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Networking.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Networking.qll @@ -38,9 +38,6 @@ class UrlConnectionGetInputStreamMethod extends Method { } } -/** DEPRECATED: Alias for UrlConnectionGetInputStreamMethod */ -deprecated class URLConnectionGetInputStreamMethod = UrlConnectionGetInputStreamMethod; - /** The method `java.net.Socket::getInputStream`. */ class SocketGetInputStreamMethod extends Method { SocketGetInputStreamMethod() { diff --git a/java/ql/lib/semmle/code/java/frameworks/Servlets.qll b/java/ql/lib/semmle/code/java/frameworks/Servlets.qll index 82e837862be..f2de51b2aab 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Servlets.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Servlets.qll @@ -128,9 +128,6 @@ class HttpServletRequestGetRequestUrlMethod extends Method { } } -/** DEPRECATED: Alias for HttpServletRequestGetRequestUrlMethod */ -deprecated class HttpServletRequestGetRequestURLMethod = HttpServletRequestGetRequestUrlMethod; - /** * The method `getRequestURI()` declared in `javax.servlet.http.HttpServletRequest`. */ @@ -339,9 +336,6 @@ class ServletWebXmlListenerType extends RefType { } } -/** DEPRECATED: Alias for ServletWebXmlListenerType */ -deprecated class ServletWebXMLListenerType = ServletWebXmlListenerType; - /** Holds if `m` is a request handler method (for example `doGet` or `doPost`). */ predicate isServletRequestMethod(Method m) { m.getDeclaringType() instanceof ServletClass and diff --git a/java/ql/lib/semmle/code/java/frameworks/UnboundId.qll b/java/ql/lib/semmle/code/java/frameworks/UnboundId.qll index e19a6b43019..8bab6dfe581 100644 --- a/java/ql/lib/semmle/code/java/frameworks/UnboundId.qll +++ b/java/ql/lib/semmle/code/java/frameworks/UnboundId.qll @@ -29,9 +29,6 @@ class TypeUnboundIdLdapConnection extends Class { } } -/** DEPRECATED: Alias for TypeUnboundIdLdapConnection */ -deprecated class TypeUnboundIdLDAPConnection = TypeUnboundIdLdapConnection; - /*--- Methods ---*/ /** A method with the name `setBaseDN` declared in `com.unboundid.ldap.sdk.SearchRequest`. */ class MethodUnboundIdSearchRequestSetBaseDN extends Method { @@ -103,9 +100,6 @@ class MethodUnboundIdLdapConnectionSearch extends Method { } } -/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionSearch */ -deprecated class MethodUnboundIdLDAPConnectionSearch = MethodUnboundIdLdapConnectionSearch; - /** A method with the name `asyncSearch` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */ class MethodUnboundIdLdapConnectionAsyncSearch extends Method { MethodUnboundIdLdapConnectionAsyncSearch() { @@ -114,10 +108,6 @@ class MethodUnboundIdLdapConnectionAsyncSearch extends Method { } } -/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionAsyncSearch */ -deprecated class MethodUnboundIdLDAPConnectionAsyncSearch = - MethodUnboundIdLdapConnectionAsyncSearch; - /** A method with the name `searchForEntry` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */ class MethodUnboundIdLdapConnectionSearchForEntry extends Method { MethodUnboundIdLdapConnectionSearchForEntry() { @@ -125,7 +115,3 @@ class MethodUnboundIdLdapConnectionSearchForEntry extends Method { this.hasName("searchForEntry") } } - -/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionSearchForEntry */ -deprecated class MethodUnboundIdLDAPConnectionSearchForEntry = - MethodUnboundIdLdapConnectionSearchForEntry; diff --git a/java/ql/lib/semmle/code/java/frameworks/jackson/JacksonSerializability.qll b/java/ql/lib/semmle/code/java/frameworks/jackson/JacksonSerializability.qll index 79fd19f4ef2..f1395431a3c 100644 --- a/java/ql/lib/semmle/code/java/frameworks/jackson/JacksonSerializability.qll +++ b/java/ql/lib/semmle/code/java/frameworks/jackson/JacksonSerializability.qll @@ -20,9 +20,6 @@ class JacksonJsonIgnoreAnnotation extends NonReflectiveAnnotation { } } -/** DEPRECATED: Alias for JacksonJsonIgnoreAnnotation */ -deprecated class JacksonJSONIgnoreAnnotation = JacksonJsonIgnoreAnnotation; - /** A type whose values may be serialized using the Jackson JSON framework. */ abstract class JacksonSerializableType extends Type { } diff --git a/java/ql/lib/semmle/code/java/frameworks/javaee/PersistenceXML.qll b/java/ql/lib/semmle/code/java/frameworks/javaee/PersistenceXML.qll index faca537d171..7564dafa37e 100644 --- a/java/ql/lib/semmle/code/java/frameworks/javaee/PersistenceXML.qll +++ b/java/ql/lib/semmle/code/java/frameworks/javaee/PersistenceXML.qll @@ -26,9 +26,6 @@ class PersistenceXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for PersistenceXmlFile */ -deprecated class PersistenceXMLFile = PersistenceXmlFile; - /** The root `persistence` XML element in a `persistence.xml` file. */ class PersistenceXmlRoot extends XmlElement { PersistenceXmlRoot() { diff --git a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll index 9323b3852b4..f44d77d89bd 100644 --- a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll +++ b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll @@ -35,9 +35,6 @@ class EjbJarXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for EjbJarXmlFile */ -deprecated class EjbJarXMLFile = EjbJarXmlFile; - /** The root `ejb-jar` XML element in an `ejb-jar.xml` file. */ class EjbJarRootElement extends XmlElement { EjbJarRootElement() { diff --git a/java/ql/lib/semmle/code/java/frameworks/javaee/jsf/JSFFacesContextXML.qll b/java/ql/lib/semmle/code/java/frameworks/javaee/jsf/JSFFacesContextXML.qll index f85f36c37a3..13ed765638d 100644 --- a/java/ql/lib/semmle/code/java/frameworks/javaee/jsf/JSFFacesContextXML.qll +++ b/java/ql/lib/semmle/code/java/frameworks/javaee/jsf/JSFFacesContextXML.qll @@ -16,9 +16,6 @@ class FacesConfigXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for FacesConfigXmlFile */ -deprecated class FacesConfigXMLFile = FacesConfigXmlFile; - /** * An XML element in a `FacesConfigXMLFile`. */ @@ -31,9 +28,6 @@ class FacesConfigXmlElement extends XmlElement { string getValue() { result = this.allCharactersString().trim() } } -/** DEPRECATED: Alias for FacesConfigXmlElement */ -deprecated class FacesConfigXMLElement = FacesConfigXmlElement; - /** * An element in a JSF config file that declares a managed bean. */ diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll index 1dd6dfd292f..966db95afce 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll @@ -100,9 +100,6 @@ class SpringBeanXmlAutowiredSetterMethod extends Method { } } -/** DEPRECATED: Alias for SpringBeanXmlAutowiredSetterMethod */ -deprecated class SpringBeanXMLAutowiredSetterMethod = SpringBeanXmlAutowiredSetterMethod; - /** * A callable that is annotated with `@Autowired`. * diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringCamel.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringCamel.qll index 9bbdaad9687..985565255b6 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringCamel.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringCamel.qll @@ -13,9 +13,6 @@ class SpringCamelXmlElement extends SpringXmlElement { SpringCamelXmlElement() { this.getNamespace().getUri() = "http://camel.apache.org/schema/spring" } } -/** DEPRECATED: Alias for SpringCamelXmlElement */ -deprecated class SpringCamelXMLElement = SpringCamelXmlElement; - /** * An element in a Spring beans file that defines an Apache Camel context. * @@ -25,9 +22,6 @@ class SpringCamelXmlContext extends SpringCamelXmlElement { SpringCamelXmlContext() { this.getName() = "camelContext" } } -/** DEPRECATED: Alias for SpringCamelXmlContext */ -deprecated class SpringCamelXMLContext = SpringCamelXmlContext; - /** * An element in a Spring beans file that defines an Apache Camel route context. * @@ -38,9 +32,6 @@ class SpringCamelXmlRouteContext extends SpringCamelXmlElement { SpringCamelXmlRouteContext() { this.getName() = "routeContext" } } -/** DEPRECATED: Alias for SpringCamelXmlRouteContext */ -deprecated class SpringCamelXMLRouteContext = SpringCamelXmlRouteContext; - /** * An element in a Spring beans files that defines an Apache Camel route. * @@ -58,9 +49,6 @@ class SpringCamelXmlRoute extends SpringCamelXmlElement { } } -/** DEPRECATED: Alias for SpringCamelXmlRoute */ -deprecated class SpringCamelXMLRoute = SpringCamelXmlRoute; - /** * An element in a Spring bean file that is logically contained in an Apache Camel route. */ @@ -71,9 +59,6 @@ class SpringCamelXmlRouteElement extends SpringCamelXmlElement { } } -/** DEPRECATED: Alias for SpringCamelXmlRouteElement */ -deprecated class SpringCamelXMLRouteElement = SpringCamelXmlRouteElement; - /** * A reference to a Spring bean in an Apache Camel route defined in a Spring beans file. * @@ -98,9 +83,6 @@ class SpringCamelXmlBeanRef extends SpringCamelXmlRouteElement { RefType getBeanType() { result.getQualifiedName() = this.getAttribute("beanType").getValue() } } -/** DEPRECATED: Alias for SpringCamelXmlBeanRef */ -deprecated class SpringCamelXMLBeanRef = SpringCamelXmlBeanRef; - /** * A declaration of a target in an Apache Camel route defined in a Spring beans file. * @@ -120,9 +102,6 @@ class SpringCamelXmlToElement extends SpringCamelXmlRouteElement { deprecated string getURI() { result = this.getUri() } } -/** DEPRECATED: Alias for SpringCamelXmlToElement */ -deprecated class SpringCamelXMLToElement = SpringCamelXmlToElement; - /** * A declaration of a Apache Camel "method" expression defined in a Spring beans file. * @@ -147,6 +126,3 @@ class SpringCamelXmlMethodElement extends SpringCamelXmlElement { */ RefType getBeanType() { result.getQualifiedName() = this.getAttribute("beanType").getValue() } } - -/** DEPRECATED: Alias for SpringCamelXmlMethodElement */ -deprecated class SpringCamelXMLMethodElement = SpringCamelXmlMethodElement; diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll index f3380c45458..d285e9d0e6a 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll @@ -23,9 +23,6 @@ class SpringXmlComponentScan extends SpringXmlElement { string getAProfileExpr() { result = this.getSpringBeanFile().getAProfileExpr() } } -/** DEPRECATED: Alias for SpringXmlComponentScan */ -deprecated class SpringXMLComponentScan = SpringXmlComponentScan; - /** * An annotation of a class that configures which packages are considered to be "base" packages * when performing the Spring component scan. diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringFlex.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringFlex.qll index 0d18749a63e..af0afa91f4c 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringFlex.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringFlex.qll @@ -57,11 +57,6 @@ class SpringRemotingDestinationClass extends Class { */ SpringRemotingDestination getRemotingDestinationXml() { this = result.getSpringBean().getClass() } - /** DEPRECATED: Alias for getRemotingDestinationXml */ - deprecated SpringRemotingDestination getRemotingDestinationXML() { - result = this.getRemotingDestinationXml() - } - /** * Holds if the class is operating on an "include" or "exclude" basis. * diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringXMLElement.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringXMLElement.qll index efc7dfdaaf2..312cd659b39 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringXMLElement.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringXMLElement.qll @@ -37,6 +37,3 @@ class SpringXmlElement extends XmlElement { string getContentString() { result = this.allCharactersString() } } - -/** DEPRECATED: Alias for SpringXmlElement */ -deprecated class SpringXMLElement = SpringXmlElement; diff --git a/java/ql/lib/semmle/code/java/frameworks/struts/StrutsConventions.qll b/java/ql/lib/semmle/code/java/frameworks/struts/StrutsConventions.qll index fd9f14d4c6f..b3adfa8d80e 100644 --- a/java/ql/lib/semmle/code/java/frameworks/struts/StrutsConventions.qll +++ b/java/ql/lib/semmle/code/java/frameworks/struts/StrutsConventions.qll @@ -77,9 +77,6 @@ StrutsXmlFile getRootXmlFile(RefType refType) { ) } -/** DEPRECATED: Alias for getRootXmlFile */ -deprecated StrutsXMLFile getRootXMLFile(RefType refType) { result = getRootXmlFile(refType) } - /** * Gets the suffix used for automatically identifying actions when using the convention plugin. * diff --git a/java/ql/lib/semmle/code/java/frameworks/struts/StrutsXML.qll b/java/ql/lib/semmle/code/java/frameworks/struts/StrutsXML.qll index 3009056cce3..273034978d1 100644 --- a/java/ql/lib/semmle/code/java/frameworks/struts/StrutsXML.qll +++ b/java/ql/lib/semmle/code/java/frameworks/struts/StrutsXML.qll @@ -5,9 +5,6 @@ import java */ predicate isStrutsXmlIncluded() { exists(StrutsXmlFile strutsXml) } -/** DEPRECATED: Alias for isStrutsXmlIncluded */ -deprecated predicate isStrutsXMLIncluded = isStrutsXmlIncluded/0; - /** * A struts 2 configuration file. */ @@ -51,9 +48,6 @@ abstract class StrutsXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for StrutsXmlFile */ -deprecated class StrutsXMLFile = StrutsXmlFile; - /** * A Struts 2 "root" configuration XML file directly read by struts. * @@ -66,9 +60,6 @@ class StrutsRootXmlFile extends StrutsXmlFile { } } -/** DEPRECATED: Alias for StrutsRootXmlFile */ -deprecated class StrutsRootXMLFile = StrutsRootXmlFile; - /** * A Struts 2 configuration XML file included, directly or indirectly, by a root Struts configuration. */ @@ -76,9 +67,6 @@ class StrutsIncludedXmlFile extends StrutsXmlFile { StrutsIncludedXmlFile() { exists(StrutsXmlInclude include | this = include.getIncludedFile()) } } -/** DEPRECATED: Alias for StrutsIncludedXmlFile */ -deprecated class StrutsIncludedXMLFile = StrutsIncludedXmlFile; - /** * A Folder which has one or more Struts 2 root configurations. */ @@ -116,9 +104,6 @@ class StrutsXmlElement extends XmlElement { string getValue() { result = this.allCharactersString().trim() } } -/** DEPRECATED: Alias for StrutsXmlElement */ -deprecated class StrutsXMLElement = StrutsXmlElement; - /** * A `<include>` element within a `struts.xml` file. * @@ -141,9 +126,6 @@ class StrutsXmlInclude extends StrutsXmlElement { } } -/** DEPRECATED: Alias for StrutsXmlInclude */ -deprecated class StrutsXMLInclude = StrutsXmlInclude; - /** * Escape a string for use as the matcher in a string.match(..) call. */ @@ -192,9 +174,6 @@ class StrutsXmlAction extends StrutsXmlElement { } } -/** DEPRECATED: Alias for StrutsXmlAction */ -deprecated class StrutsXMLAction = StrutsXmlAction; - /** * A `<constant>` property, representing a configuration parameter to struts. */ @@ -205,6 +184,3 @@ class StrutsXmlConstant extends StrutsXmlElement { string getConstantValue() { result = this.getAttribute("value").getValue() } } - -/** DEPRECATED: Alias for StrutsXmlConstant */ -deprecated class StrutsXMLConstant = StrutsXmlConstant; diff --git a/java/ql/lib/semmle/code/java/security/Encryption.qll b/java/ql/lib/semmle/code/java/security/Encryption.qll index c0c35103331..88a1996ffd9 100644 --- a/java/ql/lib/semmle/code/java/security/Encryption.qll +++ b/java/ql/lib/semmle/code/java/security/Encryption.qll @@ -25,9 +25,6 @@ class HttpsUrlConnection extends RefType { HttpsUrlConnection() { this.hasQualifiedName("javax.net.ssl", "HttpsURLConnection") } } -/** DEPRECATED: Alias for HttpsUrlConnection */ -deprecated class HttpsURLConnection = HttpsUrlConnection; - class SslSocketFactory extends RefType { SslSocketFactory() { this.hasQualifiedName("javax.net.ssl", "SSLSocketFactory") } } diff --git a/java/ql/lib/semmle/code/java/security/ExternalAPIs.qll b/java/ql/lib/semmle/code/java/security/ExternalAPIs.qll index 89b24006475..beef024eb15 100644 --- a/java/ql/lib/semmle/code/java/security/ExternalAPIs.qll +++ b/java/ql/lib/semmle/code/java/security/ExternalAPIs.qll @@ -12,9 +12,6 @@ import semmle.code.java.dataflow.TaintTracking */ abstract class SafeExternalApiMethod extends Method { } -/** DEPRECATED: Alias for SafeExternalApiMethod */ -deprecated class SafeExternalAPIMethod = SafeExternalApiMethod; - /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApiMethod extends SafeExternalApiMethod { DefaultSafeExternalApiMethod() { @@ -95,9 +92,6 @@ class ExternalApiDataNode extends DataFlow::Node { string getMethodDescription() { result = this.getMethod().getQualifiedName() } } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** * DEPRECATED: Use `UntrustedDataToExternalApiFlow` instead. * @@ -125,9 +119,6 @@ module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { */ module UntrustedDataToExternalApiFlow = TaintTracking::Global<UntrustedDataToExternalApiConfig>; -/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ -deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; - /** A node representing untrusted data being passed to an external API. */ class UntrustedExternalApiDataNode extends ExternalApiDataNode { UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flowTo(this) } @@ -136,9 +127,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** An external API which is used with untrusted data. */ private newtype TExternalApi = /** An untrusted API method `m` where untrusted data is passed at `index`. */ @@ -172,6 +160,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { ) } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/java/ql/lib/semmle/code/java/security/XmlParsers.qll b/java/ql/lib/semmle/code/java/security/XmlParsers.qll index a079267b131..ded513ec656 100644 --- a/java/ql/lib/semmle/code/java/security/XmlParsers.qll +++ b/java/ql/lib/semmle/code/java/security/XmlParsers.qll @@ -337,9 +337,6 @@ class SaxBuilder extends RefType { } } -/** DEPRECATED: Alias for SaxBuilder */ -deprecated class SAXBuilder = SaxBuilder; - /** * A call to `SAXBuilder.build.` */ @@ -359,9 +356,6 @@ class SaxBuilderParse extends XmlParserCall { } } -/** DEPRECATED: Alias for SaxBuilderParse */ -deprecated class SAXBuilderParse = SaxBuilderParse; - private module SafeSaxBuilderToSaxBuilderParseFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxBuilder } @@ -386,9 +380,6 @@ class SaxBuilderConfig extends ParserConfig { } } -/** DEPRECATED: Alias for SaxBuilderConfig */ -deprecated class SAXBuilderConfig = SaxBuilderConfig; - /** A safely configured `SaxBuilder`. */ class SafeSaxBuilder extends VarAccess { SafeSaxBuilder() { @@ -404,9 +395,6 @@ class SafeSaxBuilder extends VarAccess { } } -/** DEPRECATED: Alias for SafeSaxBuilder */ -deprecated class SafeSAXBuilder = SafeSaxBuilder; - /* * The case in * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller @@ -420,17 +408,11 @@ class SaxParser extends RefType { SaxParser() { this.hasQualifiedName("javax.xml.parsers", "SAXParser") } } -/** DEPRECATED: Alias for SaxParser */ -deprecated class SAXParser = SaxParser; - /** The class `javax.xml.parsers.SAXParserFactory`. */ class SaxParserFactory extends RefType { SaxParserFactory() { this.hasQualifiedName("javax.xml.parsers", "SAXParserFactory") } } -/** DEPRECATED: Alias for SaxParserFactory */ -deprecated class SAXParserFactory = SaxParserFactory; - /** A call to `SAXParser.parse`. */ class SaxParserParse extends XmlParserCall { SaxParserParse() { @@ -446,9 +428,6 @@ class SaxParserParse extends XmlParserCall { override predicate isSafe() { SafeSaxParserFlow::flowToExpr(this.getQualifier()) } } -/** DEPRECATED: Alias for SaxParserParse */ -deprecated class SAXParserParse = SaxParserParse; - /** A `ParserConfig` that is specific to `SaxParserFactory`. */ class SaxParserFactoryConfig extends ParserConfig { SaxParserFactoryConfig() { @@ -460,9 +439,6 @@ class SaxParserFactoryConfig extends ParserConfig { } } -/** DEPRECATED: Alias for SaxParserFactoryConfig */ -deprecated class SAXParserFactoryConfig = SaxParserFactoryConfig; - /** * A safely configured `SAXParserFactory`. */ @@ -496,9 +472,6 @@ class SafeSaxParserFactory extends VarAccess { } } -/** DEPRECATED: Alias for SafeSaxParserFactory */ -deprecated class SafeSAXParserFactory = SafeSaxParserFactory; - private module SafeSaxParserFactoryToNewSaxParserFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParserFactory } @@ -540,9 +513,6 @@ class SafeSaxParser extends MethodAccess { } } -/** DEPRECATED: Alias for SafeSaxParser */ -deprecated class SafeSAXParser = SafeSaxParser; - /* SAXReader: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#saxreader */ /** * The class `org.dom4j.io.SAXReader`. @@ -551,9 +521,6 @@ class SaxReader extends RefType { SaxReader() { this.hasQualifiedName("org.dom4j.io", "SAXReader") } } -/** DEPRECATED: Alias for SaxReader */ -deprecated class SAXReader = SaxReader; - /** A call to `SAXReader.read`. */ class SaxReaderRead extends XmlParserCall { SaxReaderRead() { @@ -569,9 +536,6 @@ class SaxReaderRead extends XmlParserCall { override predicate isSafe() { SafeSaxReaderFlow::flowToExpr(this.getQualifier()) } } -/** DEPRECATED: Alias for SaxReaderRead */ -deprecated class SAXReaderRead = SaxReaderRead; - /** A `ParserConfig` specific to `SaxReader`. */ class SaxReaderConfig extends ParserConfig { SaxReaderConfig() { @@ -583,9 +547,6 @@ class SaxReaderConfig extends ParserConfig { } } -/** DEPRECATED: Alias for SaxReaderConfig */ -deprecated class SAXReaderConfig = SaxReaderConfig; - private module SafeSaxReaderFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxReader } @@ -626,9 +587,6 @@ class SafeSaxReader extends VarAccess { } } -/** DEPRECATED: Alias for SafeSaxReader */ -deprecated class SafeSAXReader = SafeSaxReader; - /* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#xmlreader */ /** The class `org.xml.sax.XMLReader`. */ class XmlReader extends RefType { @@ -640,9 +598,6 @@ class InputSource extends Class { InputSource() { this.hasQualifiedName("org.xml.sax", "InputSource") } } -/** DEPRECATED: Alias for XmlReader */ -deprecated class XMLReader = XmlReader; - /** A call to `XMLReader.read`. */ class XmlReaderParse extends XmlParserCall { XmlReaderParse() { @@ -661,9 +616,6 @@ class XmlReaderParse extends XmlParserCall { } } -/** DEPRECATED: Alias for XmlReaderParse */ -deprecated class XMLReaderParse = XmlReaderParse; - /** A `ParserConfig` specific to the `XmlReader`. */ class XmlReaderConfig extends ParserConfig { XmlReaderConfig() { @@ -675,9 +627,6 @@ class XmlReaderConfig extends ParserConfig { } } -/** DEPRECATED: Alias for XmlReaderConfig */ -deprecated class XMLReaderConfig = XmlReaderConfig; - private module ExplicitlySafeXmlReaderFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ExplicitlySafeXmlReader } @@ -697,9 +646,6 @@ class SafeXmlReaderFlowSink extends Expr { } } -/** DEPRECATED: Alias for SafeXmlReaderFlowSink */ -deprecated class SafeXMLReaderFlowSink = SafeXmlReaderFlowSink; - /** An `XmlReader` that is explicitly configured to be safe. */ class ExplicitlySafeXmlReader extends VarAccess { ExplicitlySafeXmlReader() { @@ -739,9 +685,6 @@ class ExplicitlySafeXmlReader extends VarAccess { } } -/** DEPRECATED: Alias for ExplicitlySafeXmlReader */ -deprecated class ExplicitlySafeXMLReader = ExplicitlySafeXmlReader; - private module CreatedSafeXmlReaderFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CreatedSafeXmlReader } @@ -778,9 +721,6 @@ class CreatedSafeXmlReader extends Call { } } -/** DEPRECATED: Alias for CreatedSafeXmlReader */ -deprecated class CreatedSafeXMLReader = CreatedSafeXmlReader; - /* * SAXSource in * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller @@ -791,9 +731,6 @@ class SaxSource extends RefType { SaxSource() { this.hasQualifiedName("javax.xml.transform.sax", "SAXSource") } } -/** DEPRECATED: Alias for SaxSource */ -deprecated class SAXSource = SaxSource; - /** A call to the constructor of `SAXSource` with `XmlReader` and `InputSource`. */ class ConstructedSaxSource extends ClassInstanceExpr { ConstructedSaxSource() { @@ -814,9 +751,6 @@ class ConstructedSaxSource extends ClassInstanceExpr { } } -/** DEPRECATED: Alias for ConstructedSaxSource */ -deprecated class ConstructedSAXSource = ConstructedSaxSource; - /** A call to the `SAXSource.setXMLReader` method. */ class SaxSourceSetReader extends MethodAccess { SaxSourceSetReader() { @@ -828,9 +762,6 @@ class SaxSourceSetReader extends MethodAccess { } } -/** DEPRECATED: Alias for SaxSourceSetReader */ -deprecated class SAXSourceSetReader = SaxSourceSetReader; - /** A `SaxSource` that is safe to use. */ class SafeSaxSource extends Expr { SafeSaxSource() { @@ -847,9 +778,6 @@ class SafeSaxSource extends Expr { } } -/** DEPRECATED: Alias for SafeSaxSource */ -deprecated class SafeSAXSource = SafeSaxSource; - /* Transformer: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#transformerfactory */ /** An access to a method use for configuring a transformer or schema. */ abstract class TransformerConfig extends MethodAccess { @@ -1063,9 +991,6 @@ class SaxTransformerFactoryNewXmlFilter extends XmlParserCall { override predicate isSafe() { SafeTransformerFactoryFlow::flowToExpr(this.getQualifier()) } } -/** DEPRECATED: Alias for SaxTransformerFactoryNewXmlFilter */ -deprecated class SAXTransformerFactoryNewXMLFilter = SaxTransformerFactoryNewXmlFilter; - /* Schema: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#schemafactory */ /** The class `javax.xml.validation.SchemaFactory`. */ class SchemaFactory extends RefType { @@ -1197,9 +1122,6 @@ class SimpleXmlPersisterCall extends XmlParserCall { override predicate isSafe() { none() } } -/** DEPRECATED: Alias for SimpleXmlPersisterCall */ -deprecated class SimpleXMLPersisterCall = SimpleXmlPersisterCall; - /** A call to `provide` in `Provider`. */ class SimpleXmlProviderCall extends XmlParserCall { SimpleXmlProviderCall() { @@ -1218,9 +1140,6 @@ class SimpleXmlProviderCall extends XmlParserCall { override predicate isSafe() { none() } } -/** DEPRECATED: Alias for SimpleXmlProviderCall */ -deprecated class SimpleXMLProviderCall = SimpleXmlProviderCall; - /** A call to `read` in `NodeBuilder`. */ class SimpleXmlNodeBuilderCall extends XmlParserCall { SimpleXmlNodeBuilderCall() { @@ -1236,9 +1155,6 @@ class SimpleXmlNodeBuilderCall extends XmlParserCall { override predicate isSafe() { none() } } -/** DEPRECATED: Alias for SimpleXmlNodeBuilderCall */ -deprecated class SimpleXMLNodeBuilderCall = SimpleXmlNodeBuilderCall; - /** A call to the `format` method of the `Formatter`. */ class SimpleXmlFormatterCall extends XmlParserCall { SimpleXmlFormatterCall() { @@ -1254,9 +1170,6 @@ class SimpleXmlFormatterCall extends XmlParserCall { override predicate isSafe() { none() } } -/** DEPRECATED: Alias for SimpleXmlFormatterCall */ -deprecated class SimpleXMLFormatterCall = SimpleXmlFormatterCall; - /** A configuration for secure processing. */ Expr configSecureProcessing() { result.(ConstantStringExpr).getStringValue() = diff --git a/java/ql/lib/semmle/code/xml/WebXML.qll b/java/ql/lib/semmle/code/xml/WebXML.qll index c15793b58a4..c356081c95f 100644 --- a/java/ql/lib/semmle/code/xml/WebXML.qll +++ b/java/ql/lib/semmle/code/xml/WebXML.qll @@ -5,9 +5,6 @@ import java */ predicate isWebXmlIncluded() { exists(WebXmlFile webXml) } -/** DEPRECATED: Alias for isWebXmlIncluded */ -deprecated predicate isWebXMLIncluded = isWebXmlIncluded/0; - /** * A deployment descriptor file, typically called `web.xml`. */ @@ -31,9 +28,6 @@ class WebXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for WebXmlFile */ -deprecated class WebXMLFile = WebXmlFile; - /** * An XML element in a `WebXMLFile`. */ @@ -46,9 +40,6 @@ class WebXmlElement extends XmlElement { string getValue() { result = this.allCharactersString().trim() } } -/** DEPRECATED: Alias for WebXmlElement */ -deprecated class WebXMLElement = WebXmlElement; - /** * A `<context-param>` element in a `web.xml` file. */ diff --git a/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisCommonLib.qll b/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisCommonLib.qll index 85d3f36dfdf..377c7f74bd4 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisCommonLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-089/MyBatisCommonLib.qll @@ -56,9 +56,6 @@ predicate myBatisMapperXmlElementFromMethod(Method method, MyBatisMapperXmlEleme ) } -/** DEPRECATED: Alias for myBatisMapperXmlElementFromMethod */ -deprecated predicate myBatisMapperXMLElementFromMethod = myBatisMapperXmlElementFromMethod/2; - /** Holds if the specified `method` has Ibatis Sql operation annotation `isoa`. */ predicate myBatisSqlOperationAnnotationFromMethod(Method method, IbatisSqlOperationAnnotation isoa) { exists(MyBatisSqlOperationAnnotationMethod msoam | diff --git a/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll index 874d8448640..8d829612d95 100644 --- a/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll +++ b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll @@ -10,9 +10,6 @@ class StrutsXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for StrutsXmlFile */ -deprecated class StrutsXMLFile = StrutsXmlFile; - /** * An XML element in a `StrutsXMLFile`. */ @@ -25,9 +22,6 @@ class StrutsXmlElement extends XmlElement { string getValue() { result = this.allCharactersString().trim() } } -/** DEPRECATED: Alias for StrutsXmlElement */ -deprecated class StrutsXMLElement = StrutsXmlElement; - /** * A `<constant>` element in a `StrutsXMLFile`. */ diff --git a/java/ql/src/semmle/code/xml/MyBatisMapperXML.qll b/java/ql/src/semmle/code/xml/MyBatisMapperXML.qll index c7de1b8b945..529a627e96f 100644 --- a/java/ql/src/semmle/code/xml/MyBatisMapperXML.qll +++ b/java/ql/src/semmle/code/xml/MyBatisMapperXML.qll @@ -14,9 +14,6 @@ class MyBatisMapperXmlFile extends XmlFile { } } -/** DEPRECATED: Alias for MyBatisMapperXmlFile */ -deprecated class MyBatisMapperXMLFile = MyBatisMapperXmlFile; - /** * An XML element in a `MyBatisMapperXMLFile`. */ @@ -36,9 +33,6 @@ class MyBatisMapperXmlElement extends XmlElement { } } -/** DEPRECATED: Alias for MyBatisMapperXmlElement */ -deprecated class MyBatisMapperXMLElement = MyBatisMapperXmlElement; - /** * An MyBatis Mapper sql operation element. */ diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll index 5532c8d4726..6836e14e72c 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll @@ -166,6 +166,3 @@ abstract class AtmConfig extends JS::TaintTracking::Configuration { ) } } - -/** DEPRECATED: Alias for AtmConfig */ -deprecated class ATMConfig = AtmConfig; diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FunctionBodyFeatures.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FunctionBodyFeatures.qll index 62531a9d423..0fc660796c4 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FunctionBodyFeatures.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FunctionBodyFeatures.qll @@ -41,9 +41,6 @@ AstNode getAnAstNodeToFeaturize(Function f) { not result = f.getIdentifier() } -/** DEPRECATED: Alias for getAnAstNodeToFeaturize */ -deprecated ASTNode getAnASTNodeToFeaturize(Function f) { result = getAnAstNodeToFeaturize(f) } - /** * Gets a function that contains the endpoint. * @@ -130,9 +127,6 @@ AstNode getAnAstNodeWithAFeature(Function f) { result = getAnAstNodeToFeaturize(f) } -/** DEPRECATED: Alias for getAnAstNodeWithAFeature */ -deprecated ASTNode getAnASTNodeWithAFeature(Function f) { result = getAnAstNodeWithAFeature(f) } - /** Returns the number of source-code characters in a function. */ int getNumCharsInFunction(Function f) { result = diff --git a/javascript/ql/lib/Expressions/DOMProperties.qll b/javascript/ql/lib/Expressions/DOMProperties.qll index 17f53f8a366..fdb7e6024c2 100644 --- a/javascript/ql/lib/Expressions/DOMProperties.qll +++ b/javascript/ql/lib/Expressions/DOMProperties.qll @@ -4,9 +4,6 @@ import semmle.javascript.Externs -/** DEPRECATED: Alias for isDomRootType */ -deprecated predicate isDOMRootType = isDomRootType/1; - /** Holds if `p` is declared as a property of a DOM class or interface. */ pragma[nomagic] predicate isDomProperty(string p) { @@ -14,6 +11,3 @@ predicate isDomProperty(string p) { isDomRootType(emd.getDeclaringType().getASupertype*()) ) } - -/** DEPRECATED: Alias for isDomProperty */ -deprecated predicate isDOMProperty = isDomProperty/1; diff --git a/javascript/ql/lib/semmle/javascript/AST.qll b/javascript/ql/lib/semmle/javascript/AST.qll index 895922f952f..e4a1cf944c4 100644 --- a/javascript/ql/lib/semmle/javascript/AST.qll +++ b/javascript/ql/lib/semmle/javascript/AST.qll @@ -184,9 +184,6 @@ class AstNode extends @ast_node, NodeInStmtContainer { } } -/** DEPRECATED: Alias for AstNode */ -deprecated class ASTNode = AstNode; - /** * Holds if the given file is a `.d.ts` file. */ @@ -339,9 +336,6 @@ class EventHandlerCode extends @event_handler, CodeInAttribute { } */ class JavaScriptUrl extends @javascript_url, CodeInAttribute { } -/** DEPRECATED: Alias for JavaScriptUrl */ -deprecated class JavaScriptURL = JavaScriptUrl; - /** * A toplevel syntactic entity containing Closure-style externs definitions. * diff --git a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll index c543607e73f..080a1bc1209 100644 --- a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll @@ -636,9 +636,6 @@ module API { /** Gets an API-node for this entry point. */ API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) } - - /** DEPRECATED. Use `getANode()` instead. */ - deprecated API::Node getNode() { result = this.getANode() } } /** diff --git a/javascript/ql/lib/semmle/javascript/DefUse.qll b/javascript/ql/lib/semmle/javascript/DefUse.qll index 8ad710fdc57..a9d021f939e 100644 --- a/javascript/ql/lib/semmle/javascript/DefUse.qll +++ b/javascript/ql/lib/semmle/javascript/DefUse.qll @@ -243,71 +243,3 @@ class VarUse extends ControlFlowNode, @varref instanceof RValue { */ SsaVariable getSsaVariable() { result.getAUse() = this } } - -/** - * Holds if the definition of `v` in `def` reaches `use` along some control flow path - * without crossing another definition of `v`. - * DEPRECATED: Use the `SSA.qll` library instead. - */ -deprecated predicate definitionReaches(Variable v, VarDef def, VarUse use) { - v = use.getVariable() and - exists(BasicBlock bb, int i, int next | next = nextDefAfter(bb, v, i, def) | - exists(int j | j in [i + 1 .. next - 1] | bb.useAt(j, v, use)) - or - exists(BasicBlock succ | succ = bb.getASuccessor() | - succ.isLiveAtEntry(v, use) and - next = bb.length() - ) - ) -} - -/** - * Holds if the definition of local variable `v` in `def` reaches `use` along some control flow path - * without crossing another definition of `v`. - * DEPRECATED: Use the `SSA.qll` library instead. - */ -deprecated predicate localDefinitionReaches(LocalVariable v, VarDef def, VarUse use) { - exists(SsaExplicitDefinition ssa | - ssa.defines(def, v) and - ssa = getAPseudoDefinitionInput*(use.getSsaVariable().getDefinition()) - ) -} - -/** - * Holds if `nd` is a pseudo-definition and the result is one of its inputs. - * DEPRECATED: Use the `SSA.qll` library instead. - */ -deprecated private SsaDefinition getAPseudoDefinitionInput(SsaDefinition nd) { - result = nd.(SsaPseudoDefinition).getAnInput() -} - -/** - * Holds if `d` is a definition of `v` at index `i` in `bb`, and the result is the next index - * in `bb` after `i` at which the same variable is defined, or `bb.length()` if there is none. - */ -deprecated private int nextDefAfter(BasicBlock bb, Variable v, int i, VarDef d) { - bb.defAt(i, v, d) and - result = - min(int jj | - (bb.defAt(jj, v, _) or jj = bb.length()) and - jj > i - ) -} - -/** - * Holds if the `later` definition of `v` could overwrite its `earlier` definition. - * - * This is the case if there is a path from `earlier` to `later` that does not cross - * another definition of `v`. - * DEPRECATED: Use the `SSA.qll` library instead. - */ -deprecated predicate localDefinitionOverwrites(LocalVariable v, VarDef earlier, VarDef later) { - exists(BasicBlock bb, int next | next = nextDefAfter(bb, v, _, earlier) | - bb.defAt(next, v, later) - or - exists(BasicBlock succ | succ = bb.getASuccessor() | - succ.localMayBeOverwritten(v, later) and - next = bb.length() - ) - ) -} diff --git a/javascript/ql/lib/semmle/javascript/E4X.qll b/javascript/ql/lib/semmle/javascript/E4X.qll index 47f1b8e4189..cd112d60664 100644 --- a/javascript/ql/lib/semmle/javascript/E4X.qll +++ b/javascript/ql/lib/semmle/javascript/E4X.qll @@ -16,9 +16,6 @@ module E4X { */ class XmlAnyName extends Expr, @e4x_xml_anyname { } - /** DEPRECATED: Alias for XmlAnyName */ - deprecated class XMLAnyName = XmlAnyName; - /** * An E4X qualified identifier. * @@ -57,9 +54,6 @@ module E4X { } } - /** DEPRECATED: Alias for XmlQualifiedIdentifier */ - deprecated class XMLQualifiedIdentifier = XmlQualifiedIdentifier; - /** * An E4X attribute selector. * @@ -89,9 +83,6 @@ module E4X { } } - /** DEPRECATED: Alias for XmlAttributeSelector */ - deprecated class XMLAttributeSelector = XmlAttributeSelector; - /** * An E4X filter expression. * @@ -117,9 +108,6 @@ module E4X { } } - /** DEPRECATED: Alias for XmlFilterExpression */ - deprecated class XMLFilterExpression = XmlFilterExpression; - /** * An E4X "dot-dot" expression. * @@ -144,7 +132,4 @@ module E4X { result = this.getBase().getFirstControlFlowNode() } } - - /** DEPRECATED: Alias for XmlDotDotExpression */ - deprecated class XMLDotDotExpression = XmlDotDotExpression; } diff --git a/javascript/ql/lib/semmle/javascript/JSON.qll b/javascript/ql/lib/semmle/javascript/JSON.qll index c0d78c078da..1e56fc00657 100644 --- a/javascript/ql/lib/semmle/javascript/JSON.qll +++ b/javascript/ql/lib/semmle/javascript/JSON.qll @@ -61,9 +61,6 @@ class JsonValue extends @json_value, Locatable { override string getAPrimaryQlClass() { result = "JsonValue" } } -/** DEPRECATED: Alias for JsonValue */ -deprecated class JSONValue = JsonValue; - /** * A JSON-encoded primitive value. * @@ -85,9 +82,6 @@ abstract class JsonPrimitiveValue extends JsonValue { string getRawValue() { json_literals(_, result, this) } } -/** DEPRECATED: Alias for JsonPrimitiveValue */ -deprecated class JSONPrimitiveValue = JsonPrimitiveValue; - /** * A JSON-encoded null value. * @@ -101,9 +95,6 @@ class JsonNull extends @json_null, JsonPrimitiveValue { override string getAPrimaryQlClass() { result = "JsonNull" } } -/** DEPRECATED: Alias for JsonNull */ -deprecated class JSONNull = JsonNull; - /** * A JSON-encoded Boolean value. * @@ -118,9 +109,6 @@ class JsonBoolean extends @json_boolean, JsonPrimitiveValue { override string getAPrimaryQlClass() { result = "JsonBoolean" } } -/** DEPRECATED: Alias for JsonBoolean */ -deprecated class JSONBoolean = JsonBoolean; - /** * A JSON-encoded number. * @@ -135,9 +123,6 @@ class JsonNumber extends @json_number, JsonPrimitiveValue { override string getAPrimaryQlClass() { result = "JsonNumber" } } -/** DEPRECATED: Alias for JsonNumber */ -deprecated class JSONNumber = JsonNumber; - /** * A JSON-encoded string value. * @@ -151,9 +136,6 @@ class JsonString extends @json_string, JsonPrimitiveValue { override string getAPrimaryQlClass() { result = "JsonString" } } -/** DEPRECATED: Alias for JsonString */ -deprecated class JSONString = JsonString; - /** * A JSON-encoded array. * @@ -170,9 +152,6 @@ class JsonArray extends @json_array, JsonValue { string getElementStringValue(int i) { result = this.getElementValue(i).getStringValue() } } -/** DEPRECATED: Alias for JsonArray */ -deprecated class JSONArray = JsonArray; - /** * A JSON-encoded object. * @@ -189,9 +168,6 @@ class JsonObject extends @json_object, JsonValue { string getPropStringValue(string name) { result = this.getPropValue(name).getStringValue() } } -/** DEPRECATED: Alias for JsonObject */ -deprecated class JSONObject = JsonObject; - /** * An error reported by the JSON parser. */ @@ -200,6 +176,3 @@ class JsonParseError extends @json_parse_error, Error { override string getMessage() { json_errors(this, result) } } - -/** DEPRECATED: Alias for JsonParseError */ -deprecated class JSONParseError = JsonParseError; diff --git a/javascript/ql/lib/semmle/javascript/JSX.qll b/javascript/ql/lib/semmle/javascript/JSX.qll index fa8f79fb2bb..6fd7c775d4e 100644 --- a/javascript/ql/lib/semmle/javascript/JSX.qll +++ b/javascript/ql/lib/semmle/javascript/JSX.qll @@ -30,9 +30,6 @@ class JsxNode extends Expr, @jsx_element { override string getAPrimaryQlClass() { result = "JsxNode" } } -/** DEPRECATED: Alias for JsxNode */ -deprecated class JSXNode = JsxNode; - /** * A JSX element. * @@ -81,9 +78,6 @@ class JsxElement extends JsxNode { deprecated predicate isHTMLElement() { this.isHtmlElement() } } -/** DEPRECATED: Alias for JsxElement */ -deprecated class JSXElement = JsxElement; - /** * A JSX fragment. * @@ -105,9 +99,6 @@ class JsxFragment extends JsxNode { override string getAPrimaryQlClass() { result = "JsxFragment" } } -/** DEPRECATED: Alias for JsxFragment */ -deprecated class JSXFragment = JsxFragment; - /** * An attribute of a JSX element, including spread attributes. * @@ -154,9 +145,6 @@ class JsxAttribute extends AstNode, @jsx_attribute { override string getAPrimaryQlClass() { result = "JsxAttribute" } } -/** DEPRECATED: Alias for JsxAttribute */ -deprecated class JSXAttribute = JsxAttribute; - /** * A spread attribute of a JSX element. * @@ -175,9 +163,6 @@ class JsxSpreadAttribute extends JsxAttribute { } } -/** DEPRECATED: Alias for JsxSpreadAttribute */ -deprecated class JSXSpreadAttribute = JsxSpreadAttribute; - /** * A namespace-qualified name such as `n:a`. * @@ -201,9 +186,6 @@ class JsxQualifiedName extends Expr, @jsx_qualified_name { override string getAPrimaryQlClass() { result = "JsxQualifiedName" } } -/** DEPRECATED: Alias for JsxQualifiedName */ -deprecated class JSXQualifiedName = JsxQualifiedName; - /** * A name of an JSX element or attribute (which is * always an identifier, a dot expression, or a qualified @@ -244,9 +226,6 @@ class JsxName extends Expr { } } -/** DEPRECATED: Alias for JsxName */ -deprecated class JSXName = JsxName; - /** * An interpolating expression that interpolates nothing. * @@ -260,9 +239,6 @@ class JsxEmptyExpr extends Expr, @jsx_empty_expr { override string getAPrimaryQlClass() { result = "JsxEmptyExpr" } } -/** DEPRECATED: Alias for JsxEmptyExpr */ -deprecated class JSXEmptyExpr = JsxEmptyExpr; - /** * A legacy `@jsx` pragma. * @@ -284,6 +260,3 @@ class JsxPragma extends JSDocTag { /** DEPRECATED: Alias for getDomName */ deprecated string getDOMName() { result = this.getDomName() } } - -/** DEPRECATED: Alias for JsxPragma */ -deprecated class JSXPragma = JsxPragma; diff --git a/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll b/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll index 0ca2ec2ac2e..d128dd9a653 100644 --- a/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll +++ b/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll @@ -77,6 +77,3 @@ class PrettyJsonTaintStep extends TaintTracking::SharedTaintStep { ) } } - -/** DEPRECATED: Alias for PrettyJsonTaintStep */ -deprecated class PrettyJSONTaintStep = PrettyJsonTaintStep; diff --git a/javascript/ql/lib/semmle/javascript/NPM.qll b/javascript/ql/lib/semmle/javascript/NPM.qll index e1059d94930..0bf92c5d29a 100644 --- a/javascript/ql/lib/semmle/javascript/NPM.qll +++ b/javascript/ql/lib/semmle/javascript/NPM.qll @@ -262,9 +262,6 @@ class PackageJson extends JsonObject { Module getTypingsModule() { result.getFile() = this.getTypingsFile() } } -/** DEPRECATED: Alias for PackageJson */ -deprecated class PackageJSON = PackageJson; - /** * A representation of bug tracker information for an NPM package. */ @@ -370,9 +367,6 @@ class NpmPackage extends @folder { /** Gets the `package.json` object of this package. */ PackageJson getPackageJson() { result = pkg } - /** DEPRECATED: Alias for getPackageJson */ - deprecated PackageJSON getPackageJSON() { result = this.getPackageJson() } - /** Gets the name of this package. */ string getPackageName() { result = this.getPackageJson().getPackageName() } @@ -411,9 +405,6 @@ class NpmPackage extends @folder { predicate declaresDependency(string p, string v) { pkg.declaresDependency(p, v) } } -/** DEPRECATED: Alias for NpmPackage */ -deprecated class NPMPackage = NpmPackage; - /** * Gets the parent folder of `c`, provided that they belong to the same NPM * package; that is, `c` must not be a `node_modules` folder. diff --git a/javascript/ql/lib/semmle/javascript/PrintAst.qll b/javascript/ql/lib/semmle/javascript/PrintAst.qll index 5c4960e041c..0defda1dc6b 100644 --- a/javascript/ql/lib/semmle/javascript/PrintAst.qll +++ b/javascript/ql/lib/semmle/javascript/PrintAst.qll @@ -391,9 +391,6 @@ private module PrintJavaScript { } } - /** DEPRECATED: Alias for JsxNodeNode */ - deprecated class JSXNodeNode = JsxNodeNode; - /** * An aggregate node representing all the attributes in a `JSXNode`. */ @@ -409,17 +406,11 @@ private module PrintJavaScript { */ JsxElement getJsxElement() { result = n } - /** DEPRECATED: Alias for getJsxElement */ - deprecated JSXElement getJSXElement() { result = this.getJsxElement() } - override PrintAstNode getChild(int childIndex) { result.(ElementNode).getElement() = n.getAttribute(childIndex) } } - /** DEPRECATED: Alias for JsxAttributesNode */ - deprecated class JSXAttributesNode = JsxAttributesNode; - /** * An aggregate node representing all the body elements in a `JSXNode`. */ @@ -435,17 +426,11 @@ private module PrintJavaScript { */ JsxNode getJsxNode() { result = n } - /** DEPRECATED: Alias for getJsxNode */ - deprecated JSXNode getJSXNode() { result = this.getJsxNode() } - override PrintAstNode getChild(int childIndex) { result.(ElementNode).getElement() = n.getBodyElement(childIndex) } } - /** DEPRECATED: Alias for JsxBodyElementsNode */ - deprecated class JSXBodyElementsNode = JsxBodyElementsNode; - /** * A node representing any `ASTNode` that has type-parameters. * @@ -582,9 +567,6 @@ private module PrintJson { } } - /** DEPRECATED: Alias for JsonNode */ - deprecated class JSONNode = JsonNode; - /** Provied predicates for pretty printing JSON. */ private module PrettyPrinting { /** @@ -655,9 +637,6 @@ module PrintYaml { } } - /** DEPRECATED: Alias for YamlNodeNode */ - deprecated class YAMLNodeNode = YamlNodeNode; - /** * A print node representing a `YAMLMapping`. * @@ -671,9 +650,6 @@ module PrintYaml { } } - /** DEPRECATED: Alias for YamlMappingNode */ - deprecated class YAMLMappingNode = YamlMappingNode; - /** * A print node representing the `i`th mapping in `mapping`. */ @@ -703,14 +679,8 @@ module PrintYaml { childIndex = 1 and result.(YamlNodeNode).getValue() = mapping.getValueNode(i) } } - - /** DEPRECATED: Alias for YamlMappingMapNode */ - deprecated class YAMLMappingMapNode = YamlMappingMapNode; } -/** DEPRECATED: Alias for PrintYaml */ -deprecated module PrintYAML = PrintYaml; - /** * Classes for printing HTML AST. */ @@ -741,9 +711,6 @@ module PrintHtml { } } - /** DEPRECATED: Alias for HtmlElementNode */ - deprecated class HTMLElementNode = HtmlElementNode; - /** * A print node representing an HTML node in a .html file. */ @@ -757,9 +724,6 @@ module PrintHtml { } } - /** DEPRECATED: Alias for HtmlScriptElementNode */ - deprecated class HTMLScriptElementNode = HtmlScriptElementNode; - /** * A print node representing the code inside a `<script>` element. */ @@ -785,9 +749,6 @@ module PrintHtml { } } - /** DEPRECATED: Alias for HtmlScript */ - deprecated class HTMLScript = HtmlScript; - /** * A print node representing the code inside an attribute. */ @@ -813,9 +774,6 @@ module PrintHtml { } } - /** DEPRECATED: Alias for HtmlCodeInAttr */ - deprecated class HTMLCodeInAttr = HtmlCodeInAttr; - /** * An aggregate node representing all the attributes of an HTMLElement. */ @@ -838,9 +796,6 @@ module PrintHtml { } } - /** DEPRECATED: Alias for HtmlAttributesNodes */ - deprecated class HTMLAttributesNodes = HtmlAttributesNodes; - /** * A print node representing an HTML attribute in a .html file. */ @@ -862,14 +817,8 @@ module PrintHtml { childIndex = 0 and result.(HtmlCodeInAttr).getCode() = attr.getCodeInAttribute() } } - - /** DEPRECATED: Alias for HtmlAttributeNode */ - deprecated class HTMLAttributeNode = HtmlAttributeNode; } -/** DEPRECATED: Alias for PrintHtml */ -deprecated module PrintHTML = PrintHtml; - /** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ query predicate nodes(PrintAstNode node, string key, string value) { value = node.getProperty(key) } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index c013dab3680..e8c2b563c92 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -1817,6 +1817,4 @@ module DataFlow { import Configuration import TypeTracking import internal.FunctionWrapperSteps - - deprecated predicate localTaintStep = TaintTracking::localTaintStep/2; } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index 2e80990ac13..96d97a270c6 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -419,16 +419,6 @@ module TaintTracking { import Cached::Public - /** - * Holds if `pred -> succ` is a taint propagating data flow edge through a string operation. - * DEPRECATED: Use `stringConcatenationStep` and `stringManipulationStep` instead. - */ - pragma[inline] - deprecated predicate stringStep(DataFlow::Node pred, DataFlow::Node succ) { - stringConcatenationStep(pred, succ) or - stringManipulationStep(pred, succ) - } - /** * Holds if `pred -> succ` is an edge used by all taint-tracking configurations. */ @@ -1241,13 +1231,4 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } - - /** - * Holds if taint propagates from `pred` to `succ` in one local (intra-procedural) step. - * DEPRECATED: Use `TaintTracking::sharedTaintStep` and `DataFlow::Node::getALocalSource()` instead. - */ - deprecated predicate localTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - DataFlow::localFlowStep(pred, succ) or - sharedTaintStep(pred, succ) - } } diff --git a/javascript/ql/lib/semmle/javascript/dependencies/Dependencies.qll b/javascript/ql/lib/semmle/javascript/dependencies/Dependencies.qll index 76a285ccd8c..948b8c9aff2 100644 --- a/javascript/ql/lib/semmle/javascript/dependencies/Dependencies.qll +++ b/javascript/ql/lib/semmle/javascript/dependencies/Dependencies.qll @@ -39,9 +39,6 @@ abstract class NpmDependency extends Dependency { /** Gets the name of the NPM package this module belongs to. */ abstract string getNpmPackageName(); - /** DEPRECATED: Alias for getNpmPackageName */ - deprecated string getNPMPackageName() { result = this.getNpmPackageName() } - /** Gets the version of the NPM package this module belongs to. */ abstract string getVersion(); @@ -62,9 +59,6 @@ abstract class NpmDependency extends Dependency { } } -/** DEPRECATED: Alias for NpmDependency */ -deprecated class NPMDependency = NpmDependency; - /** * Gets a variable into which something is imported by `i`. */ @@ -105,9 +99,6 @@ class BundledNpmDependency extends NpmDependency { override string getNpmPackageName() { result = this.getPackageJson().getPackageName() } - /** DEPRECATED: Alias for getNpmPackageName */ - deprecated override string getNPMPackageName() { result = this.getNpmPackageName() } - override string getVersion() { result = this.getPackageJson().getVersion() } override Import getAnImport() { @@ -117,9 +108,6 @@ class BundledNpmDependency extends NpmDependency { } } -/** DEPRECATED: Alias for BundledNpmDependency */ -deprecated class BundledNPMDependency = BundledNpmDependency; - /** * An NPM package referenced in a `package.json` file. */ @@ -139,9 +127,6 @@ class ExternalNpmDependency extends NpmDependency { exists(PackageDependencies pkgdeps | this = pkgdeps.getPropValue(result)) } - /** DEPRECATED: Alias for getNpmPackageName */ - deprecated override string getNPMPackageName() { result = this.getNpmPackageName() } - private string getVersionNumber() { exists(string versionRange | versionRange = this.(JsonString).getValue() | // extract a concrete version from the version range; currently, @@ -166,9 +151,6 @@ class ExternalNpmDependency extends NpmDependency { } } -/** DEPRECATED: Alias for ExternalNpmDependency */ -deprecated class ExternalNPMDependency = ExternalNpmDependency; - /** * Holds if import `i` may refer to the declared dependency `dep` of package `pkg`, * where the result value is the nesting depth of the file containing `i` within `pkg`. diff --git a/javascript/ql/lib/semmle/javascript/dependencies/FrameworkLibraries.qll b/javascript/ql/lib/semmle/javascript/dependencies/FrameworkLibraries.qll index 32a2941c1ab..9ff96a58fdc 100644 --- a/javascript/ql/lib/semmle/javascript/dependencies/FrameworkLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/dependencies/FrameworkLibraries.qll @@ -137,14 +137,8 @@ abstract class FrameworkLibraryWithUrlRegex extends FrameworkLibrary { * the version number. */ abstract string getAUrlRegex(); - - /** DEPRECATED: Alias for getAUrlRegex */ - deprecated string getAURLRegex() { result = this.getAUrlRegex() } } -/** DEPRECATED: Alias for FrameworkLibraryWithUrlRegex */ -deprecated class FrameworkLibraryWithURLRegex = FrameworkLibraryWithUrlRegex; - /** * A framework library that is referenced by URLs containing the name * of the framework (or an alias) and a version string. @@ -175,14 +169,8 @@ abstract class FrameworkLibraryWithGenericUrl extends FrameworkLibraryWithUrlReg "\\.js" ) } - - /** DEPRECATED: Alias for getAUrlRegex */ - deprecated override string getAURLRegex() { result = this.getAUrlRegex() } } -/** DEPRECATED: Alias for FrameworkLibraryWithGenericUrl */ -deprecated class FrameworkLibraryWithGenericURL = FrameworkLibraryWithGenericUrl; - /** * Gets a regular expression identifying suffixes that are commonly appended * to the name of a library to distinguish minor variants. @@ -282,9 +270,6 @@ class FrameworkLibraryReferenceWithUrl extends FrameworkLibraryReference { override predicate info(FrameworkLibrary fl, string v) { matchUrl(this, fl, v) } } -/** DEPRECATED: Alias for FrameworkLibraryReferenceWithUrl */ -deprecated class FrameworkLibraryReferenceWithURL = FrameworkLibraryReferenceWithUrl; - /** * Holds if the value of `src` attribute `attr` matches the URL pattern of library * `fl` at `version`. @@ -953,9 +938,6 @@ private class ApplicationInsights extends FrameworkLibraryWithUrlRegex { ApplicationInsights() { this = "ApplicationInsights" } override string getAUrlRegex() { result = ".*(?:^|/)ai\\.(" + semverRegex() + ")-build\\d+\\.js" } - - /** DEPRECATED: Alias for getAUrlRegex */ - deprecated override string getAURLRegex() { result = this.getAUrlRegex() } } /** @@ -974,9 +956,6 @@ private class TwitterTextClassic extends FrameworkLibraryWithUrlRegex { TwitterTextClassic() { this = "twitter-text" } override string getAUrlRegex() { result = ".*(?:^|/)twitter_text" + variantRegex() + "\\.js" } - - /** DEPRECATED: Alias for getAUrlRegex */ - deprecated override string getAURLRegex() { result = this.getAUrlRegex() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 73e3308329a..13879fda3e7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -631,9 +631,6 @@ module ClientRequest { } } - /** DEPRECATED: Alias for XmlHttpRequest */ - deprecated class XMLHttpRequest = XmlHttpRequest; - /** * A model of a URL request made using the `XhrIo` class from the closure library. */ @@ -814,9 +811,6 @@ module ClientRequest { override DataFlow::Node getADataNode() { none() } } - /** DEPRECATED: Alias for JSDomFromUrl */ - deprecated class JSDOMFromUrl = JSDomFromUrl; - /** * Classes and predicates modeling the `apollo-client` library. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Files.qll b/javascript/ql/lib/semmle/javascript/frameworks/Files.qll index 244c9c502c2..853d122b301 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Files.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Files.qll @@ -250,9 +250,6 @@ private module JsonFile { } } - /** DEPRECATED: Alias for JsonFileReader */ - deprecated class JSONFileReader = JsonFileReader; - /** * A writer for JSON files. */ @@ -267,9 +264,6 @@ private module JsonFile { override DataFlow::Node getADataNode() { result = this.getArgument(1) } } - - /** DEPRECATED: Alias for JsonFileWriter */ - deprecated class JSONFileWriter = JsonFileWriter; } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll index 5a60a8ac84d..fa8fd4da565 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll @@ -22,9 +22,6 @@ module Markdown { * Holds if the taint-step preserves HTML. */ predicate preservesHtml() { any() } - - /** DEPRECATED: Alias for preservesHtml */ - deprecated predicate preservesHTML() { this.preservesHtml() } } private class MarkdownStepAsTaintStep extends TaintTracking::SharedTaintStep { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll index 5ed808456d3..913753ff9da 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll @@ -241,9 +241,6 @@ module NextJS { } } - /** DEPRECATED: Alias for NextApiRouteHandler */ - deprecated class NextAPIRouteHandler = NextApiRouteHandler; - /** * Gets a reference to a [Next.js router](https://nextjs.org/docs/api-reference/next/router). */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll index 56e9c6f4406..2525f1d0c3d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll @@ -17,9 +17,6 @@ module NoSql { } } -/** DEPRECATED: Alias for NoSql */ -deprecated module NoSQL = NoSql; - /** * Provides classes modeling the `mongodb` and `mongoose` libraries. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll index f10bb58b8fc..0a262d154b2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll @@ -4,9 +4,6 @@ import javascript -/** DEPRECATED: Alias for `Urijs` */ -deprecated module urijs = Urijs; - /** * Provides classes for working with [urijs](http://medialize.github.io/URI.js/) code. */ @@ -73,9 +70,6 @@ module Urijs { } } -/** DEPRECATED: Alias for `Uridashjs` */ -deprecated module uridashjs = Uridashjs; - /** * Provides classes for working with [uri-js](https://github.com/garycourt/uri-js) code. */ @@ -101,9 +95,6 @@ module Uridashjs { } } -/** DEPRECATED: Alias for `Punycode` */ -deprecated module punycode = Punycode; - /** * Provides classes for working with [punycode](https://github.com/bestiejs/punycode.js) code. */ @@ -129,9 +120,6 @@ module Punycode { } } -/** DEPRECATED: Alias for `UrlParse` */ -deprecated module urlParse = UrlParse; - /** * Provides classes for working with [url-parse](https://github.com/unshiftio/url-parse) code. */ @@ -169,9 +157,6 @@ module UrlParse { } } -/** DEPRECATED: Alias for `Querystringify` */ -deprecated module querystringify = Querystringify; - /** * Provides classes for working with [querystringify](https://github.com/unshiftio/querystringify) code. */ @@ -202,9 +187,6 @@ module Querystringify { } } -/** DEPRECATED: Alias for `Querydashstring` */ -deprecated module querydashstring = Querydashstring; - /** * Provides classes for working with [query-string](https://github.com/sindresorhus/query-string) code. */ @@ -230,9 +212,6 @@ module Querydashstring { } } -/** DEPRECATED: Alias for `Url` */ -deprecated module url = Url; - /** * Provides classes for working with [url](https://nodejs.org/api/url.html) code. */ @@ -256,9 +235,6 @@ module Url { } } -/** DEPRECATED: Alias for `Querystring` */ -deprecated module querystring = Querystring; - /** * Provides classes for working with [querystring](https://nodejs.org/api/querystring.html) code. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/WebSocket.qll b/javascript/ql/lib/semmle/javascript/frameworks/WebSocket.qll index abdfe3bc445..d2fc69751d6 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/WebSocket.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/WebSocket.qll @@ -249,9 +249,6 @@ module ServerWebSocket { override Http::RouteHandler getRouteHandler() { result = handler } } - /** DEPRECATED: Alias for ServerHttpRequest */ - deprecated class ServerHTTPRequest = ServerHttpRequest; - /** * An access user-controlled HTTP request input in a request to a WebSocket server. */ diff --git a/javascript/ql/lib/semmle/javascript/internal/CachedStages.qll b/javascript/ql/lib/semmle/javascript/internal/CachedStages.qll index cc1404e34e7..59639f3d904 100644 --- a/javascript/ql/lib/semmle/javascript/internal/CachedStages.qll +++ b/javascript/ql/lib/semmle/javascript/internal/CachedStages.qll @@ -286,9 +286,6 @@ module Stages { } } - /** DEPRECATED: Alias for ApiStage */ - deprecated module APIStage = ApiStage; - /** * The `taint` stage. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index e68a0b604b0..5d658b23b59 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -255,9 +255,6 @@ module CodeInjection { NoSqlCodeInjectionSink() { any(NoSql::Query q).getACodeOperator() = this } } - /** DEPRECATED: Alias for NoSqlCodeInjectionSink */ - deprecated class NoSQLCodeInjectionSink = NoSqlCodeInjectionSink; - /** * The first argument to `Module.prototype._compile`, considered as a code-injection sink. */ @@ -427,9 +424,6 @@ module CodeInjection { */ class JsonStringifySanitizer extends Sanitizer, JsonStringifyCall { } - /** DEPRECATED: Alias for JsonStringifySanitizer */ - deprecated class JSONStringifySanitizer = JsonStringifySanitizer; - private class SinkFromModel extends Sink { SinkFromModel() { this = ModelOutput::getASinkNode("code-injection").asSink() } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 21fb6f785af..e007bdd8ede 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -18,9 +18,6 @@ class DomGlobalVariable extends GlobalVariable { } } -/** DEPRECATED: Alias for DomGlobalVariable */ -deprecated class DOMGlobalVariable = DomGlobalVariable; - /** * DEPRECATED: Use `isDomNode` instead. * Holds if `e` could hold a value that comes from the DOM. @@ -45,27 +42,6 @@ predicate isLocationNode(DataFlow::Node e) { e = DataFlow::globalVarRef("location") } -/** - * DEPRECATED: Use DOM::documentRef() instead. - * Gets a reference to the 'document' object. - */ -deprecated DataFlow::SourceNode document() { result = DOM::documentRef() } - -/** - * DEPRECATED: Use DOM::documentRef() instead. - * Holds if `e` could refer to the `document` object. - */ -deprecated predicate isDocument(Expr e) { DOM::documentRef().flowsToExpr(e) } - -/** - * DEPRECATED: Use DOM::locationSource() instead. - * Holds if `e` could refer to the document URL. - */ -deprecated predicate isDocumentUrl(Expr e) { e.flow() = DOM::locationSource() } - -/** DEPRECATED: Alias for isDocumentUrl */ -deprecated predicate isDocumentURL = isDocumentUrl/1; - /** * DEPRECATED. In most cases, a sanitizer based on this predicate can be removed, as * taint tracking no longer step through the properties of the location object by default. @@ -179,9 +155,6 @@ deprecated class DomPropWriteNode extends Assignment { */ predicate interpretsValueAsHtml() { node.interpretsValueAsHtml() } - /** DEPRECATED: Alias for interpretsValueAsHtml */ - deprecated predicate interpretsValueAsHTML() { this.interpretsValueAsHtml() } - /** * Holds if the assigned value is interpreted as JavaScript via javascript: protocol. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll index e26b4eea8c8..fa64b7300b0 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll @@ -8,12 +8,6 @@ private import semmle.javascript.security.TaintedUrlSuffix import DomBasedXssCustomizations::DomBasedXss private import Xss::Shared as Shared -/** DEPRECATED. Use `Configuration`. */ -deprecated class HtmlInjectionConfiguration = Configuration; - -/** DEPRECATED. Use `Configuration`. */ -deprecated class JQueryHtmlOrSelectorInjectionConfiguration = Configuration; - /** * A sink that is not a URL write or a JQuery selector, * assumed to be a value that is interpreted as HTML. diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll index 31963b6843e..c070fdff662 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll @@ -5,6 +5,3 @@ private import ExternalAPIUsedWithUntrustedDataQuery as ExternalApiUsedWithUntru /** DEPRECATED. Import `ExternalApiUsedWithUntrustedDataQuery` instead. */ deprecated module ExternalApiUsedWithUntrustedData = ExternalApiUsedWithUntrustedDataQuery; - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated module ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll index f17eab628ff..fac7b95fe80 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll @@ -64,9 +64,6 @@ module ExternalApiUsedWithUntrustedData { SafeExternalApiPackage() { exists(API::moduleImport(this)) } } - /** DEPRECATED: Alias for SafeExternalApiPackage */ - deprecated class SafeExternalAPIPackage = SafeExternalApiPackage; - private class DefaultSafeExternalApiPackage extends SafeExternalApiPackage { DefaultSafeExternalApiPackage() { // Promise libraries are safe and generate too much noise if included @@ -83,9 +80,6 @@ module ExternalApiUsedWithUntrustedData { */ abstract class SafeExternalApiFunction extends API::Node { } - /** DEPRECATED: Alias for SafeExternalApiFunction */ - deprecated class SafeExternalAPIFunction = SafeExternalApiFunction; - /** Holds if data read from a use of `f` may originate from an imported package. */ private predicate mayComeFromLibrary(API::Node f) { // base case: import @@ -371,6 +365,3 @@ module ExternalApiUsedWithUntrustedData { } } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated module ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataQuery.qll index 9335098af37..857cf837de2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataQuery.qll @@ -61,9 +61,6 @@ class Configuration extends TaintTracking::Configuration { /** A node representing data being passed to an external API. */ class ExternalApiDataNode extends DataFlow::Node instanceof Sink { } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** A node representing untrusted data being passed to an external API. */ class UntrustedExternalApiDataNode extends ExternalApiDataNode { UntrustedExternalApiDataNode() { any(Configuration c).hasFlow(_, this) } @@ -72,9 +69,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { DataFlow::Node getAnUntrustedSource() { any(Configuration c).hasFlow(result, this) } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** * Name of an external API sink, boxed in a newtype for consistency with other languages. */ @@ -102,6 +96,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { /** Gets a textual representation of this element. */ string toString() { this = MkExternalApiNode(result) } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll index 8968360d636..4bf212b90d2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll @@ -35,9 +35,6 @@ module ImproperCodeSanitization { */ class JsonStringifyAsSource extends Source instanceof JsonStringifyCall { } - /** DEPRECATED: Alias for JsonStringifyAsSource */ - deprecated class JSONStringifyAsSource = JsonStringifyAsSource; - /** * A leaf in a string-concatenation, where the string-concatenation constructs code that looks like a function. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 0a34642ffd8..dc383df448c 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -51,18 +51,12 @@ module InsecureDownload { SensitiveInsecureUrl() { this = "sensitiveInsecure" } } - /** DEPRECATED: Alias for SensitiveInsecureUrl */ - deprecated class SensitiveInsecureURL = SensitiveInsecureUrl; - /** * A flow-label for a URL that is downloaded over an insecure connection. */ class InsecureUrl extends DataFlow::FlowLabel { InsecureUrl() { this = "insecure" } } - - /** DEPRECATED: Alias for InsecureUrl */ - deprecated class InsecureURL = InsecureUrl; } /** @@ -127,9 +121,6 @@ module InsecureDownload { } } - /** DEPRECATED: Alias for ClientRequestUrl */ - deprecated class ClientRequestURL = ClientRequestUrl; - /** * Gets a node for the response from `request`, type-tracked using `t`. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll index 5c309b07727..90579211a3f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll @@ -145,9 +145,6 @@ module UnsafeHtmlConstruction { override string describe() { result = "HTML construction" } } - /** DEPRECATED: Alias for HtmlConcatenationSink */ - deprecated class HTMLConcatenationSink = HtmlConcatenationSink; - /** * A string parsed as XML, which is later used in an XSS sink. */ @@ -162,9 +159,6 @@ module UnsafeHtmlConstruction { override string describe() { result = "XML parsing" } } - /** DEPRECATED: Alias for XmlParsedSink */ - deprecated class XMLParsedSink = XmlParsedSink; - /** * A string rendered as markdown, where the rendering preserves HTML. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll index 216243fb8a5..8c881e49226 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll @@ -97,9 +97,6 @@ module Shared { } } - /** DEPRECATED: Alias for ContainsHtmlGuard */ - deprecated class ContainsHTMLGuard = ContainsHtmlGuard; - /** * Holds if `str` is used in a switch-case that has cases matching HTML escaping. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll index bd3aa65aa4d..a1074e49eb2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -137,9 +137,6 @@ module XssThroughDom { override string getPropertyName() { result = prop } } - /** DEPRECATED: Alias for DomTextSource */ - deprecated class DOMTextSource = DomTextSource; - /** The `files` property of an `<input />` element */ class FilesSource extends Source { FilesSource() { this = DOM::domValueRef().getAPropertyRead("files") } diff --git a/javascript/ql/src/Declarations/Definitions.qll b/javascript/ql/src/Declarations/Definitions.qll index a7034ad5093..7046b14f09d 100644 --- a/javascript/ql/src/Declarations/Definitions.qll +++ b/javascript/ql/src/Declarations/Definitions.qll @@ -1,13 +1 @@ import javascript - -/** - * DEPRECATED: Use `SsaDefinition` from `SSA.qll` instead. - * An identifier appearing in a defining position. - */ -deprecated class DefiningIdentifier extends Identifier { - DefiningIdentifier() { - this instanceof VarDecl or - exists(Assignment assgn | this = assgn.getLhs()) or - exists(UpdateExpr upd | this = upd.getOperand()) - } -} diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll b/javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll index 940332693a7..885f1f38a57 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll @@ -15,6 +15,3 @@ query predicate test_JSXname(JsxElement element, JsxName jsxname, string name, s } query ThisExpr test_JsxName_this(JsxElement element) { result.getParentExpr+() = element } - -/** DEPRECATED: Alias for test_JsxName_this */ -deprecated ThisExpr test_JSXName_this(JSXElement element) { result = test_JsxName_this(element) } diff --git a/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll b/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll index 385e3b8e7dd..02375976126 100644 --- a/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll +++ b/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll @@ -30,9 +30,6 @@ class OspreyCreateApiCall extends MethodCallExpr { } } -/** DEPRECATED: Alias for OspreyCreateApiCall */ -deprecated class OspreyCreateAPICall = OspreyCreateApiCall; - /** A variable in which an Osprey API object is stored. */ class OspreyApi extends Variable { OspreyApi() { this.getAnAssignedExpr() instanceof OspreyCreateApiCall } @@ -40,9 +37,6 @@ class OspreyApi extends Variable { File getSpecFile() { result = this.getAnAssignedExpr().(OspreyCreateApiCall).getSpecFile() } } -/** DEPRECATED: Alias for OspreyApi */ -deprecated class OspreyAPI = OspreyApi; - /** An Osprey REST method definition. */ class OspreyMethodDefinition extends MethodCallExpr { OspreyMethodDefinition() { diff --git a/javascript/ql/test/tutorials/Validating RAML-based APIs/RAML.qll b/javascript/ql/test/tutorials/Validating RAML-based APIs/RAML.qll index 5c22bf65ab9..50bd4a6ed03 100644 --- a/javascript/ql/test/tutorials/Validating RAML-based APIs/RAML.qll +++ b/javascript/ql/test/tutorials/Validating RAML-based APIs/RAML.qll @@ -8,9 +8,6 @@ class RamlSpec extends YamlDocument, YamlMapping { RamlSpec() { getLocation().getFile().getExtension() = "raml" } } -/** DEPRECATED: Alias for RamlSpec */ -deprecated class RAMLSpec = RamlSpec; - /** A RAML resource specification. */ class RamlResource extends YamlMapping { RamlResource() { @@ -38,9 +35,6 @@ class RamlResource extends YamlMapping { } } -/** DEPRECATED: Alias for RamlResource */ -deprecated class RAMLResource = RamlResource; - /** A RAML method specification. */ class RamlMethod extends YamlValue { RamlMethod() { @@ -57,6 +51,3 @@ class RamlMethod extends YamlValue { ) } } - -/** DEPRECATED: Alias for RamlMethod */ -deprecated class RAMLMethod = RamlMethod; diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index ec27694581f..28d5990e76a 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -715,14 +715,6 @@ module Http { /** Gets a node which returns the body of the response */ abstract DataFlow::Node getResponseBody(); - /** - * DEPRECATED: overwrite `getAUrlPart` instead. - * - * Gets a node that contributes to the URL of the request. - * Depending on the framework, a request may have multiple nodes which contribute to the URL. - */ - deprecated DataFlow::Node getURL() { none() } - /** * DEPRECATED: override `disablesCertificateValidation/2` instead. * diff --git a/ruby/ql/lib/codeql/ruby/ast/Expr.qll b/ruby/ql/lib/codeql/ruby/ast/Expr.qll index 99d955b3400..3e17c573b50 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Expr.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Expr.qll @@ -11,13 +11,6 @@ private import internal.TreeSitter * This is the root QL class for all expressions. */ class Expr extends Stmt, TExpr { - /** - * DEPRECATED: Use `getConstantValue` instead. - * - * Gets the textual (constant) value of this expression, if any. - */ - deprecated string getValueText() { result = this.getConstantValue().toString() } - /** Gets the constant value of this expression, if any. */ ConstantValue getConstantValue() { result = getConstantValueExpr(this) } } diff --git a/ruby/ql/lib/codeql/ruby/ast/Literal.qll b/ruby/ql/lib/codeql/ruby/ast/Literal.qll index f860cbe5c2b..059db251fc4 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Literal.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Literal.qll @@ -165,14 +165,6 @@ class FileLiteral extends Literal instanceof FileLiteralImpl { * `StringEscapeSequenceComponent`, or `StringInterpolationComponent`. */ class StringComponent extends AstNode instanceof StringComponentImpl { - /** - * DEPRECATED: Use `getConstantValue` instead. - * - * Gets the source text for this string component. Has no result if this is - * a `StringInterpolationComponent`. - */ - deprecated string getValueText() { result = this.getConstantValue().toString() } - /** Gets the constant value of this string component, if any. */ ConstantValue::ConstantStringValue getConstantValue() { result = TString(super.getValue()) } } @@ -218,8 +210,6 @@ class StringInterpolationComponent extends StringComponent, StmtSequence instanc final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - deprecated final override string getValueText() { none() } - final override ConstantValue::ConstantStringValue getConstantValue() { result = StmtSequence.super.getConstantValue() } @@ -267,8 +257,6 @@ class RegExpInterpolationComponent extends RegExpComponent, StmtSequence instanc final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - deprecated final override string getValueText() { none() } - final override ConstantValue::ConstantStringValue getConstantValue() { result = StmtSequence.super.getConstantValue() } diff --git a/ruby/ql/lib/codeql/ruby/ast/Pattern.qll b/ruby/ql/lib/codeql/ruby/ast/Pattern.qll index 439881535da..ef778664031 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Pattern.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Pattern.qll @@ -363,19 +363,3 @@ class ReferencePattern extends CasePattern, TReferencePattern { pred = "getExpr" and result = this.getExpr() } } - -/** - * DEPRECATED: Use `ReferencePattern` instead. - * - * A variable reference in a pattern, i.e. `^x` in the following example: - * ```rb - * x = 10 - * case expr - * in ^x then puts "ok" - * end - * ``` - */ -deprecated class VariableReferencePattern extends ReferencePattern, TVariableReferencePattern { - /** Gets the variable access corresponding to this variable reference pattern. */ - final VariableReadAccess getVariableAccess() { result = this.getExpr() } -} diff --git a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll index 96c015a6a4a..507b37b6a8f 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll @@ -113,13 +113,6 @@ class ExprCfgNode extends AstCfgNode { /** Gets the underlying expression. */ Expr getExpr() { result = e } - /** - * DEPRECATED: Use `getConstantValue` instead. - * - * Gets the textual (constant) value of this expression, if any. - */ - deprecated string getValueText() { result = this.getConstantValue().toString() } - /** Gets the constant value of this expression, if any. */ ConstantValue getConstantValue() { result = getConstantValue(this) } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll b/ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll deleted file mode 100644 index d97cdd89dd4..00000000000 --- a/ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll +++ /dev/null @@ -1,97 +0,0 @@ -/** - * This module is deprecated, and exists as a shim to support any existing code that relies on it. - * New code should use `codeql.ruby.frameworks.Core` and `codeql.ruby.frameworks.Stdlib` instead. - */ - -private import codeql.ruby.frameworks.Core as Core -private import codeql.ruby.frameworks.Stdlib as Stdlib - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class SubshellLiteralExecution = Core::SubshellLiteralExecution; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class SubshellHeredocExecution = Core::SubshellHeredocExecution; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class BasicObjectInstanceMethodCall = Core::BasicObjectInstanceMethodCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated predicate basicObjectInstanceMethodName = Core::basicObjectInstanceMethodName/0; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class InstanceEvalCallCodeExecution = Core::InstanceEvalCallCodeExecution; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class ObjectInstanceMethodCall = Core::ObjectInstanceMethodCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated predicate objectInstanceMethodName = Core::objectInstanceMethodName/0; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class KernelMethodCall = Core::KernelMethodCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class KernelSystemCall = Core::KernelSystemCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class KernelExecCall = Core::KernelExecCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class KernelSpawnCall = Core::KernelSpawnCall; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class EvalCallCodeExecution = Core::EvalCallCodeExecution; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated class SendCallCodeExecution = Core::SendCallCodeExecution; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated module Module = Core::Module; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Core` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated module Array = Core::Array; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Stdlib` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated module Regexp = Core::Regexp; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Stdlib` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated module Open3 = Stdlib::Open3; - -/** - * DEPRECATED: Import `codeql.ruby.frameworks.Stdlib` instead of `codeql.ruby.frameworks.StandardLibrary`. - */ -deprecated module Logger = Stdlib::Logger; diff --git a/ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll b/ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll index e94ddf45d3e..02b0c4b36f9 100644 --- a/ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll @@ -37,6 +37,3 @@ module ReflectedXss { } } } - -/** DEPRECATED: Alias for ReflectedXss */ -deprecated module ReflectedXSS = ReflectedXss; diff --git a/ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll b/ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll index f08529988c7..74b43195ce6 100644 --- a/ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll @@ -58,6 +58,3 @@ module StoredXss { import TaintTracking::Global<Config> } - -/** DEPRECATED: Alias for StoredXss */ -deprecated module StoredXSS = StoredXss; diff --git a/ruby/ql/lib/codeql/ruby/security/XSS.qll b/ruby/ql/lib/codeql/ruby/security/XSS.qll index d4b99766a58..8196f508b55 100644 --- a/ruby/ql/lib/codeql/ruby/security/XSS.qll +++ b/ruby/ql/lib/codeql/ruby/security/XSS.qll @@ -243,9 +243,6 @@ private module Shared { or isFlowFromHelperMethod(node1, node2) } - - /** DEPRECATED: Alias for isAdditionalXssFlowStep */ - deprecated predicate isAdditionalXSSFlowStep = isAdditionalXssFlowStep/2; } /** @@ -275,9 +272,6 @@ module ReflectedXss { */ predicate isAdditionalXssTaintStep = Shared::isAdditionalXssFlowStep/2; - /** DEPRECATED: Alias for isAdditionalXssTaintStep */ - deprecated predicate isAdditionalXSSTaintStep = isAdditionalXssTaintStep/2; - /** * A HTTP request input, considered as a flow source. */ @@ -286,9 +280,6 @@ module ReflectedXss { } } -/** DEPRECATED: Alias for ReflectedXss */ -deprecated module ReflectedXSS = ReflectedXss; - private module OrmTracking { /** * A data flow configuration to track flow from finder calls to field accesses. @@ -330,9 +321,6 @@ module StoredXss { */ predicate isAdditionalXssTaintStep = Shared::isAdditionalXssFlowStep/2; - /** DEPRECATED: Alias for isAdditionalXssTaintStep */ - deprecated predicate isAdditionalXSSTaintStep = isAdditionalXssTaintStep/2; - private class OrmFieldAsSource extends Source instanceof DataFlow::CallNode { OrmFieldAsSource() { exists(DataFlow::CallNode subSrc | @@ -346,6 +334,3 @@ module StoredXss { private class FileSystemReadAccessAsSource extends Source instanceof FileSystemReadAccess { } // TODO: Consider `FileNameSource` flowing to script tag `src` attributes and similar } - -/** DEPRECATED: Alias for StoredXss */ -deprecated module StoredXSS = StoredXss; From 9000243828a1018b7ee9f316c58c2334178a6048 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 09:45:30 +0200 Subject: [PATCH 109/219] JS: fix compilation --- .../ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll index 468d31c2c02..7231143ed55 100644 --- a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll @@ -198,7 +198,7 @@ class MainModulePath extends PathExpr, @json_string { } /** DEPRECATED: Alias for getPackageJson */ - deprecated PackageJSON getPackageJSON() { result = this.getPackageJson() } + deprecated PackageJson getPackageJSON() { result = this.getPackageJson() } override string getValue() { result = this.(JsonString).getValue() } @@ -259,7 +259,7 @@ private class FilesPath extends PathExpr, @json_string { PackageJson getPackageJson() { result = pkg } /** DEPRECATED: Alias for getPackageJson */ - deprecated PackageJSON getPackageJSON() { result = this.getPackageJson() } + deprecated PackageJson getPackageJSON() { result = this.getPackageJson() } override string getValue() { result = this.(JsonString).getValue() } From c3e57382f7fffaa200e7c6f4fd9a5f18ba3eb5cf Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 09:50:33 +0200 Subject: [PATCH 110/219] Ruby: fix compilation --- ruby/ql/lib/codeql/ruby/Concepts.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index 28d5990e76a..920c99c9034 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -687,9 +687,7 @@ module Http { * Gets a node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ - deprecated DataFlow::Node getURL() { - result = super.getURL() or result = Request::Range.super.getAUrlPart() - } + deprecated DataFlow::Node getURL() { result = Request::Range.super.getAUrlPart() } /** * Holds if this request is made using a mode that disables SSL/TLS From 3dfe2b30b161e22cf51cebdf30061bd7614fadcc Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 10:37:32 +0200 Subject: [PATCH 111/219] C#: delete override where the parent predicate no longer existed --- .../desugar/internal/TranslatedCompilerGeneratedElement.qll | 3 --- 1 file changed, 3 deletions(-) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll index 30440235443..2e5908b8194 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll @@ -20,7 +20,4 @@ abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, final override Callable getFunction() { result = generatedBy.getEnclosingCallable() } final override Language::AST getAst() { result = generatedBy } - - /** DEPRECATED: Alias for getAst */ - deprecated override Language::AST getAST() { result = this.getAst() } } From 3584e85fe8d707b9c679eaa49851854f459c7393 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Fri, 2 Jun 2023 07:47:15 +0200 Subject: [PATCH 112/219] JS: fix tutorial --- .../ql/test/tutorials/Validating RAML-based APIs/Osprey.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll b/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll index 02375976126..140bf59c4e6 100644 --- a/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll +++ b/javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll @@ -48,7 +48,7 @@ class OspreyMethodDefinition extends MethodCallExpr { OspreyApi getApi() { this.getReceiver() = result.getAnAccess() } /** DEPRECATED: Alias for getApi */ - deprecated OspreyAPI getAPI() { result = this.getApi() } + deprecated OspreyApi getAPI() { result = this.getApi() } /** Get the verb which this method implements. */ string getVerb() { result = this.getMethodName() } From 5cbe6db37dc00dce86ebd8badf342cbb04e51361 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Fri, 2 Jun 2023 07:51:14 +0200 Subject: [PATCH 113/219] C++: sync files from C# --- .../ir/implementation/aliased_ssa/Instruction.qll | 6 ------ .../aliased_ssa/internal/SSAConstruction.qll | 12 ------------ .../cpp/ir/implementation/internal/TInstruction.qll | 6 ------ .../code/cpp/ir/implementation/raw/Instruction.qll | 6 ------ .../ir/implementation/unaliased_ssa/Instruction.qll | 6 ------ .../unaliased_ssa/internal/SSAConstruction.qll | 12 ------------ .../unaliased_ssa/internal/SimpleSSA.qll | 6 ------ 7 files changed, 54 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 0aa7c552638..1b5ea432946 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction { */ final Language::AST getAst() { result = Construction::getInstructionAst(this) } - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Gets the location of the source code for this instruction. */ @@ -463,9 +460,6 @@ class VariableInstruction extends Instruction { * Gets the AST variable that this instruction's IR variable refers to, if one exists. */ final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } - - /** DEPRECATED: Alias for getAstVariable */ - deprecated Language::Variable getASTVariable() { result = this.getAstVariable() } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index dc785f3e0b1..63dc4142a13 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -422,12 +422,6 @@ private module Cached { ) } - /** DEPRECATED: Alias for getInstructionAst */ - cached - deprecated Language::AST getInstructionAST(Instruction instr) { - result = getInstructionAst(instr) - } - cached Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() @@ -993,9 +987,6 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { // We don't support reusing SSA for any location that could create a `Chi` instruction. } -/** DEPRECATED: Alias for canReuseSsaForMemoryResult */ -deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; - /** * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSsa` module, which is then imported by PrintSSA. @@ -1005,9 +996,6 @@ module DebugSsa { import DefUse } -/** DEPRECATED: Alias for DebugSsa */ -deprecated module DebugSSA = DebugSsa; - import CachedForDebugging cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index 169de03c2dc..bb3eb683653 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -73,9 +73,6 @@ module UnaliasedSsaInstructions { } } -/** DEPRECATED: Alias for UnaliasedSsaInstructions */ -deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions; - /** * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the * aliased SSA stage. @@ -107,6 +104,3 @@ module AliasedSsaInstructions { result = TAliasedSsaUnreachedInstruction(irFunc) } } - -/** DEPRECATED: Alias for AliasedSsaInstructions */ -deprecated module AliasedSSAInstructions = AliasedSsaInstructions; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 0aa7c552638..1b5ea432946 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction { */ final Language::AST getAst() { result = Construction::getInstructionAst(this) } - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Gets the location of the source code for this instruction. */ @@ -463,9 +460,6 @@ class VariableInstruction extends Instruction { * Gets the AST variable that this instruction's IR variable refers to, if one exists. */ final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } - - /** DEPRECATED: Alias for getAstVariable */ - deprecated Language::Variable getASTVariable() { result = this.getAstVariable() } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 0aa7c552638..1b5ea432946 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction { */ final Language::AST getAst() { result = Construction::getInstructionAst(this) } - /** DEPRECATED: Alias for getAst */ - deprecated Language::AST getAST() { result = this.getAst() } - /** * Gets the location of the source code for this instruction. */ @@ -463,9 +460,6 @@ class VariableInstruction extends Instruction { * Gets the AST variable that this instruction's IR variable refers to, if one exists. */ final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() } - - /** DEPRECATED: Alias for getAstVariable */ - deprecated Language::Variable getASTVariable() { result = this.getAstVariable() } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index dc785f3e0b1..63dc4142a13 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -422,12 +422,6 @@ private module Cached { ) } - /** DEPRECATED: Alias for getInstructionAst */ - cached - deprecated Language::AST getInstructionAST(Instruction instr) { - result = getInstructionAst(instr) - } - cached Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() @@ -993,9 +987,6 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) { // We don't support reusing SSA for any location that could create a `Chi` instruction. } -/** DEPRECATED: Alias for canReuseSsaForMemoryResult */ -deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1; - /** * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSsa` module, which is then imported by PrintSSA. @@ -1005,9 +996,6 @@ module DebugSsa { import DefUse } -/** DEPRECATED: Alias for DebugSsa */ -deprecated module DebugSSA = DebugSsa; - import CachedForDebugging cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index f5b0b3af930..5c33ecf5f99 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -46,9 +46,6 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) { not allocationEscapes(var) } -/** DEPRECATED: Alias for canReuseSsaForVariable */ -deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1; - private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) } private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var } @@ -80,9 +77,6 @@ class MemoryLocation extends TMemoryLocation { predicate canReuseSsaForOldResult(Instruction instr) { none() } -/** DEPRECATED: Alias for canReuseSsaForOldResult */ -deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1; - /** * Represents a set of `MemoryLocation`s that cannot overlap with * `MemoryLocation`s outside of the set. The `VirtualVariable` will be From f61b781386bf5a8c761ba4fd81e51a41305c61a9 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Fri, 2 Jun 2023 11:49:26 +0200 Subject: [PATCH 114/219] JS: delete effectively empty file --- javascript/ql/src/Declarations/ArgumentsRedefined.ql | 1 - javascript/ql/src/Declarations/Definitions.qll | 1 - 2 files changed, 2 deletions(-) delete mode 100644 javascript/ql/src/Declarations/Definitions.qll diff --git a/javascript/ql/src/Declarations/ArgumentsRedefined.ql b/javascript/ql/src/Declarations/ArgumentsRedefined.ql index fdd70ac1479..dc1ca153062 100644 --- a/javascript/ql/src/Declarations/ArgumentsRedefined.ql +++ b/javascript/ql/src/Declarations/ArgumentsRedefined.ql @@ -12,7 +12,6 @@ */ import javascript -import Definitions from VarRef d where diff --git a/javascript/ql/src/Declarations/Definitions.qll b/javascript/ql/src/Declarations/Definitions.qll deleted file mode 100644 index 7046b14f09d..00000000000 --- a/javascript/ql/src/Declarations/Definitions.qll +++ /dev/null @@ -1 +0,0 @@ -import javascript From ac9ede4ec0d18d30f953216212aaf54d7a3eda26 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Fri, 2 Jun 2023 11:54:04 +0200 Subject: [PATCH 115/219] add change-notes --- csharp/ql/lib/change-notes/2023-06-02-delete-deps.md | 8 ++++++++ java/ql/lib/change-notes/2023-06-02-delete-deps.md | 6 ++++++ .../ql/lib/change-notes/2023-06-02-delete-deps.md | 10 ++++++++++ ruby/ql/lib/change-notes/2023-06-02-delete-deps.md | 7 +++++++ 4 files changed, 31 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-06-02-delete-deps.md create mode 100644 java/ql/lib/change-notes/2023-06-02-delete-deps.md create mode 100644 javascript/ql/lib/change-notes/2023-06-02-delete-deps.md create mode 100644 ruby/ql/lib/change-notes/2023-06-02-delete-deps.md diff --git a/csharp/ql/lib/change-notes/2023-06-02-delete-deps.md b/csharp/ql/lib/change-notes/2023-06-02-delete-deps.md new file mode 100644 index 00000000000..13402f08147 --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-06-02-delete-deps.md @@ -0,0 +1,8 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `WebConfigXML`, `ConfigurationXMLElement`, `LocationXMLElement`, `SystemWebXMLElement`, `SystemWebServerXMLElement`, `CustomErrorsXMLElement`, and `HttpRuntimeXMLElement` classes from `WebConfig.qll`. The non-deprecated names with PascalCased Xml suffixes should be used instead. +* Deleted the deprecated `Record` class from both `Types.qll` and `Type.qll`. +* Deleted the deprecated `StructuralComparisonConfiguration` class from `StructuralComparison.qll`, use `sameGvn` instead. +* Deleted the deprecated `isParameterOf` predicate from the `ParameterNode` class. +* Deleted the deprecated `SafeExternalAPICallable`, `ExternalAPIDataNode`, `UntrustedDataToExternalAPIConfig`, `UntrustedExternalAPIDataNode`, and `ExternalAPIUsedWithUntrustedData` classes from `ExternalAPIsQuery.qll`. The non-deprecated names with PascalCased Api suffixes should be used instead. diff --git a/java/ql/lib/change-notes/2023-06-02-delete-deps.md b/java/ql/lib/change-notes/2023-06-02-delete-deps.md new file mode 100644 index 00000000000..01b2fd5a457 --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-02-delete-deps.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `getRHS` predicate from the `LValue` class, use `getRhs` instead. +* Deleted the deprecated `getCFGNode` predicate from the `SsaVariable` class, use `getCfgNode` instead. +* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/2023-06-02-delete-deps.md b/javascript/ql/lib/change-notes/2023-06-02-delete-deps.md new file mode 100644 index 00000000000..9edbce9771e --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-06-02-delete-deps.md @@ -0,0 +1,10 @@ +--- +category: minorAnalysis +--- +* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `localTaintStep` predicate from `DataFlow.qll`. +* Deleted the deprecated `stringStep`, and `localTaintStep` predicates from `TaintTracking.qll`. +* Deleted many modules that started with a lowercase letter. Use the versions that start with an uppercase letter instead. +* Deleted the deprecated `HtmlInjectionConfiguration` and `JQueryHtmlOrSelectorInjectionConfiguration` classes from `DomBasedXssQuery.qll`, use `Configuration` instead. +* Deleted the deprecated `DefiningIdentifier` class and the `Definitions.qll` file it was in. Use `SsaDefinition` instead. +* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`. \ No newline at end of file diff --git a/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md b/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md new file mode 100644 index 00000000000..f4df20530dc --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md @@ -0,0 +1,7 @@ +--- +category: minorAnalysis +--- +* Deleted many deprecated predicates and classes with uppercase `URL`, `XSS`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `getValueText` predicate from the `Expr`, `StringComponent`, and `ExprCfgNode` classes. Use `getConstantValue` instead. +* Deleted the deprecated `VariableReferencePattern` class, use `ReferencePattern` instead. +* Deleted all deprecated aliases in `StandardLibrary.qll`, use `codeql.ruby.frameworks.Core` and `codeql.ruby.frameworks.Stdlib` instead. \ No newline at end of file From 5bf82aeddfa36d7cfbb520e2c71f454439c7a229 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 2 Jun 2023 11:13:57 +0100 Subject: [PATCH 116/219] Swift: Add FieldDecl.hasQualifiedName. --- .../codeql/swift/elements/decl/VarDecl.qll | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll index ca650d12407..f7fd03bf906 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll @@ -9,8 +9,32 @@ class VarDecl extends Generated::VarDecl { } /** - * A field declaration. + * A field declaration. That is, a variable declaration that is a member of a + * class, struct, enum or protocol. */ class FieldDecl extends VarDecl { FieldDecl() { this = any(Decl ctx).getAMember() } + + /** + * Holds if this field is called `fieldName` and is a member of a + * class, struct, extension, enum or protocol called `typeName`. + */ + cached + predicate hasQualifiedName(string typeName, string fieldName) { + this.getName() = fieldName and + exists(Decl d | + d.asNominalTypeDecl().getFullName() = typeName and + d.getAMember() = this + ) + } + + /** + * Holds if this field is called `fieldName` and is a member of a + * class, struct, extension, enum or protocol called `typeName` in a module + * called `moduleName`. + */ + predicate hasQualifiedName(string moduleName, string typeName, string fieldName) { + this.hasQualifiedName(typeName, fieldName) and + this.getModule().getFullName() = moduleName + } } From ac4933a9cc714809d0877eb99d983d77881796e2 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Fri, 2 Jun 2023 12:32:38 +0200 Subject: [PATCH 117/219] C++: Ensure that the sink instruction occurs last in `cpp/invalid-pointer-deref` This avoids some counter-intuitive paths where we would seemingly jump back to an earlier instruction, which might actually have been in bounds. --- .../CWE/CWE-193/InvalidPointerDeref.ql | 19 +- .../InvalidPointerDeref.expected | 296 ------------------ .../CWE/CWE-193/pointer-deref/test.cpp | 4 +- 3 files changed, 20 insertions(+), 299 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 610eb572d8c..dbbe398ff7d 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -179,6 +179,22 @@ predicate isSinkImpl( pointerAddInstructionHasBounds(pai, sink1, sink2, delta) } +/** + * Yields any instruction that is control-flow reachable from `instr`. + */ +Instruction getASuccessor(Instruction instr) { + exists(IRBlock b, int instrIndex, int resultIndex | + result.getBlock() = b and + instr.getBlock() = b and + b.getInstruction(instrIndex) = instr and + b.getInstruction(resultIndex) = result + | + resultIndex >= instrIndex + ) + or + instr.getBlock().getASuccessor+() = result.getBlock() +} + /** * Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that * writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that @@ -189,7 +205,8 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o exists(AddressOperand addr | bounded1(addr.getDef(), sink.asInstruction(), delta) and delta >= 0 and - i.getAnOperand() = addr + i.getAnOperand() = addr and + i = getASuccessor(sink.asInstruction()) | i instanceof StoreInstruction and operation = "write" diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 09c75e7369c..418251cf6db 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -9,15 +9,7 @@ edges | test.cpp:5:15:5:15 | p | test.cpp:7:16:7:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:7:16:7:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:8:16:8:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:8:16:8:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:8:16:8:20 | ... + ... | -| test.cpp:5:15:5:15 | p | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:15 | p | test.cpp:12:16:12:16 | q | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... | @@ -38,22 +30,6 @@ edges | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | q | -| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | q | | test.cpp:6:15:6:15 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:7:16:7:16 | q | @@ -61,62 +37,11 @@ edges | test.cpp:6:15:6:15 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:8:16:8:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:8:16:8:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:9:16:9:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:9:16:9:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:10:16:10:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:10:16:10:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:11:16:11:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:11:16:11:16 | q | -| test.cpp:6:15:6:15 | q | test.cpp:12:16:12:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:7:16:7:16 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:16:8:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:8:16:8:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:9:16:9:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:9:16:9:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:7:16:7:16 | q | test.cpp:12:16:12:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:8:16:8:16 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:8:16:8:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:8:16:8:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:8:16:8:16 | q | test.cpp:9:16:9:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:9:16:9:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:8:16:8:16 | q | test.cpp:12:16:12:16 | q | | test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:9:16:9:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:9:16:9:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:9:16:9:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:9:16:9:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:9:16:9:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:9:16:9:16 | q | test.cpp:10:16:10:16 | q | -| test.cpp:9:16:9:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:9:16:9:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:9:16:9:16 | q | test.cpp:12:16:12:16 | q | -| test.cpp:10:16:10:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:10:16:10:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:10:16:10:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:10:16:10:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:10:16:10:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:10:16:10:16 | q | test.cpp:11:16:11:16 | q | -| test.cpp:10:16:10:16 | q | test.cpp:12:16:12:16 | q | -| test.cpp:11:16:11:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:11:16:11:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:11:16:11:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:11:16:11:16 | q | test.cpp:8:14:8:21 | Load: * ... | -| test.cpp:11:16:11:16 | q | test.cpp:12:16:12:16 | q | -| test.cpp:12:16:12:16 | q | test.cpp:6:14:6:15 | Load: * ... | -| test.cpp:12:16:12:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | p | | test.cpp:17:15:17:15 | p | test.cpp:17:15:17:22 | ... + ... | | test.cpp:17:15:17:15 | p | test.cpp:20:16:20:20 | ... + ... | @@ -132,15 +57,7 @@ edges | test.cpp:29:15:29:15 | p | test.cpp:31:16:31:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:31:16:31:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:32:16:32:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:32:16:32:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:32:16:32:20 | ... + ... | -| test.cpp:29:15:29:15 | p | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:15 | p | test.cpp:36:16:36:16 | q | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... | @@ -161,22 +78,6 @@ edges | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | q | -| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | q | | test.cpp:30:15:30:15 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:31:16:31:16 | q | @@ -184,62 +85,11 @@ edges | test.cpp:30:15:30:15 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:32:16:32:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:32:16:32:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:33:16:33:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:33:16:33:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:34:16:34:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:34:16:34:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:35:16:35:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:35:16:35:16 | q | -| test.cpp:30:15:30:15 | q | test.cpp:36:16:36:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:31:16:31:16 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:16:32:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:32:16:32:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:33:16:33:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:33:16:33:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:31:16:31:16 | q | test.cpp:36:16:36:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:32:16:32:16 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:32:16:32:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:32:16:32:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:32:16:32:16 | q | test.cpp:33:16:33:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:33:16:33:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:32:16:32:16 | q | test.cpp:36:16:36:16 | q | | test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:33:16:33:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:33:16:33:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:33:16:33:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:33:16:33:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:33:16:33:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:33:16:33:16 | q | test.cpp:34:16:34:16 | q | -| test.cpp:33:16:33:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:33:16:33:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:33:16:33:16 | q | test.cpp:36:16:36:16 | q | -| test.cpp:34:16:34:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:34:16:34:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:34:16:34:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:34:16:34:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:34:16:34:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:34:16:34:16 | q | test.cpp:35:16:35:16 | q | -| test.cpp:34:16:34:16 | q | test.cpp:36:16:36:16 | q | -| test.cpp:35:16:35:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:35:16:35:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:35:16:35:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:35:16:35:16 | q | test.cpp:32:14:32:21 | Load: * ... | -| test.cpp:35:16:35:16 | q | test.cpp:36:16:36:16 | q | -| test.cpp:36:16:36:16 | q | test.cpp:30:14:30:15 | Load: * ... | -| test.cpp:36:16:36:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | p | | test.cpp:41:15:41:15 | p | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:15 | p | test.cpp:41:15:41:28 | ... + ... | @@ -250,15 +100,7 @@ edges | test.cpp:41:15:41:15 | p | test.cpp:43:16:43:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:43:16:43:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:44:16:44:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:44:16:44:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:44:16:44:20 | ... + ... | -| test.cpp:41:15:41:15 | p | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:15 | p | test.cpp:48:16:48:16 | q | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... | @@ -279,22 +121,6 @@ edges | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | q | -| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | q | | test.cpp:42:15:42:15 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:43:16:43:16 | q | @@ -302,62 +128,11 @@ edges | test.cpp:42:15:42:15 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:44:16:44:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:44:16:44:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:45:16:45:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:45:16:45:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:46:16:46:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:46:16:46:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:47:16:47:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:47:16:47:16 | q | -| test.cpp:42:15:42:15 | q | test.cpp:48:16:48:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:43:16:43:16 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:16:44:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:44:16:44:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:45:16:45:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:45:16:45:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:43:16:43:16 | q | test.cpp:48:16:48:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:44:16:44:16 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:44:16:44:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:44:16:44:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:44:16:44:16 | q | test.cpp:45:16:45:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:45:16:45:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:44:16:44:16 | q | test.cpp:48:16:48:16 | q | | test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:45:16:45:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:45:16:45:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:45:16:45:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:45:16:45:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:45:16:45:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:45:16:45:16 | q | test.cpp:46:16:46:16 | q | -| test.cpp:45:16:45:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:45:16:45:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:45:16:45:16 | q | test.cpp:48:16:48:16 | q | -| test.cpp:46:16:46:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:46:16:46:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:46:16:46:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:46:16:46:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:46:16:46:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:46:16:46:16 | q | test.cpp:47:16:47:16 | q | -| test.cpp:46:16:46:16 | q | test.cpp:48:16:48:16 | q | -| test.cpp:47:16:47:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:47:16:47:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:47:16:47:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:47:16:47:16 | q | test.cpp:44:14:44:21 | Load: * ... | -| test.cpp:47:16:47:16 | q | test.cpp:48:16:48:16 | q | -| test.cpp:48:16:48:16 | q | test.cpp:42:14:42:15 | Load: * ... | -| test.cpp:48:16:48:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:51:7:51:14 | mk_array indirection | test.cpp:60:19:60:26 | call to mk_array | | test.cpp:51:33:51:35 | end | test.cpp:60:34:60:37 | mk_array output argument | | test.cpp:52:19:52:24 | call to malloc | test.cpp:51:7:51:14 | mk_array indirection | @@ -371,10 +146,8 @@ edges | test.cpp:60:19:60:26 | call to mk_array | test.cpp:70:38:70:38 | p | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | end | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | end | -| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | end | | test.cpp:62:32:62:34 | end | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:66:32:66:34 | end | test.cpp:67:9:67:14 | Store: ... = ... | -| test.cpp:70:31:70:33 | end | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:80:9:80:16 | mk_array indirection [begin] | test.cpp:89:19:89:26 | call to mk_array [begin] | | test.cpp:80:9:80:16 | mk_array indirection [begin] | test.cpp:119:18:119:25 | call to mk_array [begin] | | test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:89:19:89:26 | call to mk_array [end] | @@ -395,7 +168,6 @@ edges | test.cpp:89:19:89:26 | call to mk_array [begin] | test.cpp:99:20:99:22 | arr indirection [begin] | | test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:91:36:91:38 | arr indirection [end] | | test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:95:36:95:38 | arr indirection [end] | -| test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:99:35:99:37 | arr indirection [end] | | test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin | | test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin indirection | | test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | p | @@ -416,16 +188,11 @@ edges | test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin indirection | | test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | p | | test.cpp:99:24:99:28 | begin indirection | test.cpp:99:46:99:46 | p | -| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end | -| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end indirection | -| test.cpp:99:39:99:41 | end | test.cpp:96:9:96:14 | Store: ... = ... | -| test.cpp:99:39:99:41 | end indirection | test.cpp:99:39:99:41 | end | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:113:20:113:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [end] | test.cpp:105:36:105:38 | arr indirection [end] | | test.cpp:104:27:104:29 | arr [end] | test.cpp:109:36:109:38 | arr indirection [end] | -| test.cpp:104:27:104:29 | arr [end] | test.cpp:113:35:113:37 | arr indirection [end] | | test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin | | test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin indirection | | test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | p | @@ -446,10 +213,6 @@ edges | test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin indirection | | test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | p | | test.cpp:113:24:113:28 | begin indirection | test.cpp:113:46:113:46 | p | -| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end | -| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end indirection | -| test.cpp:113:39:113:41 | end | test.cpp:110:9:110:14 | Store: ... = ... | -| test.cpp:113:39:113:41 | end indirection | test.cpp:113:39:113:41 | end | | test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] | | test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] | | test.cpp:124:15:124:20 | call to malloc | test.cpp:125:5:125:17 | ... = ... | @@ -504,7 +267,6 @@ edges | test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:174:20:174:22 | arr indirection [begin] | | test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:166:37:166:39 | arr indirection [end] | | test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:170:37:170:39 | arr indirection [end] | -| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:174:36:174:38 | arr indirection [end] | | test.cpp:166:20:166:22 | arr indirection [begin] | test.cpp:166:25:166:29 | begin | | test.cpp:166:20:166:22 | arr indirection [begin] | test.cpp:166:25:166:29 | begin indirection | | test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | p | @@ -525,10 +287,6 @@ edges | test.cpp:174:20:174:22 | arr indirection [begin] | test.cpp:174:25:174:29 | begin indirection | | test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | p | | test.cpp:174:25:174:29 | begin indirection | test.cpp:174:48:174:48 | p | -| test.cpp:174:36:174:38 | arr indirection [end] | test.cpp:174:41:174:43 | end | -| test.cpp:174:36:174:38 | arr indirection [end] | test.cpp:174:41:174:43 | end indirection | -| test.cpp:174:41:174:43 | end | test.cpp:171:9:171:14 | Store: ... = ... | -| test.cpp:174:41:174:43 | end indirection | test.cpp:174:41:174:43 | end | | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] | | test.cpp:188:15:188:20 | call to malloc | test.cpp:189:15:189:15 | p | @@ -655,16 +413,6 @@ edges | test.cpp:308:5:308:11 | access to array | test.cpp:308:5:308:29 | Store: ... = ... | | test.cpp:313:14:313:27 | new[] | test.cpp:314:15:314:16 | xs | | test.cpp:325:14:325:27 | new[] | test.cpp:326:15:326:16 | xs | -| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... | -| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... | -| test.cpp:326:15:326:16 | xs | test.cpp:338:8:338:15 | * ... | -| test.cpp:326:15:326:16 | xs | test.cpp:341:8:341:17 | * ... | -| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... | -| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... | -| test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... | -| test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... | -| test.cpp:342:8:342:17 | * ... | test.cpp:333:5:333:21 | Store: ... = ... | -| test.cpp:342:8:342:17 | * ... | test.cpp:341:5:341:21 | Store: ... = ... | | test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs | | test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | | test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | @@ -720,7 +468,6 @@ edges | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:16:359:27 | end_plus_one | -| test.cpp:359:16:359:27 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... | | test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p | @@ -746,15 +493,7 @@ nodes | test.cpp:7:16:7:16 | q | semmle.label | q | | test.cpp:8:14:8:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:8:16:8:16 | q | semmle.label | q | -| test.cpp:8:16:8:16 | q | semmle.label | q | | test.cpp:8:16:8:20 | ... + ... | semmle.label | ... + ... | -| test.cpp:9:16:9:16 | q | semmle.label | q | -| test.cpp:9:16:9:16 | q | semmle.label | q | -| test.cpp:10:16:10:16 | q | semmle.label | q | -| test.cpp:10:16:10:16 | q | semmle.label | q | -| test.cpp:11:16:11:16 | q | semmle.label | q | -| test.cpp:11:16:11:16 | q | semmle.label | q | -| test.cpp:12:16:12:16 | q | semmle.label | q | | test.cpp:16:15:16:20 | call to malloc | semmle.label | call to malloc | | test.cpp:17:15:17:15 | p | semmle.label | p | | test.cpp:17:15:17:22 | ... + ... | semmle.label | ... + ... | @@ -773,15 +512,7 @@ nodes | test.cpp:31:16:31:16 | q | semmle.label | q | | test.cpp:32:14:32:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:32:16:32:16 | q | semmle.label | q | -| test.cpp:32:16:32:16 | q | semmle.label | q | | test.cpp:32:16:32:20 | ... + ... | semmle.label | ... + ... | -| test.cpp:33:16:33:16 | q | semmle.label | q | -| test.cpp:33:16:33:16 | q | semmle.label | q | -| test.cpp:34:16:34:16 | q | semmle.label | q | -| test.cpp:34:16:34:16 | q | semmle.label | q | -| test.cpp:35:16:35:16 | q | semmle.label | q | -| test.cpp:35:16:35:16 | q | semmle.label | q | -| test.cpp:36:16:36:16 | q | semmle.label | q | | test.cpp:40:15:40:20 | call to malloc | semmle.label | call to malloc | | test.cpp:41:15:41:15 | p | semmle.label | p | | test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... | @@ -795,15 +526,7 @@ nodes | test.cpp:43:16:43:16 | q | semmle.label | q | | test.cpp:44:14:44:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:44:16:44:16 | q | semmle.label | q | -| test.cpp:44:16:44:16 | q | semmle.label | q | | test.cpp:44:16:44:20 | ... + ... | semmle.label | ... + ... | -| test.cpp:45:16:45:16 | q | semmle.label | q | -| test.cpp:45:16:45:16 | q | semmle.label | q | -| test.cpp:46:16:46:16 | q | semmle.label | q | -| test.cpp:46:16:46:16 | q | semmle.label | q | -| test.cpp:47:16:47:16 | q | semmle.label | q | -| test.cpp:47:16:47:16 | q | semmle.label | q | -| test.cpp:48:16:48:16 | q | semmle.label | q | | test.cpp:51:7:51:14 | mk_array indirection | semmle.label | mk_array indirection | | test.cpp:51:33:51:35 | end | semmle.label | end | | test.cpp:52:19:52:24 | call to malloc | semmle.label | call to malloc | @@ -817,7 +540,6 @@ nodes | test.cpp:66:32:66:34 | end | semmle.label | end | | test.cpp:66:39:66:39 | p | semmle.label | p | | test.cpp:67:9:67:14 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:70:31:70:33 | end | semmle.label | end | | test.cpp:70:38:70:38 | p | semmle.label | p | | test.cpp:80:9:80:16 | mk_array indirection [begin] | semmle.label | mk_array indirection [begin] | | test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] | @@ -850,9 +572,6 @@ nodes | test.cpp:99:20:99:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:99:24:99:28 | begin | semmle.label | begin | | test.cpp:99:24:99:28 | begin indirection | semmle.label | begin indirection | -| test.cpp:99:35:99:37 | arr indirection [end] | semmle.label | arr indirection [end] | -| test.cpp:99:39:99:41 | end | semmle.label | end | -| test.cpp:99:39:99:41 | end indirection | semmle.label | end indirection | | test.cpp:99:46:99:46 | p | semmle.label | p | | test.cpp:104:27:104:29 | arr [begin] | semmle.label | arr [begin] | | test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] | @@ -874,9 +593,6 @@ nodes | test.cpp:113:20:113:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:113:24:113:28 | begin | semmle.label | begin | | test.cpp:113:24:113:28 | begin indirection | semmle.label | begin indirection | -| test.cpp:113:35:113:37 | arr indirection [end] | semmle.label | arr indirection [end] | -| test.cpp:113:39:113:41 | end | semmle.label | end | -| test.cpp:113:39:113:41 | end indirection | semmle.label | end indirection | | test.cpp:113:46:113:46 | p | semmle.label | p | | test.cpp:119:18:119:25 | call to mk_array [begin] | semmle.label | call to mk_array [begin] | | test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] | @@ -942,9 +658,6 @@ nodes | test.cpp:174:20:174:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:174:25:174:29 | begin | semmle.label | begin | | test.cpp:174:25:174:29 | begin indirection | semmle.label | begin indirection | -| test.cpp:174:36:174:38 | arr indirection [end] | semmle.label | arr indirection [end] | -| test.cpp:174:41:174:43 | end | semmle.label | end | -| test.cpp:174:41:174:43 | end indirection | semmle.label | end indirection | | test.cpp:174:48:174:48 | p | semmle.label | p | | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] | @@ -1029,13 +742,6 @@ nodes | test.cpp:314:15:314:16 | xs | semmle.label | xs | | test.cpp:325:14:325:27 | new[] | semmle.label | new[] | | test.cpp:326:15:326:16 | xs | semmle.label | xs | -| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... | -| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... | -| test.cpp:333:5:333:21 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:338:8:338:15 | * ... | semmle.label | * ... | -| test.cpp:341:5:341:21 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:341:8:341:17 | * ... | semmle.label | * ... | -| test.cpp:342:8:342:17 | * ... | semmle.label | * ... | | test.cpp:347:14:347:27 | new[] | semmle.label | new[] | | test.cpp:348:15:348:16 | xs | semmle.label | xs | | test.cpp:350:15:350:19 | Load: * ... | semmle.label | Load: * ... | @@ -1088,8 +794,6 @@ subpaths | test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len | | test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len | | test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... | -| test.cpp:333:5:333:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:333:5:333:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size | -| test.cpp:341:5:341:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:341:5:341:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size | | test.cpp:350:15:350:19 | Load: * ... | test.cpp:347:14:347:27 | new[] | test.cpp:350:15:350:19 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:347:14:347:27 | new[] | new[] | test.cpp:348:20:348:23 | size | size | | test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 3711f272e76..5e79aaa4bd9 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -330,7 +330,7 @@ void test23(unsigned size, int val) { if(*current - xs < 1) return; - *--(*current) = 0; // GOOD [FALSE POSITIVE] + *--(*current) = 0; // GOOD return; } @@ -338,7 +338,7 @@ void test23(unsigned size, int val) { if(*current - xs < 2) return; - *--(*current) = 0; // GOOD [FALSE POSITIVE] + *--(*current) = 0; // GOOD *--(*current) = 0; // GOOD } } From c7c8807f40b4c5e864a4a2d05e15e2d1f4744ad9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 2 Jun 2023 11:44:47 +0100 Subject: [PATCH 118/219] Swift: Use FieldDecl.hasQualifiedName. --- .../frameworks/StandardLibrary/Collection.qll | 7 ++--- .../frameworks/StandardLibrary/NsString.qll | 29 +++++++++---------- .../frameworks/StandardLibrary/Sequence.qll | 7 +---- .../frameworks/StandardLibrary/String.qll | 22 +++++++------- .../frameworks/StandardLibrary/WebView.qll | 7 +---- .../security/CleartextLoggingExtensions.qll | 7 +---- 6 files changed, 31 insertions(+), 48 deletions(-) diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll index fcbd418f6b9..cf3ff748d48 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll @@ -47,9 +47,8 @@ private class CollectionFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { CollectionFieldsInheritTaint() { - exists(FieldDecl f | this.getField() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = ["Collection", "BidirectionalCollection"] and - f.getName() = ["first", "last"] - ) + this.getField() + .(FieldDecl) + .hasQualifiedName(["Collection", "BidirectionalCollection"], ["first", "last"]) } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll index ce8b959fffe..d9743140c34 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll @@ -132,20 +132,19 @@ private class NsStringFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { NsStringFieldsInheritTaint() { - exists(FieldDecl f | this.getField() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = "NSString" and - f.getName() = - [ - "utf8String", "lowercased", "localizedLowedCase", "uppercased", "localizedUppercase", - "capitalized", "localizedCapitalized", "decomposedStringWithCanonicalMapping", - "decomposedStringWithCompatibilityMapping", "precomposedStringWithCanonicalMapping", - "precomposedStringWithCompatibilityMapping", "doubleValue", "floatValue", "intValue", - "integerValue", "longLongValue", "boolValue", "description", "pathComponents", - "fileSystemRepresentation", "lastPathComponent", "pathExtension", - "abbreviatingWithTildeInPath", "deletingLastPathComponent", "deletingPathExtension", - "expandingTildeInPath", "resolvingSymlinksInPath", "standardizingPath", - "removingPercentEncoding" - ] - ) + this.getField() + .(FieldDecl) + .hasQualifiedName("NSString", + [ + "utf8String", "lowercased", "localizedLowedCase", "uppercased", "localizedUppercase", + "capitalized", "localizedCapitalized", "decomposedStringWithCanonicalMapping", + "decomposedStringWithCompatibilityMapping", "precomposedStringWithCanonicalMapping", + "precomposedStringWithCompatibilityMapping", "doubleValue", "floatValue", "intValue", + "integerValue", "longLongValue", "boolValue", "description", "pathComponents", + "fileSystemRepresentation", "lastPathComponent", "pathExtension", + "abbreviatingWithTildeInPath", "deletingLastPathComponent", "deletingPathExtension", + "expandingTildeInPath", "resolvingSymlinksInPath", "standardizingPath", + "removingPercentEncoding" + ]) } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll index 8d4eb9eb39d..b4e68513c1d 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll @@ -36,10 +36,5 @@ private class SequenceSummaries extends SummaryModelCsv { private class SequenceFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { - SequenceFieldsInheritTaint() { - exists(FieldDecl f | this.getField() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = "Sequence" and - f.getName() = "lazy" - ) - } + SequenceFieldsInheritTaint() { this.getField().(FieldDecl).hasQualifiedName("Sequence", "lazy") } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll index 2df33a0f0f4..51424e2d042 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll @@ -124,16 +124,16 @@ private class StringFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { StringFieldsInheritTaint() { - exists(FieldDecl f | this.getField() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = ["String", "StringProtocol"] and - f.getName() = - [ - "unicodeScalars", "utf8", "utf16", "lazy", "utf8CString", "description", - "debugDescription", "dataValue", "identifierValue", "capitalized", "localizedCapitalized", - "localizedLowercase", "localizedUppercase", "decomposedStringWithCanonicalMapping", - "decomposedStringWithCompatibilityMapping", "precomposedStringWithCanonicalMapping", - "precomposedStringWithCompatibilityMapping", "removingPercentEncoding" - ] - ) + this.getField() + .(FieldDecl) + .hasQualifiedName(["String", "StringProtocol"], + [ + "unicodeScalars", "utf8", "utf16", "lazy", "utf8CString", "description", + "debugDescription", "dataValue", "identifierValue", "capitalized", + "localizedCapitalized", "localizedLowercase", "localizedUppercase", + "decomposedStringWithCanonicalMapping", "decomposedStringWithCompatibilityMapping", + "precomposedStringWithCanonicalMapping", "precomposedStringWithCompatibilityMapping", + "removingPercentEncoding" + ]) } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/WebView.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/WebView.qll index 6dd8321388a..b845ee81104 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/WebView.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/WebView.qll @@ -208,10 +208,5 @@ private class WKUserScriptSummaries extends SummaryModelCsv { private class WKUserScriptInheritsTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { - WKUserScriptInheritsTaint() { - exists(FieldDecl f | this.getField() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = "WKUserScript" and - f.getName() = "source" - ) - } + WKUserScriptInheritsTaint() { this.getField().hasQualifiedName("WKUserScript", "source") } } diff --git a/swift/ql/lib/codeql/swift/security/CleartextLoggingExtensions.qll b/swift/ql/lib/codeql/swift/security/CleartextLoggingExtensions.qll index 935da6a232e..21bf855d1fc 100644 --- a/swift/ql/lib/codeql/swift/security/CleartextLoggingExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/CleartextLoggingExtensions.qll @@ -74,12 +74,7 @@ private class OsLogNonRedactedType extends Type { private class OsLogPrivacyRef extends MemberRefExpr { string optionName; - OsLogPrivacyRef() { - exists(FieldDecl f | this.getMember() = f | - f.getEnclosingDecl().asNominalTypeDecl().getName() = "OSLogPrivacy" and - optionName = f.getName() - ) - } + OsLogPrivacyRef() { this.getMember().(FieldDecl).hasQualifiedName("OSLogPrivacy", optionName) } /** Holds if this is a safe privacy option (private or sensitive). */ predicate isSafe() { optionName = ["private", "sensitive"] } From 4c8225724b45a85178b9800402a008a69a9cc3e9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:21:17 +0100 Subject: [PATCH 119/219] Swift: Fix QL-for-QL warnings. --- .../codeql/swift/frameworks/StandardLibrary/Collection.qll | 4 +--- .../lib/codeql/swift/frameworks/StandardLibrary/NsString.qll | 1 - .../lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll | 2 +- .../ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll index cf3ff748d48..6022d4b767a 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Collection.qll @@ -47,8 +47,6 @@ private class CollectionFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { CollectionFieldsInheritTaint() { - this.getField() - .(FieldDecl) - .hasQualifiedName(["Collection", "BidirectionalCollection"], ["first", "last"]) + this.getField().hasQualifiedName(["Collection", "BidirectionalCollection"], ["first", "last"]) } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll index d9743140c34..f866ba23a17 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsString.qll @@ -133,7 +133,6 @@ private class NsStringFieldsInheritTaint extends TaintInheritingContent, { NsStringFieldsInheritTaint() { this.getField() - .(FieldDecl) .hasQualifiedName("NSString", [ "utf8String", "lowercased", "localizedLowedCase", "uppercased", "localizedUppercase", diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll index b4e68513c1d..e830b6cc1a4 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Sequence.qll @@ -36,5 +36,5 @@ private class SequenceSummaries extends SummaryModelCsv { private class SequenceFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent { - SequenceFieldsInheritTaint() { this.getField().(FieldDecl).hasQualifiedName("Sequence", "lazy") } + SequenceFieldsInheritTaint() { this.getField().hasQualifiedName("Sequence", "lazy") } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll index 51424e2d042..4768521322f 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll @@ -125,7 +125,6 @@ private class StringFieldsInheritTaint extends TaintInheritingContent, { StringFieldsInheritTaint() { this.getField() - .(FieldDecl) .hasQualifiedName(["String", "StringProtocol"], [ "unicodeScalars", "utf8", "utf16", "lazy", "utf8CString", "description", From 8ac1d56a7f880ad5348b93765db0e83a0a17a7be Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Fri, 2 Jun 2023 16:37:35 +0200 Subject: [PATCH 120/219] C++: Fix join order in `cpp/invalid-pointer-deref` --- .../Security/CWE/CWE-193/InvalidPointerDeref.ql | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index dbbe398ff7d..88d483dbebc 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -182,6 +182,8 @@ predicate isSinkImpl( /** * Yields any instruction that is control-flow reachable from `instr`. */ +bindingset[instr, result] +pragma[inline_late] Instruction getASuccessor(Instruction instr) { exists(IRBlock b, int instrIndex, int resultIndex | result.getBlock() = b and @@ -202,11 +204,12 @@ Instruction getASuccessor(Instruction instr) { */ pragma[inline] predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) { - exists(AddressOperand addr | - bounded1(addr.getDef(), sink.asInstruction(), delta) and + exists(AddressOperand addr, Instruction s | + s = sink.asInstruction() and + bounded1(addr.getDef(), s, delta) and delta >= 0 and i.getAnOperand() = addr and - i = getASuccessor(sink.asInstruction()) + i = getASuccessor(s) | i instanceof StoreInstruction and operation = "write" From 5608082f356c8a027f66b12e02983801898d122f Mon Sep 17 00:00:00 2001 From: jorgectf <jorgectf@github.com> Date: Fri, 2 Jun 2023 17:57:24 +0200 Subject: [PATCH 121/219] Update `py/unsafe-deserialization` name --- python/ql/src/Security/CWE-502/UnsafeDeserialization.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 0ef54275827..a15838cdabd 100644 --- a/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -1,5 +1,5 @@ /** - * @name Deserializing untrusted input + * @name Deserialization of user-controlled data * @description Deserializing user-controlled data may allow attackers to execute arbitrary code. * @kind path-problem * @id py/unsafe-deserialization From 3e8c7f72b668188981f1f469788109b458d6d26b Mon Sep 17 00:00:00 2001 From: jorgectf <jorgectf@github.com> Date: Fri, 2 Jun 2023 18:20:55 +0200 Subject: [PATCH 122/219] Add changenote --- .../2023-06-02-unsafe-deserialization-name-update.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md diff --git a/python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md b/python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md new file mode 100644 index 00000000000..d786e9dc14d --- /dev/null +++ b/python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages. \ No newline at end of file From 79b3a8c955fc1a70b482af756ffee1d723be5b62 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Fri, 2 Jun 2023 19:39:24 +0100 Subject: [PATCH 123/219] C#: avoid call to Location::toString() --- csharp/ql/src/Complexity/ComplexCondition.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/Complexity/ComplexCondition.ql b/csharp/ql/src/Complexity/ComplexCondition.ql index 2ebbaa8a362..2813db1cda5 100644 --- a/csharp/ql/src/Complexity/ComplexCondition.ql +++ b/csharp/ql/src/Complexity/ComplexCondition.ql @@ -26,4 +26,4 @@ where operators = count(BinaryLogicalOperation op | logicalParent*(op, e) and nontrivialLogicalOperator(op)) and operators > 3 -select e.getLocation(), "Complex condition: too many logical operations in this expression." +select e, "Complex condition: too many logical operations in this expression." From 5d89b0739b8cfc41120727eb4265e7fda3660ccf Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" <mbg@github.com> Date: Mon, 5 Jun 2023 09:12:21 +0100 Subject: [PATCH 124/219] Swift: Remove .cmd script --- swift/tools/identify-environment.cmd | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 swift/tools/identify-environment.cmd diff --git a/swift/tools/identify-environment.cmd b/swift/tools/identify-environment.cmd deleted file mode 100644 index 7fd1786f31f..00000000000 --- a/swift/tools/identify-environment.cmd +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -SETLOCAL EnableDelayedExpansion - -echo { "swift": { "os": { "name": "macOS" } } } - -ENDLOCAL From 400176f677d90700bef9689db8907271ef92d549 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Mon, 5 Jun 2023 11:12:11 +0200 Subject: [PATCH 125/219] Swift: fix cmake generation The bazel -> cmake generator is currently not capable of handling separate included generated cmake files making use of common C/C++ dependencies. To work around this limitation, a single generated cmake is now in place. Long-term, we should either: * make the cmake generator handle common dependencies gracefully, or * make the cmake generation aspect travel up `pkg_` rules `srcs` attributes so to avoid having to list the targets to be generated in the top-level `BUILD` file. Other things fixed: * removed some warning spam about redefined `BAZEL_CURRENT_REPOSITORY` * fixed the final link step, that was failing because `libswiftCore.so` was not being linked. --- misc/bazel/cmake/cmake.bzl | 35 +++++++------------ swift/BUILD.bazel | 13 +++++++ swift/CMakeLists.txt | 5 +-- swift/extractor/BUILD.bazel | 7 +--- .../tests/assertion-diagnostics/BUILD.bazel | 13 +++---- .../tools/autobuilder-diagnostics/BUILD.bazel | 7 ---- swift/xcode-autobuilder/BUILD.bazel | 11 ++---- 7 files changed, 34 insertions(+), 57 deletions(-) diff --git a/misc/bazel/cmake/cmake.bzl b/misc/bazel/cmake/cmake.bzl index d3c6581677b..85760de476c 100644 --- a/misc/bazel/cmake/cmake.bzl +++ b/misc/bazel/cmake/cmake.bzl @@ -11,8 +11,7 @@ CmakeInfo = provider( "includes": "", "quote_includes": "", "stripped_includes": "", - "imported_static_libs": "", - "imported_dynamic_libs": "", + "imported_libs": "", "copts": "", "linkopts": "", "force_cxx_compilation": "", @@ -41,10 +40,8 @@ def _file_kind(file): return "src" if ext in ("h", "hh", "hpp", "def", "inc"): return "hdr" - if ext == "a": - return "static_lib" - if ext in ("so", "dylib"): - return "dynamic_lib" + if ext in ("a", "so", "dylib"): + return "lib" return None def _get_includes(includes): @@ -70,8 +67,7 @@ def _cmake_aspect_impl(target, ctx): by_kind.setdefault(_file_kind(f), []).append(_cmake_file(f)) hdrs = by_kind.get("hdr", []) srcs = by_kind.get("src", []) - static_libs = by_kind.get("static_lib", []) - dynamic_libs = by_kind.get("dynamic_lib", []) + libs = by_kind.get("lib", []) if not srcs and is_binary: empty = ctx.actions.declare_file(name + "_empty.cpp") ctx.actions.write(empty, "") @@ -134,12 +130,15 @@ def _cmake_aspect_impl(target, ctx): system_includes = system_includes, quote_includes = quote_includes, stripped_includes = stripped_includes, - imported_static_libs = static_libs, - imported_dynamic_libs = dynamic_libs, + imported_libs = libs, copts = copts, linkopts = linkopts, defines = compilation_ctx.defines.to_list(), - local_defines = compilation_ctx.local_defines.to_list(), + local_defines = [ + d + for d in compilation_ctx.local_defines.to_list() + if not d.startswith("BAZEL_CURRENT_REPOSITORY") + ], force_cxx_compilation = force_cxx_compilation, transitive_deps = depset(deps, transitive = [dep.transitive_deps for dep in deps]), ), @@ -156,20 +155,10 @@ def _map_cmake_info(info, is_windows): commands = [ "add_%s(%s)" % (info.kind, args), ] - if info.imported_static_libs and info.imported_dynamic_libs: - commands += [ - "if(BUILD_SHARED_LIBS)", - " target_link_libraries(%s %s %s)" % - (info.name, info.modifier or "PUBLIC", " ".join(info.imported_dynamic_libs)), - "else()", - " target_link_libraries(%s %s %s)" % - (info.name, info.modifier or "PUBLIC", " ".join(info.imported_static_libs)), - "endif()", - ] - elif info.imported_static_libs or info.imported_dynamic_libs: + if info.imported_libs: commands += [ "target_link_libraries(%s %s %s)" % - (info.name, info.modifier or "PUBLIC", " ".join(info.imported_dynamic_lib + info.imported_static_libs)), + (info.name, info.modifier or "PUBLIC", " ".join(info.imported_libs)), ] if info.deps: libs = {} diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index c4e41bb0817..59cafbba609 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -2,6 +2,7 @@ load("@rules_pkg//:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files" load("@rules_pkg//:install.bzl", "pkg_install") load("//:defs.bzl", "codeql_platform") load("//misc/bazel:pkg_runfiles.bzl", "pkg_runfiles") +load("//misc/bazel/cmake:cmake.bzl", "generate_cmake") filegroup( name = "schema", @@ -106,3 +107,15 @@ py_binary( main = "create_extractor_pack.py", deps = [":_create_extractor_pack"], ) + +generate_cmake( + name = "cmake", + targets = [ + "//swift/extractor:extractor.real", + "//swift/logging/tests/assertion-diagnostics:assert-false", + ] + select({ + "@platforms//os:linux": ["//swift/tools/autobuilder-diagnostics:incompatible-os"], + "@platforms//os:macos": ["//swift/xcode-autobuilder"], + }), + visibility = ["//visibility:public"], +) diff --git a/swift/CMakeLists.txt b/swift/CMakeLists.txt index fbc55187567..ba4a30d5c4a 100644 --- a/swift/CMakeLists.txt +++ b/swift/CMakeLists.txt @@ -17,7 +17,4 @@ project(codeql) include(../misc/bazel/cmake/setup.cmake) -include_generated(//swift/extractor:cmake) -if (APPLE) - include_generated(//swift/xcode-autobuilder:cmake) -endif () +include_generated(//swift:cmake) diff --git a/swift/extractor/BUILD.bazel b/swift/extractor/BUILD.bazel index 26077dadbd8..984c205d97b 100644 --- a/swift/extractor/BUILD.bazel +++ b/swift/extractor/BUILD.bazel @@ -8,6 +8,7 @@ swift_cc_binary( "*.h", "*.cpp", ]), + visibility = ["//swift:__pkg__"], deps = [ "//swift/extractor/config", "//swift/extractor/infra", @@ -19,12 +20,6 @@ swift_cc_binary( ], ) -generate_cmake( - name = "cmake", - targets = [":extractor.real"], - visibility = ["//visibility:public"], -) - sh_binary( name = "extractor", srcs = ["extractor.sh"], diff --git a/swift/logging/tests/assertion-diagnostics/BUILD.bazel b/swift/logging/tests/assertion-diagnostics/BUILD.bazel index 52c3125a567..e51459e1e17 100644 --- a/swift/logging/tests/assertion-diagnostics/BUILD.bazel +++ b/swift/logging/tests/assertion-diagnostics/BUILD.bazel @@ -4,7 +4,7 @@ load("//misc/bazel/cmake:cmake.bzl", "generate_cmake") swift_cc_binary( name = "assert-false", srcs = ["AssertFalse.cpp"], - visibility = ["//visibility:private"], + visibility = ["//swift:__pkg__"], deps = [ "//swift/logging", ], @@ -14,12 +14,9 @@ py_test( name = "test", size = "small", srcs = ["test.py"], + data = [ + "diagnostics.expected", + ":assert-false", + ], deps = ["//swift/integration-tests:integration_tests"], - data = [":assert-false", "diagnostics.expected"], -) - -generate_cmake( - name = "cmake", - targets = [":assert-false"], - visibility = ["//visibility:public"], ) diff --git a/swift/tools/autobuilder-diagnostics/BUILD.bazel b/swift/tools/autobuilder-diagnostics/BUILD.bazel index 77d90121155..32d6ce703e9 100644 --- a/swift/tools/autobuilder-diagnostics/BUILD.bazel +++ b/swift/tools/autobuilder-diagnostics/BUILD.bazel @@ -1,5 +1,4 @@ load("//swift:rules.bzl", "swift_cc_binary") -load("//misc/bazel/cmake:cmake.bzl", "generate_cmake") swift_cc_binary( name = "incompatible-os", @@ -9,9 +8,3 @@ swift_cc_binary( "//swift/logging", ], ) - -generate_cmake( - name = "cmake", - targets = [":incompatible-os"], - visibility = ["//visibility:public"], -) diff --git a/swift/xcode-autobuilder/BUILD.bazel b/swift/xcode-autobuilder/BUILD.bazel index d497666f3e2..13d6e9818ff 100644 --- a/swift/xcode-autobuilder/BUILD.bazel +++ b/swift/xcode-autobuilder/BUILD.bazel @@ -1,5 +1,4 @@ load("//swift:rules.bzl", "swift_cc_binary") -load("//misc/bazel/cmake:cmake.bzl", "generate_cmake") swift_cc_binary( name = "xcode-autobuilder", @@ -7,20 +6,14 @@ swift_cc_binary( "*.cpp", "*.h", ]), - visibility = ["//swift:__subpackages__"], linkopts = [ "-lxml2", "-framework CoreFoundation", ], target_compatible_with = ["@platforms//os:macos"], + visibility = ["//swift:__subpackages__"], deps = [ - "@absl//absl/strings", "//swift/logging", + "@absl//absl/strings", ], ) - -generate_cmake( - name = "cmake", - targets = [":xcode-autobuilder"], - visibility = ["//visibility:public"], -) From dadb5b34e69fadd5d9bcef12656f382a4f5db38d Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Mon, 5 Jun 2023 10:19:27 +0100 Subject: [PATCH 126/219] C#: avoid call to Location::toString() in cs/expose-implementation --- .../Implementation Hiding/ExposeRepresentation.ql | 2 +- .../ExposeRepresentation/ExposeRepresentation.expected | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql b/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql index e9f9b6cb8c6..3aec796daf7 100644 --- a/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql +++ b/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql @@ -78,4 +78,4 @@ where exposesByStore(c, f, why, whyText) select c, "'" + c.getName() + "' exposes the internal representation stored in field '" + f.getName() + - "'. The value may be modified $@.", why.getLocation(), whyText + "'. The value may be modified $@.", why, whyText diff --git a/csharp/ql/test/query-tests/Bad Practices/Implementation Hiding/ExposeRepresentation/ExposeRepresentation.expected b/csharp/ql/test/query-tests/Bad Practices/Implementation Hiding/ExposeRepresentation/ExposeRepresentation.expected index 92f7365adeb..f4b2fcbf837 100644 --- a/csharp/ql/test/query-tests/Bad Practices/Implementation Hiding/ExposeRepresentation/ExposeRepresentation.expected +++ b/csharp/ql/test/query-tests/Bad Practices/Implementation Hiding/ExposeRepresentation/ExposeRepresentation.expected @@ -1,2 +1,2 @@ -| ExposeRepresentation.cs:8:21:8:23 | Set | 'Set' exposes the internal representation stored in field 'rarray'. The value may be modified $@. | ExposeRepresentation.cs:16:9:16:9 | ExposeRepresentation.cs:16:9:16:9 | through the variable a | -| ExposeRepresentationBad.cs:18:22:18:24 | Get | 'Get' exposes the internal representation stored in field 'rarray'. The value may be modified $@. | ExposeRepresentationBad.cs:24:23:24:29 | ExposeRepresentationBad.cs:24:23:24:29 | after this call to Get | +| ExposeRepresentation.cs:8:21:8:23 | Set | 'Set' exposes the internal representation stored in field 'rarray'. The value may be modified $@. | ExposeRepresentation.cs:16:9:16:9 | access to local variable a | through the variable a | +| ExposeRepresentationBad.cs:18:22:18:24 | Get | 'Get' exposes the internal representation stored in field 'rarray'. The value may be modified $@. | ExposeRepresentationBad.cs:24:23:24:29 | call to method Get | after this call to Get | From be9d32a6c1bbcbfb13d3fb604a1e81bbaff385b7 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Mon, 5 Jun 2023 11:43:48 +0200 Subject: [PATCH 127/219] Bazel/CMake: make include not use cmake include ...but rather just pass along targets. This is required to fix CMake generation in the internal repository. --- misc/bazel/cmake/cmake.bzl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/misc/bazel/cmake/cmake.bzl b/misc/bazel/cmake/cmake.bzl index 85760de476c..653725e5641 100644 --- a/misc/bazel/cmake/cmake.bzl +++ b/misc/bazel/cmake/cmake.bzl @@ -212,7 +212,7 @@ def _map_cmake_info(info, is_windows): GeneratedCmakeFiles = provider( fields = { - "files": "", + "targets": "", }, ) @@ -221,7 +221,11 @@ def _generate_cmake_impl(ctx): inputs = [] infos = {} - for dep in ctx.attr.targets: + targets = list(ctx.attr.targets) + for include in ctx.attr.includes: + targets += include[GeneratedCmakeFiles].targets.to_list() + + for dep in targets: for info in [dep[CmakeInfo]] + dep[CmakeInfo].transitive_deps.to_list(): if info.name != None: inputs += info.inputs @@ -233,11 +237,6 @@ def _generate_cmake_impl(ctx): commands += _map_cmake_info(info, is_windows) commands.append("") - for include in ctx.attr.includes: - for file in include[GeneratedCmakeFiles].files.to_list(): - inputs.append(file) - commands.append("include(${BAZEL_EXEC_ROOT}/%s)" % file.path) - # we want to use a run or run_shell action to register a bunch of files like inputs, but we cannot write all # in a shell command as we would hit the command size limit. So we first write the file and then copy it with # the dummy inputs @@ -248,7 +247,7 @@ def _generate_cmake_impl(ctx): return [ DefaultInfo(files = depset([output])), - GeneratedCmakeFiles(files = depset([output])), + GeneratedCmakeFiles(targets = depset(ctx.attr.targets)), ] generate_cmake = rule( From c67a350e366671a46b737a30a594fb44515aad7a Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Mon, 5 Jun 2023 10:44:22 +0100 Subject: [PATCH 128/219] Python: avoid selecting getLocation() in py/unnecessary-delete --- python/ql/src/Statements/UnnecessaryDelete.ql | 4 ++-- .../query-tests/Statements/general/UnnecessaryDelete.expected | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/Statements/UnnecessaryDelete.ql b/python/ql/src/Statements/UnnecessaryDelete.ql index 429e245fea7..808a3f3a0d3 100644 --- a/python/ql/src/Statements/UnnecessaryDelete.ql +++ b/python/ql/src/Statements/UnnecessaryDelete.ql @@ -36,5 +36,5 @@ where ex = Value::named("sys.exc_info") and ex.getACall().getScope() = f ) -select del, "Unnecessary deletion of local variable $@ in function $@.", e.getLocation(), - e.toString(), f.getLocation(), f.getName() +select del, "Unnecessary deletion of local variable $@ in function $@.", e, e.toString(), f, + f.getName() diff --git a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected index d7dda673775..137ee59e4f2 100644 --- a/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected +++ b/python/ql/test/query-tests/Statements/general/UnnecessaryDelete.expected @@ -1 +1 @@ -| statements_test.py:187:5:187:9 | Delete | Unnecessary deletion of local variable $@ in function $@. | statements_test.py:187:9:187:9 | statements_test.py:187 | x | statements_test.py:185:1:185:31 | statements_test.py:185 | error_unnecessary_delete | +| statements_test.py:187:5:187:9 | Delete | Unnecessary deletion of local variable $@ in function $@. | statements_test.py:187:9:187:9 | x | x | statements_test.py:185:1:185:31 | Function error_unnecessary_delete | error_unnecessary_delete | From 11182e4ee4d0313efb99c84050c0ba82319c3f40 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Mon, 5 Jun 2023 12:36:25 +0200 Subject: [PATCH 129/219] C++: Move location where `getASuccessor` is used to avoid join order problems --- .../Security/CWE/CWE-193/InvalidPointerDeref.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 88d483dbebc..4e5e06775bb 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -208,8 +208,7 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o s = sink.asInstruction() and bounded1(addr.getDef(), s, delta) and delta >= 0 and - i.getAnOperand() = addr and - i = getASuccessor(s) + i.getAnOperand() = addr | i instanceof StoreInstruction and operation = "write" @@ -267,7 +266,8 @@ newtype TMergedPathNode = TPathNodeSink(Instruction i) { exists(DataFlow::Node n | InvalidPointerToDerefFlow::flowTo(n) and - isInvalidPointerDerefSink(n, i, _, _) + isInvalidPointerDerefSink(n, i, _, _) and + i = getASuccessor(n.asInstruction()) ) } From 02395867c8ce76f80905e71a38bdf2f0db45ccd0 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Mon, 5 Jun 2023 11:14:43 +0100 Subject: [PATCH 130/219] Python: avoid selecting getLocation() in py/truncated-division --- python/ql/src/Expressions/TruncatedDivision.ql | 2 +- .../test/2/query-tests/Expressions/TruncatedDivision.expected | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/Expressions/TruncatedDivision.ql b/python/ql/src/Expressions/TruncatedDivision.ql index 0904081f5ff..54758b4b78e 100644 --- a/python/ql/src/Expressions/TruncatedDivision.ql +++ b/python/ql/src/Expressions/TruncatedDivision.ql @@ -34,4 +34,4 @@ where ) ) select div, "Result of division may be truncated as its $@ and $@ arguments may both be integers.", - left.getLocation(), "left", right.getLocation(), "right" + left, "left", right, "right" diff --git a/python/ql/test/2/query-tests/Expressions/TruncatedDivision.expected b/python/ql/test/2/query-tests/Expressions/TruncatedDivision.expected index b22b9b5a2f2..b6407cdca12 100644 --- a/python/ql/test/2/query-tests/Expressions/TruncatedDivision.expected +++ b/python/ql/test/2/query-tests/Expressions/TruncatedDivision.expected @@ -1,2 +1,2 @@ -| TruncatedDivision_test.py:65:7:65:11 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:65:7:65:7 | TruncatedDivision_test.py:65 | left | TruncatedDivision_test.py:65:11:65:11 | TruncatedDivision_test.py:65 | right | -| TruncatedDivision_test.py:72:7:72:35 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:25:12:25:12 | TruncatedDivision_test.py:25 | left | TruncatedDivision_test.py:28:12:28:12 | TruncatedDivision_test.py:28 | right | +| TruncatedDivision_test.py:65:7:65:11 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:65:7:65:7 | ControlFlowNode for IntegerLiteral | left | TruncatedDivision_test.py:65:11:65:11 | ControlFlowNode for IntegerLiteral | right | +| TruncatedDivision_test.py:72:7:72:35 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:25:12:25:12 | ControlFlowNode for IntegerLiteral | left | TruncatedDivision_test.py:28:12:28:12 | ControlFlowNode for IntegerLiteral | right | From a4a7ad8f99f23c3a5be4602030e6d6acea27eb75 Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Mon, 5 Jun 2023 13:20:14 +0100 Subject: [PATCH 131/219] Java/Kotlin: Split lines of code by language We were giving the sum of all lines for both languages, but labelling it as "Total lines of Java code in the database", which was confusing. Now we give separate sums for Kotlin and Java lines. --- java/ql/src/Metrics/Summaries/LinesOfCode.ql | 6 +++--- .../src/Metrics/Summaries/LinesOfCodeKotlin.ql | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 java/ql/src/Metrics/Summaries/LinesOfCodeKotlin.ql diff --git a/java/ql/src/Metrics/Summaries/LinesOfCode.ql b/java/ql/src/Metrics/Summaries/LinesOfCode.ql index c1b43c2a3d9..62c19d1b932 100644 --- a/java/ql/src/Metrics/Summaries/LinesOfCode.ql +++ b/java/ql/src/Metrics/Summaries/LinesOfCode.ql @@ -1,8 +1,8 @@ /** * @id java/summary/lines-of-code * @name Total lines of Java code in the database - * @description The total number of lines of code across all files. This is a useful metric of the size of a database. - * For all files that were seen during the build, this query counts the lines of code, excluding whitespace + * @description The total number of lines of code across all Java files. This is a useful metric of the size of a database. + * For all Java files that were seen during the build, this query counts the lines of code, excluding whitespace * or comments. * @kind metric * @tags summary @@ -11,4 +11,4 @@ import java -select sum(CompilationUnit f | f.fromSource() | f.getNumberOfLinesOfCode()) +select sum(CompilationUnit f | f.fromSource() and f.isJavaSourceFile() | f.getNumberOfLinesOfCode()) diff --git a/java/ql/src/Metrics/Summaries/LinesOfCodeKotlin.ql b/java/ql/src/Metrics/Summaries/LinesOfCodeKotlin.ql new file mode 100644 index 00000000000..0093bc0a98f --- /dev/null +++ b/java/ql/src/Metrics/Summaries/LinesOfCodeKotlin.ql @@ -0,0 +1,18 @@ +/** + * @id java/summary/lines-of-code-kotlin + * @name Total lines of Kotlin code in the database + * @description The total number of lines of code across all Kotlin files. This is a useful metric of the size of a database. + * For all Kotlin files that were seen during the build, this query counts the lines of code, excluding whitespace + * or comments. + * @kind metric + * @tags summary + * lines-of-code + */ + +import java + +select sum(CompilationUnit f | + f.fromSource() and f.isKotlinSourceFile() + | + f.getNumberOfLinesOfCode() + ) From 7f7b048f50d2a22dd22e3b3a163b5b97fc842805 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Mon, 5 Jun 2023 15:00:11 +0200 Subject: [PATCH 132/219] C++: Update expected test results --- .../InvalidPointerDeref.expected | 290 ++++++++++++++++++ 1 file changed, 290 insertions(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 418251cf6db..7cb0738c580 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -9,7 +9,15 @@ edges | test.cpp:5:15:5:15 | p | test.cpp:7:16:7:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:7:16:7:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:8:16:8:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:8:16:8:16 | q | | test.cpp:5:15:5:15 | p | test.cpp:8:16:8:20 | ... + ... | +| test.cpp:5:15:5:15 | p | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:15 | p | test.cpp:12:16:12:16 | q | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | ... + ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:6:14:6:15 | Load: * ... | @@ -30,6 +38,22 @@ edges | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | | test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:8:16:8:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:9:16:9:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:10:16:10:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:11:16:11:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | q | +| test.cpp:5:15:5:22 | ... + ... | test.cpp:12:16:12:16 | q | | test.cpp:6:15:6:15 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:7:16:7:16 | q | @@ -37,11 +61,62 @@ edges | test.cpp:6:15:6:15 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:6:15:6:15 | q | test.cpp:8:16:8:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:8:16:8:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:9:16:9:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:9:16:9:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:10:16:10:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:10:16:10:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:11:16:11:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:11:16:11:16 | q | +| test.cpp:6:15:6:15 | q | test.cpp:12:16:12:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:7:16:7:16 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:7:16:7:16 | q | test.cpp:8:16:8:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:8:16:8:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:9:16:9:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:9:16:9:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:7:16:7:16 | q | test.cpp:12:16:12:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:8:16:8:16 | q | test.cpp:6:14:6:15 | Load: * ... | | test.cpp:8:16:8:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:8:16:8:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:8:16:8:16 | q | test.cpp:9:16:9:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:9:16:9:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:8:16:8:16 | q | test.cpp:12:16:12:16 | q | | test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:9:16:9:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:9:16:9:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:9:16:9:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:9:16:9:16 | q | test.cpp:10:16:10:16 | q | +| test.cpp:9:16:9:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:9:16:9:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:9:16:9:16 | q | test.cpp:12:16:12:16 | q | +| test.cpp:10:16:10:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:10:16:10:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:10:16:10:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:10:16:10:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:10:16:10:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:10:16:10:16 | q | test.cpp:11:16:11:16 | q | +| test.cpp:10:16:10:16 | q | test.cpp:12:16:12:16 | q | +| test.cpp:11:16:11:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:11:16:11:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:11:16:11:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:11:16:11:16 | q | test.cpp:8:14:8:21 | Load: * ... | +| test.cpp:11:16:11:16 | q | test.cpp:12:16:12:16 | q | +| test.cpp:12:16:12:16 | q | test.cpp:6:14:6:15 | Load: * ... | +| test.cpp:12:16:12:16 | q | test.cpp:8:14:8:21 | Load: * ... | | test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | p | | test.cpp:17:15:17:15 | p | test.cpp:17:15:17:22 | ... + ... | | test.cpp:17:15:17:15 | p | test.cpp:20:16:20:20 | ... + ... | @@ -57,7 +132,15 @@ edges | test.cpp:29:15:29:15 | p | test.cpp:31:16:31:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:31:16:31:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:32:16:32:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:32:16:32:16 | q | | test.cpp:29:15:29:15 | p | test.cpp:32:16:32:20 | ... + ... | +| test.cpp:29:15:29:15 | p | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:15 | p | test.cpp:36:16:36:16 | q | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | ... + ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:30:14:30:15 | Load: * ... | @@ -78,6 +161,22 @@ edges | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | | test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:32:16:32:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:33:16:33:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:34:16:34:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:35:16:35:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | q | +| test.cpp:29:15:29:28 | ... + ... | test.cpp:36:16:36:16 | q | | test.cpp:30:15:30:15 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:31:16:31:16 | q | @@ -85,11 +184,62 @@ edges | test.cpp:30:15:30:15 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:30:15:30:15 | q | test.cpp:32:16:32:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:32:16:32:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:33:16:33:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:33:16:33:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:34:16:34:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:34:16:34:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:35:16:35:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:35:16:35:16 | q | +| test.cpp:30:15:30:15 | q | test.cpp:36:16:36:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:31:16:31:16 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:31:16:31:16 | q | test.cpp:32:16:32:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:32:16:32:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:33:16:33:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:33:16:33:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:31:16:31:16 | q | test.cpp:36:16:36:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:32:16:32:16 | q | test.cpp:30:14:30:15 | Load: * ... | | test.cpp:32:16:32:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:32:16:32:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:32:16:32:16 | q | test.cpp:33:16:33:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:33:16:33:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:32:16:32:16 | q | test.cpp:36:16:36:16 | q | | test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:33:16:33:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:33:16:33:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:33:16:33:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:33:16:33:16 | q | test.cpp:34:16:34:16 | q | +| test.cpp:33:16:33:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:33:16:33:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:33:16:33:16 | q | test.cpp:36:16:36:16 | q | +| test.cpp:34:16:34:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:34:16:34:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:34:16:34:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:34:16:34:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:34:16:34:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:34:16:34:16 | q | test.cpp:35:16:35:16 | q | +| test.cpp:34:16:34:16 | q | test.cpp:36:16:36:16 | q | +| test.cpp:35:16:35:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:35:16:35:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:35:16:35:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:35:16:35:16 | q | test.cpp:32:14:32:21 | Load: * ... | +| test.cpp:35:16:35:16 | q | test.cpp:36:16:36:16 | q | +| test.cpp:36:16:36:16 | q | test.cpp:30:14:30:15 | Load: * ... | +| test.cpp:36:16:36:16 | q | test.cpp:32:14:32:21 | Load: * ... | | test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | p | | test.cpp:41:15:41:15 | p | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:15 | p | test.cpp:41:15:41:28 | ... + ... | @@ -100,7 +250,15 @@ edges | test.cpp:41:15:41:15 | p | test.cpp:43:16:43:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:43:16:43:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:44:16:44:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:44:16:44:16 | q | | test.cpp:41:15:41:15 | p | test.cpp:44:16:44:20 | ... + ... | +| test.cpp:41:15:41:15 | p | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:15 | p | test.cpp:48:16:48:16 | q | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | ... + ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:42:14:42:15 | Load: * ... | @@ -121,6 +279,22 @@ edges | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | | test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:44:16:44:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:45:16:45:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:46:16:46:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:47:16:47:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | q | +| test.cpp:41:15:41:28 | ... + ... | test.cpp:48:16:48:16 | q | | test.cpp:42:15:42:15 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:43:16:43:16 | q | @@ -128,11 +302,62 @@ edges | test.cpp:42:15:42:15 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:42:15:42:15 | q | test.cpp:44:16:44:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:44:16:44:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:45:16:45:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:45:16:45:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:46:16:46:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:46:16:46:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:47:16:47:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:47:16:47:16 | q | +| test.cpp:42:15:42:15 | q | test.cpp:48:16:48:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:43:16:43:16 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:43:16:43:16 | q | test.cpp:44:16:44:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:44:16:44:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:45:16:45:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:45:16:45:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:43:16:43:16 | q | test.cpp:48:16:48:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:44:16:44:16 | q | test.cpp:42:14:42:15 | Load: * ... | | test.cpp:44:16:44:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:44:16:44:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:44:16:44:16 | q | test.cpp:45:16:45:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:45:16:45:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:44:16:44:16 | q | test.cpp:48:16:48:16 | q | | test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:45:16:45:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:45:16:45:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:45:16:45:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:45:16:45:16 | q | test.cpp:46:16:46:16 | q | +| test.cpp:45:16:45:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:45:16:45:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:45:16:45:16 | q | test.cpp:48:16:48:16 | q | +| test.cpp:46:16:46:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:46:16:46:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:46:16:46:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:46:16:46:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:46:16:46:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:46:16:46:16 | q | test.cpp:47:16:47:16 | q | +| test.cpp:46:16:46:16 | q | test.cpp:48:16:48:16 | q | +| test.cpp:47:16:47:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:47:16:47:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:47:16:47:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:47:16:47:16 | q | test.cpp:44:14:44:21 | Load: * ... | +| test.cpp:47:16:47:16 | q | test.cpp:48:16:48:16 | q | +| test.cpp:48:16:48:16 | q | test.cpp:42:14:42:15 | Load: * ... | +| test.cpp:48:16:48:16 | q | test.cpp:44:14:44:21 | Load: * ... | | test.cpp:51:7:51:14 | mk_array indirection | test.cpp:60:19:60:26 | call to mk_array | | test.cpp:51:33:51:35 | end | test.cpp:60:34:60:37 | mk_array output argument | | test.cpp:52:19:52:24 | call to malloc | test.cpp:51:7:51:14 | mk_array indirection | @@ -146,8 +371,10 @@ edges | test.cpp:60:19:60:26 | call to mk_array | test.cpp:70:38:70:38 | p | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | end | | test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | end | +| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | end | | test.cpp:62:32:62:34 | end | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:66:32:66:34 | end | test.cpp:67:9:67:14 | Store: ... = ... | +| test.cpp:70:31:70:33 | end | test.cpp:67:9:67:14 | Store: ... = ... | | test.cpp:80:9:80:16 | mk_array indirection [begin] | test.cpp:89:19:89:26 | call to mk_array [begin] | | test.cpp:80:9:80:16 | mk_array indirection [begin] | test.cpp:119:18:119:25 | call to mk_array [begin] | | test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:89:19:89:26 | call to mk_array [end] | @@ -168,6 +395,7 @@ edges | test.cpp:89:19:89:26 | call to mk_array [begin] | test.cpp:99:20:99:22 | arr indirection [begin] | | test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:91:36:91:38 | arr indirection [end] | | test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:95:36:95:38 | arr indirection [end] | +| test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:99:35:99:37 | arr indirection [end] | | test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin | | test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin indirection | | test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | p | @@ -188,11 +416,16 @@ edges | test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin indirection | | test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | p | | test.cpp:99:24:99:28 | begin indirection | test.cpp:99:46:99:46 | p | +| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end | +| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end indirection | +| test.cpp:99:39:99:41 | end | test.cpp:96:9:96:14 | Store: ... = ... | +| test.cpp:99:39:99:41 | end indirection | test.cpp:99:39:99:41 | end | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [begin] | test.cpp:113:20:113:22 | arr indirection [begin] | | test.cpp:104:27:104:29 | arr [end] | test.cpp:105:36:105:38 | arr indirection [end] | | test.cpp:104:27:104:29 | arr [end] | test.cpp:109:36:109:38 | arr indirection [end] | +| test.cpp:104:27:104:29 | arr [end] | test.cpp:113:35:113:37 | arr indirection [end] | | test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin | | test.cpp:105:20:105:22 | arr indirection [begin] | test.cpp:105:24:105:28 | begin indirection | | test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | p | @@ -213,6 +446,10 @@ edges | test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin indirection | | test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | p | | test.cpp:113:24:113:28 | begin indirection | test.cpp:113:46:113:46 | p | +| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end | +| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end indirection | +| test.cpp:113:39:113:41 | end | test.cpp:110:9:110:14 | Store: ... = ... | +| test.cpp:113:39:113:41 | end indirection | test.cpp:113:39:113:41 | end | | test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] | | test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] | | test.cpp:124:15:124:20 | call to malloc | test.cpp:125:5:125:17 | ... = ... | @@ -267,6 +504,7 @@ edges | test.cpp:165:29:165:31 | arr indirection [begin] | test.cpp:174:20:174:22 | arr indirection [begin] | | test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:166:37:166:39 | arr indirection [end] | | test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:170:37:170:39 | arr indirection [end] | +| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:174:36:174:38 | arr indirection [end] | | test.cpp:166:20:166:22 | arr indirection [begin] | test.cpp:166:25:166:29 | begin | | test.cpp:166:20:166:22 | arr indirection [begin] | test.cpp:166:25:166:29 | begin indirection | | test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | p | @@ -287,6 +525,10 @@ edges | test.cpp:174:20:174:22 | arr indirection [begin] | test.cpp:174:25:174:29 | begin indirection | | test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | p | | test.cpp:174:25:174:29 | begin indirection | test.cpp:174:48:174:48 | p | +| test.cpp:174:36:174:38 | arr indirection [end] | test.cpp:174:41:174:43 | end | +| test.cpp:174:36:174:38 | arr indirection [end] | test.cpp:174:41:174:43 | end indirection | +| test.cpp:174:41:174:43 | end | test.cpp:171:9:171:14 | Store: ... = ... | +| test.cpp:174:41:174:43 | end indirection | test.cpp:174:41:174:43 | end | | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] | | test.cpp:188:15:188:20 | call to malloc | test.cpp:189:15:189:15 | p | @@ -413,6 +655,14 @@ edges | test.cpp:308:5:308:11 | access to array | test.cpp:308:5:308:29 | Store: ... = ... | | test.cpp:313:14:313:27 | new[] | test.cpp:314:15:314:16 | xs | | test.cpp:325:14:325:27 | new[] | test.cpp:326:15:326:16 | xs | +| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... | +| test.cpp:326:15:326:16 | xs | test.cpp:326:15:326:23 | ... + ... | +| test.cpp:326:15:326:16 | xs | test.cpp:338:8:338:15 | * ... | +| test.cpp:326:15:326:16 | xs | test.cpp:341:8:341:17 | * ... | +| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... | +| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... | +| test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... | +| test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... | | test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs | | test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | | test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | @@ -468,6 +718,7 @@ edges | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:16:359:27 | end_plus_one | +| test.cpp:359:16:359:27 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... | | test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p | @@ -493,7 +744,15 @@ nodes | test.cpp:7:16:7:16 | q | semmle.label | q | | test.cpp:8:14:8:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:8:16:8:16 | q | semmle.label | q | +| test.cpp:8:16:8:16 | q | semmle.label | q | | test.cpp:8:16:8:20 | ... + ... | semmle.label | ... + ... | +| test.cpp:9:16:9:16 | q | semmle.label | q | +| test.cpp:9:16:9:16 | q | semmle.label | q | +| test.cpp:10:16:10:16 | q | semmle.label | q | +| test.cpp:10:16:10:16 | q | semmle.label | q | +| test.cpp:11:16:11:16 | q | semmle.label | q | +| test.cpp:11:16:11:16 | q | semmle.label | q | +| test.cpp:12:16:12:16 | q | semmle.label | q | | test.cpp:16:15:16:20 | call to malloc | semmle.label | call to malloc | | test.cpp:17:15:17:15 | p | semmle.label | p | | test.cpp:17:15:17:22 | ... + ... | semmle.label | ... + ... | @@ -512,7 +771,15 @@ nodes | test.cpp:31:16:31:16 | q | semmle.label | q | | test.cpp:32:14:32:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:32:16:32:16 | q | semmle.label | q | +| test.cpp:32:16:32:16 | q | semmle.label | q | | test.cpp:32:16:32:20 | ... + ... | semmle.label | ... + ... | +| test.cpp:33:16:33:16 | q | semmle.label | q | +| test.cpp:33:16:33:16 | q | semmle.label | q | +| test.cpp:34:16:34:16 | q | semmle.label | q | +| test.cpp:34:16:34:16 | q | semmle.label | q | +| test.cpp:35:16:35:16 | q | semmle.label | q | +| test.cpp:35:16:35:16 | q | semmle.label | q | +| test.cpp:36:16:36:16 | q | semmle.label | q | | test.cpp:40:15:40:20 | call to malloc | semmle.label | call to malloc | | test.cpp:41:15:41:15 | p | semmle.label | p | | test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... | @@ -526,7 +793,15 @@ nodes | test.cpp:43:16:43:16 | q | semmle.label | q | | test.cpp:44:14:44:21 | Load: * ... | semmle.label | Load: * ... | | test.cpp:44:16:44:16 | q | semmle.label | q | +| test.cpp:44:16:44:16 | q | semmle.label | q | | test.cpp:44:16:44:20 | ... + ... | semmle.label | ... + ... | +| test.cpp:45:16:45:16 | q | semmle.label | q | +| test.cpp:45:16:45:16 | q | semmle.label | q | +| test.cpp:46:16:46:16 | q | semmle.label | q | +| test.cpp:46:16:46:16 | q | semmle.label | q | +| test.cpp:47:16:47:16 | q | semmle.label | q | +| test.cpp:47:16:47:16 | q | semmle.label | q | +| test.cpp:48:16:48:16 | q | semmle.label | q | | test.cpp:51:7:51:14 | mk_array indirection | semmle.label | mk_array indirection | | test.cpp:51:33:51:35 | end | semmle.label | end | | test.cpp:52:19:52:24 | call to malloc | semmle.label | call to malloc | @@ -540,6 +815,7 @@ nodes | test.cpp:66:32:66:34 | end | semmle.label | end | | test.cpp:66:39:66:39 | p | semmle.label | p | | test.cpp:67:9:67:14 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:70:31:70:33 | end | semmle.label | end | | test.cpp:70:38:70:38 | p | semmle.label | p | | test.cpp:80:9:80:16 | mk_array indirection [begin] | semmle.label | mk_array indirection [begin] | | test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] | @@ -572,6 +848,9 @@ nodes | test.cpp:99:20:99:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:99:24:99:28 | begin | semmle.label | begin | | test.cpp:99:24:99:28 | begin indirection | semmle.label | begin indirection | +| test.cpp:99:35:99:37 | arr indirection [end] | semmle.label | arr indirection [end] | +| test.cpp:99:39:99:41 | end | semmle.label | end | +| test.cpp:99:39:99:41 | end indirection | semmle.label | end indirection | | test.cpp:99:46:99:46 | p | semmle.label | p | | test.cpp:104:27:104:29 | arr [begin] | semmle.label | arr [begin] | | test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] | @@ -593,6 +872,9 @@ nodes | test.cpp:113:20:113:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:113:24:113:28 | begin | semmle.label | begin | | test.cpp:113:24:113:28 | begin indirection | semmle.label | begin indirection | +| test.cpp:113:35:113:37 | arr indirection [end] | semmle.label | arr indirection [end] | +| test.cpp:113:39:113:41 | end | semmle.label | end | +| test.cpp:113:39:113:41 | end indirection | semmle.label | end indirection | | test.cpp:113:46:113:46 | p | semmle.label | p | | test.cpp:119:18:119:25 | call to mk_array [begin] | semmle.label | call to mk_array [begin] | | test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] | @@ -658,6 +940,9 @@ nodes | test.cpp:174:20:174:22 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:174:25:174:29 | begin | semmle.label | begin | | test.cpp:174:25:174:29 | begin indirection | semmle.label | begin indirection | +| test.cpp:174:36:174:38 | arr indirection [end] | semmle.label | arr indirection [end] | +| test.cpp:174:41:174:43 | end | semmle.label | end | +| test.cpp:174:41:174:43 | end indirection | semmle.label | end indirection | | test.cpp:174:48:174:48 | p | semmle.label | p | | test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] | | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] | @@ -742,6 +1027,11 @@ nodes | test.cpp:314:15:314:16 | xs | semmle.label | xs | | test.cpp:325:14:325:27 | new[] | semmle.label | new[] | | test.cpp:326:15:326:16 | xs | semmle.label | xs | +| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:338:8:338:15 | * ... | semmle.label | * ... | +| test.cpp:341:8:341:17 | * ... | semmle.label | * ... | +| test.cpp:342:8:342:17 | * ... | semmle.label | * ... | | test.cpp:347:14:347:27 | new[] | semmle.label | new[] | | test.cpp:348:15:348:16 | xs | semmle.label | xs | | test.cpp:350:15:350:19 | Load: * ... | semmle.label | Load: * ... | From 90f0209095943c7d1c9b1887a682cab03a8b5d95 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Mon, 5 Jun 2023 14:53:01 +0200 Subject: [PATCH 133/219] C++: Add `cpp/invalid-pointer-deref` test case with almost duplicated results --- .../InvalidPointerDeref.expected | 36 +++++++++++++++++++ .../CWE/CWE-193/pointer-deref/test.cpp | 11 ++++++ 2 files changed, 47 insertions(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 09c75e7369c..f13d7fbf86a 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -732,6 +732,29 @@ edges | test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p | | test.cpp:371:7:371:7 | p | test.cpp:372:15:372:16 | Load: * ... | | test.cpp:372:16:372:16 | p | test.cpp:372:15:372:16 | Load: * ... | +| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:16 | xs | +| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:7 | end | +| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ | +| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ | +| test.cpp:378:15:378:16 | xs | test.cpp:384:14:384:16 | end | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end | +| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end | +| test.cpp:381:5:381:7 | end | test.cpp:384:13:384:16 | Load: * ... | +| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end | +| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end | +| test.cpp:384:14:384:16 | end | test.cpp:384:13:384:16 | Load: * ... | nodes | test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc | | test.cpp:5:15:5:15 | p | semmle.label | p | @@ -1066,6 +1089,17 @@ nodes | test.cpp:371:7:371:7 | p | semmle.label | p | | test.cpp:372:15:372:16 | Load: * ... | semmle.label | Load: * ... | | test.cpp:372:16:372:16 | p | semmle.label | p | +| test.cpp:377:14:377:27 | new[] | semmle.label | new[] | +| test.cpp:378:15:378:16 | xs | semmle.label | xs | +| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... | +| test.cpp:381:5:381:7 | end | semmle.label | end | +| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ | +| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ | +| test.cpp:384:13:384:16 | Load: * ... | semmle.label | Load: * ... | +| test.cpp:384:14:384:16 | end | semmle.label | end | subpaths #select | test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | @@ -1094,3 +1128,5 @@ subpaths | test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size | +| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | +| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 3711f272e76..3465affbc6e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -372,3 +372,14 @@ void test26(unsigned size) { int val = *p; // GOOD [FALSE POSITIVE] } } + +void test27(unsigned size, bool b) { + char *xs = new char[size]; + char *end = xs + size; + + if (b) { + end++; + } + + int val = *end; // BAD +} From 4a27028768a8639fe2f5f3d57b9cc5513b26faf9 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Mon, 5 Jun 2023 14:55:08 +0200 Subject: [PATCH 134/219] C++: Remove `cpp/invalid-pointer-deref` results duplicating ones with smaller `k` --- .../Security/CWE/CWE-193/InvalidPointerDeref.ql | 16 ++++++++++------ .../pointer-deref/InvalidPointerDeref.expected | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 610eb572d8c..20f2e934fed 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -377,15 +377,19 @@ predicate hasFlowPath( } from - MergedPathNode source, MergedPathNode sink, int k2, int k3, string kstr, - InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation, - Expr offset, DataFlow::Node n + MergedPathNode source, MergedPathNode sink, int k, string kstr, PointerArithmeticInstruction pai, + string operation, Expr offset, DataFlow::Node n where - hasFlowPath(source, sink, source3, pai, operation, k3) and - invalidPointerToDerefSource(pai, source3.getNode(), k2) and + k = + min(int k2, int k3, InvalidPointerToDerefFlow::PathNode source3 | + hasFlowPath(source, sink, source3, pai, operation, k3) and + invalidPointerToDerefSource(pai, source3.getNode(), k2) + | + k2 + k3 + ) and offset = pai.getRight().getUnconvertedResultExpression() and n = source.asPathNode1().getNode() and - if (k2 + k3) = 0 then kstr = "" else kstr = " + " + (k2 + k3) + if k = 0 then kstr = "" else kstr = " + " + k select sink, source, sink, "This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr + ".", n, n.toString(), offset, offset.toString() diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index f13d7fbf86a..056e088658b 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -1128,5 +1128,4 @@ subpaths | test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size | -| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | | test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | From 86df424fca6400a16a4c0a4d8979a9f828e76ac4 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <jketema@github.com> Date: Mon, 5 Jun 2023 15:10:54 +0200 Subject: [PATCH 135/219] C++: Fix query formatting --- .../experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 20f2e934fed..18c9c0f2185 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -385,7 +385,7 @@ where hasFlowPath(source, sink, source3, pai, operation, k3) and invalidPointerToDerefSource(pai, source3.getNode(), k2) | - k2 + k3 + k2 + k3 ) and offset = pai.getRight().getUnconvertedResultExpression() and n = source.asPathNode1().getNode() and From e49b278d614dc6a2e20ce2eb07966ae455b18681 Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Mon, 5 Jun 2023 16:33:12 +0100 Subject: [PATCH 136/219] Java/Kotlin: Add a changenote for the lines-of-code changes. --- java/ql/src/change-notes/2023-06-05-lines-of-code.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/src/change-notes/2023-06-05-lines-of-code.md diff --git a/java/ql/src/change-notes/2023-06-05-lines-of-code.md b/java/ql/src/change-notes/2023-06-05-lines-of-code.md new file mode 100644 index 00000000000..a96c891e506 --- /dev/null +++ b/java/ql/src/change-notes/2023-06-05-lines-of-code.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `java/summary/lines-of-code` query now only counts lines of Java code. The new `java/summary/lines-of-code-kotlin` counts lines of Kotlin code. From 7ad860fc98c1a19720a9cf4dd6f277da0c2de87a Mon Sep 17 00:00:00 2001 From: Taus <tausbn@github.com> Date: Mon, 5 Jun 2023 18:00:40 +0200 Subject: [PATCH 137/219] Java: Update MaD declarations after triage Co-authored-by: Stephan Brandauer <kaeluka@github.com> --- java/ql/lib/change-notes/2023-06-01-new-models.md | 7 +++++++ java/ql/lib/ext/java.lang.model.yml | 2 ++ java/ql/lib/ext/java.nio.file.model.yml | 6 ++++++ 3 files changed, 15 insertions(+) create mode 100644 java/ql/lib/change-notes/2023-06-01-new-models.md diff --git a/java/ql/lib/change-notes/2023-06-01-new-models.md b/java/ql/lib/change-notes/2023-06-01-new-models.md new file mode 100644 index 00000000000..d05b3d4d59d --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-01-new-models.md @@ -0,0 +1,7 @@ +--- +category: minorAnalysis +--- +* Added models for the following packages: + + * java.lang + * java.nio.file diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml index ed14b2495a3..a0dc4947fc6 100644 --- a/java/ql/lib/ext/java.lang.model.yml +++ b/java/ql/lib/ext/java.lang.model.yml @@ -8,6 +8,8 @@ extensions: - ["java.lang", "ClassLoader", True, "getSystemResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "ClassLoader", True, "getSystemResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "Module", True, "getResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["java.lang", "Runtime", False, "load", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", False, "loadLibrary", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] # These are modeled in plain CodeQL. TODO: migrate them. # - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] # - ["java.lang", "ProcessBuilder", False, "directory", "(File)", "", "Argument[0]", "command-injection", "ai-manual"] diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index e4519fbc071..d14ae993388 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -18,6 +18,7 @@ extensions: - ["java.nio.file", "Files", False, "delete", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "deleteIfExists", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "deleteIfExists", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["java.nio.file", "Files", False, "getFileStore", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] # the FileStore class is unlikely to be used for later sanitization - ["java.nio.file", "Files", False, "lines", "(Path,Charset)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "lines", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "move", "", "", "Argument[1]", "path-injection", "manual"] @@ -26,6 +27,7 @@ extensions: - ["java.nio.file", "Files", False, "newBufferedWriter", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "newInputStream", "(Path,OpenOption[])", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "newOutputStream", "", "", "Argument[0]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "probeContentType", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] # accesses the file based on user input, but only reads its content type from it - ["java.nio.file", "Files", False, "readAllBytes", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "readAllLines", "(Path,Charset)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.nio.file", "Files", False, "readAllLines", "(Path)", "", "Argument[0]", "path-injection", "ai-manual"] @@ -46,6 +48,10 @@ extensions: pack: codeql/java-all extensible: summaryModel data: + - ["java.nio.file", "Files", False, "find", "(Path,int,BiPredicate,FileVisitOption[])", "", "Argument[0]", "ReturnValue.Element", "taint", "ai-manual"] + - ["java.nio.file", "Files", False, "find", "(Path,int,BiPredicate,FileVisitOption[])", "", "Argument[2]", "ReturnValue.Element", "taint", "ai-manual"] + - ["java.nio.file", "Files", False, "list", "(Path)", "", "Argument[0]", "ReturnValue.Element", "taint", "ai-manual"] + - ["java.nio.file", "Files", False, "readSymbolicLink", "(Path)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] # this can be used to enumerate a file system - ["java.nio.file", "Files", True, "newBufferedReader", "(Path,Charset)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] - ["java.nio.file", "Files", True, "newBufferedReader", "(Path)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] - ["java.nio.file", "Files", True, "newByteChannel", "(Path,OpenOption[])", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] From 3cb2ec4e8710bdf159ddc5045c518f0a93934587 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Mon, 5 Jun 2023 19:06:07 +0200 Subject: [PATCH 138/219] fix nits from doc review --- javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp index 9ee5158bf99..9fb1f9a39ed 100644 --- a/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp +++ b/javascript/ql/src/Security/CWE-089/SqlInjection.inc.qhelp @@ -38,7 +38,7 @@ an HTTP request handler in a web application, whose parameter </p> <p> -The handler constructs constructs an SQL query string from user input +The handler constructs an SQL query string from user input and executes it as a database query using the <code>pg</code> library. The user input may contain quote characters, so this code is vulnerable to a SQL injection attack. @@ -65,7 +65,7 @@ escape the user input before embedding it into the query string: <example> <p> -In the following example an express handler attempts to delete +In the following example, an express handler attempts to delete a single document from a MongoDB collection. The document to be deleted is identified by its <code>_id</code> field, which is constructed from user input. The user input may contain a query @@ -75,7 +75,7 @@ object, so this code is vulnerable to a NoSQL injection attack. <sample src="examples/NoSqlInjection.js" /> <p> -To fix this vulnerability we can use the <code>$eq</code> operator +To fix this vulnerability, we can use the <code>$eq</code> operator to ensure that the user input is interpreted as a literal value and not as a query object: </p> From d38bca1e8ced5cc0ea684fde4da1ed5291290e85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 04:02:46 +0000 Subject: [PATCH 139/219] Bump regex from 1.8.3 to 1.8.4 in /ql Bumps [regex](https://github.com/rust-lang/regex) from 1.8.3 to 1.8.4. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.8.3...1.8.4) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- ql/Cargo.lock | Bin 31667 -> 31667 bytes ql/buramu/Cargo.toml | 2 +- ql/extractor/Cargo.toml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/Cargo.lock b/ql/Cargo.lock index de833d37b96bcb4b4ef42188f3f137daa116c0b8..7f62aa9e6773c4f8b6956a331bab55ccd562caf7 100644 GIT binary patch delta 87 zcmV~$!3}^Q3;@8mfKRtDDHIC+O!)fH5h$e#v4{yy;xat-u8*mY>7G-2k8>Buj3tvN p@0m??Ms1EI79p~goid=W6bfpHl8ulN)fzW}fB@RAb?Hy~!VfKL9Si^f delta 88 zcmV~$%ME}a3;@uufJg5RU_#5M<>Y|{bc8~~3J$^|Cb%0%eQ!)Nrg@fZT;J~VfGRez qBt|G2P-8*glndCRmZ5o4mntF=S7{;?1UZmItkEUguYDbF{^$qUdmCl| diff --git a/ql/buramu/Cargo.toml b/ql/buramu/Cargo.toml index 13aaddaf989..3c1c885037e 100644 --- a/ql/buramu/Cargo.toml +++ b/ql/buramu/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" lazy_static = "1.4.0" chrono = "0.4.26" rayon = "1.7.0" -regex = "1.8.3" +regex = "1.8.4" diff --git a/ql/extractor/Cargo.toml b/ql/extractor/Cargo.toml index f026145c72f..90289b0d688 100644 --- a/ql/extractor/Cargo.toml +++ b/ql/extractor/Cargo.toml @@ -16,5 +16,5 @@ clap = { version = "4.2", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } rayon = "1.7.0" -regex = "1.8.3" +regex = "1.8.4" codeql-extractor = { path = "../../shared/tree-sitter-extractor" } From 1ccec90c6f5d2379f51797d29e2235466894f669 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Tue, 6 Jun 2023 09:10:18 +0200 Subject: [PATCH 140/219] Apply suggestions from code review Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com> --- java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md b/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md index 5f666a0de4f..ae5cd306c2b 100644 --- a/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md +++ b/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kinds `create-file` and `read-file`. +* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. From 0065e6e1d6efeb95b7a94a79cad40ad4a2a761cf Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:04:22 +0200 Subject: [PATCH 141/219] Apply suggestions from code review Fix incorrect models-as-data rows --- java/ql/lib/ext/java.nio.file.model.yml | 6 ++++-- java/ql/lib/ext/java.nio.model.yml | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index 475ddc43eef..f27f6a249a1 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -3,9 +3,11 @@ extensions: pack: codeql/java-all extensible: sinkModel data: - - ["java.nio.file", "Files", False, "copy", "", "", "Argument[0]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "(Path,OutputStream)", "", "Argument[0]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "(Path,Path,CopyOption[])", "", "Argument[0]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "(Path,Path,CopyOption[])", "", "Argument[1]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "copy", "(InputStream,Path,CopyOption[])", "", "Argument[0]", "file-content-store", "manual"] - - ["java.nio.file", "Files", False, "copy", "", "", "Argument[1]", "path-injection", "manual"] + - ["java.nio.file", "Files", False, "copy", "(InputStream,Path,CopyOption[])", "", "Argument[1]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createDirectories", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createDirectory", "", "", "Argument[0]", "path-injection", "manual"] - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "path-injection", "manual"] diff --git a/java/ql/lib/ext/java.nio.model.yml b/java/ql/lib/ext/java.nio.model.yml index 9fbe1b253ec..1548dc2c649 100644 --- a/java/ql/lib/ext/java.nio.model.yml +++ b/java/ql/lib/ext/java.nio.model.yml @@ -6,7 +6,6 @@ extensions: - ["java.nio", "ByteBuffer", False, "array", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.nio", "ByteBuffer", False, "get", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.nio", "ByteBuffer", False, "wrap", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["java.nio", "Paths", False, "get", "(URI)", "", "Argument[0]", "ReturnValue", "taint", "manual"] # old PathCreation - addsTo: pack: codeql/java-all From 1601846478e04f082886014baf0d7cadfc17a991 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:06:06 +0200 Subject: [PATCH 142/219] Add exclusion to the ZipSlip query to avoid FPs --- .../code/java/security/ZipSlipQuery.qll | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll index 4fad191a3e4..68365db51c2 100644 --- a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll @@ -4,6 +4,7 @@ import java import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.PathSanitizer private import semmle.code.java.dataflow.ExternalFlow +private import semmle.code.java.security.PathCreation /** * A method that returns the name of an archive entry. @@ -40,5 +41,25 @@ module ZipSlipFlow = TaintTracking::Global<ZipSlipConfig>; * A sink that represents a file creation, such as a file write, copy or move operation. */ private class FileCreationSink extends DataFlow::Node { - FileCreationSink() { sinkNode(this, "path-injection") } + FileCreationSink() { + sinkNode(this, "path-injection") and + not isPathCreation(this) + } +} + +/** + * Holds if `sink` is a path creation node that doesn't imply a read/write filesystem operation. + * This is to avoid creating new spurious alerts, since `PathCreation` sinks weren't + * previosuly part of this query. + */ +private predicate isPathCreation(DataFlow::Node sink) { + exists(PathCreation pc | + pc.getAnInput() = sink.asExpr() and + // exclude actual read/write operations included in `PathCreation` + not pc.(Call) + .getCallee() + .getDeclaringType() + .hasQualifiedName("java.io", + ["FileInputStream", "FileOutputStream", "FileReader", "FileWriter"]) + ) } From 72af63457518c54511882d59edaf75257a1dcdcd Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:22:16 +0200 Subject: [PATCH 143/219] Kotlin: Add flow through use and with --- java/ql/lib/ext/kotlin.io.model.yml | 2 ++ java/ql/lib/ext/kotlin.model.yml | 7 +++++++ .../kotlin/library-tests/dataflow/summaries/use.kt | 11 +++++++++++ .../kotlin/library-tests/dataflow/summaries/with.kt | 9 +++++++++ 4 files changed, 29 insertions(+) create mode 100644 java/ql/lib/ext/kotlin.model.yml create mode 100644 java/ql/test/kotlin/library-tests/dataflow/summaries/use.kt create mode 100644 java/ql/test/kotlin/library-tests/dataflow/summaries/with.kt diff --git a/java/ql/lib/ext/kotlin.io.model.yml b/java/ql/lib/ext/kotlin.io.model.yml index 98de45df9d6..b748e04a292 100644 --- a/java/ql/lib/ext/kotlin.io.model.yml +++ b/java/ql/lib/ext/kotlin.io.model.yml @@ -11,6 +11,8 @@ extensions: pack: codeql/java-all extensible: summaryModel data: + - ["kotlin.io", "CloseableKt", False, "use", "", "", "Argument[0]", "Argument[1].Parameter[0]", "value", "manual"] + - ["kotlin.io", "CloseableKt", False, "use", "", "", "Argument[1].ReturnValue", "ReturnValue", "value", "manual"] - ["kotlin.io", "FilesKt", False, "normalize", "(File)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] - ["kotlin.io", "FilesKt", False, "relativeTo", "(File,File)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] - ["kotlin.io", "FilesKt", False, "relativeTo", "(File,File)", "", "Argument[1]", "ReturnValue", "taint", "ai-manual"] diff --git a/java/ql/lib/ext/kotlin.model.yml b/java/ql/lib/ext/kotlin.model.yml new file mode 100644 index 00000000000..ea275a78515 --- /dev/null +++ b/java/ql/lib/ext/kotlin.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["kotlin", "StandardKt", False, "with", "", "", "Argument[0]", "Argument[1].Parameter[0]", "value", "manual"] + - ["kotlin", "StandardKt", False, "with", "", "", "Argument[1].ReturnValue", "ReturnValue", "value", "manual"] diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/use.kt b/java/ql/test/kotlin/library-tests/dataflow/summaries/use.kt new file mode 100644 index 00000000000..07beffd2be2 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/use.kt @@ -0,0 +1,11 @@ +import java.io.Closeable + +class UseFlowTest { + fun <T> taint(t: T) = t + fun sink(s: Closeable) { } + + fun test(input: Closeable) { + taint(input).use { it -> sink(it) } // $ hasValueFlow + sink(taint(input).use { it }) // $ hasValueFlow + } +} diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/with.kt b/java/ql/test/kotlin/library-tests/dataflow/summaries/with.kt new file mode 100644 index 00000000000..d495f95c854 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/with.kt @@ -0,0 +1,9 @@ +class WithFlowTest { + fun <T> taint(t: T) = t + fun sink(s: String) { } + + fun test(input: String) { + with(taint(input)) { sink(this) } // $ hasValueFlow + sink(with(taint(input)) { this }) // $ hasValueFlow + } +} From 1d8ca88aca07662a39fc7c20b07548c4c8c26b9c Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:25:07 +0200 Subject: [PATCH 144/219] Add change note --- java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md diff --git a/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md b/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md new file mode 100644 index 00000000000..b21f31aae5f --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow through the block arguments of `kotlin.io.use` and `kotlin.with`. From f4fd908f7f38903368ef368996531108435ecbc6 Mon Sep 17 00:00:00 2001 From: Taus <tausbn@github.com> Date: Tue, 6 Jun 2023 13:01:59 +0200 Subject: [PATCH 145/219] Java: Comment out sinks for which no query exists --- java/ql/lib/ext/java.lang.model.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml index a0dc4947fc6..8625a68caa0 100644 --- a/java/ql/lib/ext/java.lang.model.yml +++ b/java/ql/lib/ext/java.lang.model.yml @@ -8,8 +8,9 @@ extensions: - ["java.lang", "ClassLoader", True, "getSystemResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "ClassLoader", True, "getSystemResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "Module", True, "getResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - - ["java.lang", "Runtime", False, "load", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] - - ["java.lang", "Runtime", False, "loadLibrary", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] + # These are potential vulnerabilities, but not for command-injection. No query for this kind of vulnerability currently exists. + # - ["java.lang", "Runtime", False, "load", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] + # - ["java.lang", "Runtime", False, "loadLibrary", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] # These are modeled in plain CodeQL. TODO: migrate them. # - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] # - ["java.lang", "ProcessBuilder", False, "directory", "(File)", "", "Argument[0]", "command-injection", "ai-manual"] From 75bc8756f2ec451512a000fb867766ac1de0b8c6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk <tamasvajk@github.com> Date: Tue, 6 Jun 2023 14:22:56 +0200 Subject: [PATCH 146/219] C#: Change standalone extraction to allow unsafe code --- .../Semmle.Extraction.CSharp.Standalone/Extractor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Extractor.cs index 97a25d200f7..a9f43af2bea 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Extractor.cs @@ -33,7 +33,9 @@ namespace Semmle.Extraction.CSharp.Standalone CSharp.Extractor.Analyse(stopwatch, analyser, options, references => GetResolvedReferencesStandalone(referencePaths, references), (analyser, syntaxTrees) => CSharp.Extractor.ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees), - (syntaxTrees, references) => CSharpCompilation.Create("csharp.dll", syntaxTrees, references), + (syntaxTrees, references) => CSharpCompilation.Create( + "csharp.dll", syntaxTrees, references, new CSharpCompilationOptions(OutputKind.ConsoleApplication, allowUnsafe: true) + ), (compilation, options) => analyser.Initialize(compilation, options), () => { }, _ => { }, From a4dec591c713e5e92e36e564910c1ea5b4e4c3bd Mon Sep 17 00:00:00 2001 From: Tamas Vajk <tamasvajk@github.com> Date: Tue, 6 Jun 2023 15:01:54 +0200 Subject: [PATCH 147/219] C#: Improve error message for missing explicit interface implementation --- .../extractor/Semmle.Extraction.CSharp/Entities/Method.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 22bf9f69670..8b64df0443e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -243,7 +243,12 @@ namespace Semmle.Extraction.CSharp.Entities if (methodKind == MethodKind.ExplicitInterfaceImplementation) { // Retrieve the original method kind - methodKind = methodDecl.ExplicitInterfaceImplementations.Select(m => m.MethodKind).FirstOrDefault(); + if (methodDecl.ExplicitInterfaceImplementations.IsEmpty) + { + throw new InternalError(methodDecl, $"Couldn't get the original method kind for explicit interface implementation"); + } + + methodKind = methodDecl.ExplicitInterfaceImplementations.Select(m => m.MethodKind).First(); } switch (methodKind) From ca63122ce46a057fc68d016622bde177c668f271 Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Tue, 6 Jun 2023 14:09:55 +0100 Subject: [PATCH 148/219] Kotlin: Relax version requirements If the latest version we know about is 1.9, and we are faced with 1.10, then we try 1.9 rather than failing with an exception. --- java/kotlin-extractor/kotlin_plugin_versions.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py index c5d9e433613..bf1c211073a 100755 --- a/java/kotlin-extractor/kotlin_plugin_versions.py +++ b/java/kotlin-extractor/kotlin_plugin_versions.py @@ -24,7 +24,6 @@ def version_string_to_tuple(version): # Version number used by CI. ci_version = '1.8.10' -# Version numbers in the list need to be in semantically increasing order many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20', '1.8.0', '1.9.0-Beta' ] many_versions_tuples = [version_string_to_tuple(v) for v in many_versions] @@ -42,18 +41,13 @@ def get_single_version(fakeVersionOutput = None): if m is None: raise Exception('Cannot detect version of kotlinc (got ' + str(versionOutput) + ')') current_version = version_string_to_tuple(m.group(1)) - matching_minor_versions = [ version for version in many_versions_tuples if version[0:2] == current_version[0:2] ] - if len(matching_minor_versions) == 0: - raise Exception(f'Cannot find a matching minor version for kotlinc version {current_version} (got {versionOutput}; know about {str(many_versions)})') - matching_minor_versions.sort(reverse = True) + many_versions_tuples.sort(reverse = True) - for version in matching_minor_versions: + for version in many_versions_tuples: if version[0:3] <= current_version[0:3]: return version_tuple_to_string(version) - return version_tuple_to_string(matching_minor_versions[-1]) - raise Exception(f'No suitable kotlinc version found for {current_version} (got {versionOutput}; know about {str(many_versions)})') def get_latest_url(): From 2529312d1d0533c1630e0d4f2650856a26f87db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nora=20Dimitrijevi=C4=87?= <d10c@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:58:19 +0200 Subject: [PATCH 149/219] Codegen: fix test.qlgen failure --- misc/codegen/test/test_qlgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 1e68e43c7dc..12d5d28bca6 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -885,7 +885,7 @@ def test_synth_property(generate_classes): schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "bar", synth=True)]), ]) == { - "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + "MyObject.qll": (a_ql_stub(name="MyObject"), a_ql_class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, From e8f56f29817bfa96bcbfeacb02845d1818f27d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Vajk?= <tamasvajk@github.com> Date: Tue, 6 Jun 2023 16:20:48 +0200 Subject: [PATCH 150/219] Update csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs Co-authored-by: Michael B. Gale <mbg@github.com> --- csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 8b64df0443e..bae6a2b55ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -245,7 +245,7 @@ namespace Semmle.Extraction.CSharp.Entities // Retrieve the original method kind if (methodDecl.ExplicitInterfaceImplementations.IsEmpty) { - throw new InternalError(methodDecl, $"Couldn't get the original method kind for explicit interface implementation"); + throw new InternalError(methodDecl, $"Couldn't get the original method kind for an explicit interface implementation"); } methodKind = methodDecl.ExplicitInterfaceImplementations.Select(m => m.MethodKind).First(); From 75cbcdd72e8bad639f96447ff2b49cbc134bbf78 Mon Sep 17 00:00:00 2001 From: Stephan Brandauer <kaeluka@github.com> Date: Tue, 6 Jun 2023 16:38:31 +0200 Subject: [PATCH 151/219] Update MaD Declarations after Triage --- java/ql/lib/change-notes/2023-06-06-new-models.md | 15 +++++++++++++++ java/ql/lib/ext/com.alibaba.druid.sql.model.yml | 6 ++++++ .../ext/com.fasterxml.jackson.databind.model.yml | 6 ++++++ java/ql/lib/ext/com.jcraft.jsch.model.yml | 11 +++++++++++ java/ql/lib/ext/io.netty.handler.ssl.model.yml | 2 ++ java/ql/lib/ext/okhttp3.model.yml | 1 + java/ql/lib/ext/org.antlr.runtime.model.yml | 6 ++++++ .../lib/ext/org.fusesource.leveldbjni.model.yml | 6 ++++++ java/ql/lib/ext/org.influxdb.model.yml | 6 ++++++ .../lib/ext/org.springframework.core.io.model.yml | 6 ++++++ java/ql/lib/ext/org.yaml.snakeyaml.model.yml | 6 ++++++ 11 files changed, 71 insertions(+) create mode 100644 java/ql/lib/change-notes/2023-06-06-new-models.md create mode 100644 java/ql/lib/ext/com.alibaba.druid.sql.model.yml create mode 100644 java/ql/lib/ext/com.jcraft.jsch.model.yml create mode 100644 java/ql/lib/ext/org.antlr.runtime.model.yml create mode 100644 java/ql/lib/ext/org.fusesource.leveldbjni.model.yml create mode 100644 java/ql/lib/ext/org.influxdb.model.yml create mode 100644 java/ql/lib/ext/org.springframework.core.io.model.yml create mode 100644 java/ql/lib/ext/org.yaml.snakeyaml.model.yml diff --git a/java/ql/lib/change-notes/2023-06-06-new-models.md b/java/ql/lib/change-notes/2023-06-06-new-models.md new file mode 100644 index 00000000000..cbb80968749 --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-06-new-models.md @@ -0,0 +1,15 @@ +--- +category: minorAnalysis +--- +* Added models for the following packages: + + * com.alibaba.druid.sql + * com.fasterxml.jackson.databind + * com.jcraft.jsch + * io.netty.handler.ssl + * okhttp3 + * org.antlr.runtime + * org.fusesource.leveldbjni + * org.influxdb + * org.springframework.core.io + * org.yaml.snakeyaml diff --git a/java/ql/lib/ext/com.alibaba.druid.sql.model.yml b/java/ql/lib/ext/com.alibaba.druid.sql.model.yml new file mode 100644 index 00000000000..952cd6e8f1b --- /dev/null +++ b/java/ql/lib/ext/com.alibaba.druid.sql.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["com.alibaba.druid.sql", "SQLUtils", False, "toMySqlString", "(SQLObject)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] diff --git a/java/ql/lib/ext/com.fasterxml.jackson.databind.model.yml b/java/ql/lib/ext/com.fasterxml.jackson.databind.model.yml index 3768007ebe7..988820e84dd 100644 --- a/java/ql/lib/ext/com.fasterxml.jackson.databind.model.yml +++ b/java/ql/lib/ext/com.fasterxml.jackson.databind.model.yml @@ -9,3 +9,9 @@ extensions: - ["com.fasterxml.jackson.databind", "ObjectMapper", True, "valueToTree", "", "", "Argument[0].MapValue", "ReturnValue", "taint", "manual"] - ["com.fasterxml.jackson.databind", "ObjectMapper", True, "valueToTree", "", "", "Argument[0].MapValue.Element", "ReturnValue", "taint", "manual"] - ["com.fasterxml.jackson.databind", "ObjectReader", False, "createParser", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.fasterxml.jackson.databind", "ObjectMapper", True, "readValue", "(File,Class)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["com.fasterxml.jackson.databind", "ObjectMapper", True, "writeValue", "(File,Object)", "", "Argument[0]", "path-injection", "ai-manual"] diff --git a/java/ql/lib/ext/com.jcraft.jsch.model.yml b/java/ql/lib/ext/com.jcraft.jsch.model.yml new file mode 100644 index 00000000000..3d658630d56 --- /dev/null +++ b/java/ql/lib/ext/com.jcraft.jsch.model.yml @@ -0,0 +1,11 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["com.jcraft.jsch", "JSch", True, "getSession", "(String,String,int)", "", "Argument[1]", "request-forgery", "ai-manual"] + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["com.jcraft.jsch", "ChannelSftp", True, "realpath", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] diff --git a/java/ql/lib/ext/io.netty.handler.ssl.model.yml b/java/ql/lib/ext/io.netty.handler.ssl.model.yml index 42cf9892f81..f63a7a3906f 100644 --- a/java/ql/lib/ext/io.netty.handler.ssl.model.yml +++ b/java/ql/lib/ext/io.netty.handler.ssl.model.yml @@ -5,3 +5,5 @@ extensions: data: - ["io.netty.handler.ssl", "OpenSslServerContext", False, "OpenSslServerContext", "(File,File)", "", "Argument[0]", "path-injection", "ai-manual"] - ["io.netty.handler.ssl", "SslContextBuilder", False, "forServer", "(File,File)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["io.netty.handler.ssl", "SslContextBuilder", False, "trustManager", "(File)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["io.netty.handler.ssl", "SslContextBuilder", False, "trustManager", "(InputStream)", "", "Argument[0]", "path-injection", "ai-manual"] diff --git a/java/ql/lib/ext/okhttp3.model.yml b/java/ql/lib/ext/okhttp3.model.yml index 2368292dab7..b7bfe8a10f7 100644 --- a/java/ql/lib/ext/okhttp3.model.yml +++ b/java/ql/lib/ext/okhttp3.model.yml @@ -58,3 +58,4 @@ extensions: - ["okhttp3", "HttpUrl$Builder", False, "setQueryParameter", "", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["okhttp3", "HttpUrl$Builder", False, "setQueryParameter", "", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["okhttp3", "HttpUrl$Builder", False, "username", "", "", "Argument[this]", "ReturnValue", "value", "manual"] + - ["okhttp3", "Request$Builder", True, "build", "()", "", "Argument[undefined]", "ReturnValue", "taint", "ai-manual"] diff --git a/java/ql/lib/ext/org.antlr.runtime.model.yml b/java/ql/lib/ext/org.antlr.runtime.model.yml new file mode 100644 index 00000000000..db66062c682 --- /dev/null +++ b/java/ql/lib/ext/org.antlr.runtime.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.antlr.runtime", "ANTLRFileStream", True, "ANTLRFileStream", "(String,String)", "", "Argument[0]", "path-injection", "ai-manual"] diff --git a/java/ql/lib/ext/org.fusesource.leveldbjni.model.yml b/java/ql/lib/ext/org.fusesource.leveldbjni.model.yml new file mode 100644 index 00000000000..2c3f221abd7 --- /dev/null +++ b/java/ql/lib/ext/org.fusesource.leveldbjni.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.fusesource.leveldbjni", "JniDBFactory", True, "open", "(File,Options)", "", "Argument[0]", "path-injection", "ai-manual"] diff --git a/java/ql/lib/ext/org.influxdb.model.yml b/java/ql/lib/ext/org.influxdb.model.yml new file mode 100644 index 00000000000..00dc8277407 --- /dev/null +++ b/java/ql/lib/ext/org.influxdb.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.influxdb", "InfluxDBFactory", False, "connect", "(String,String,String,Builder)", "", "Argument[0]", "request-forgery", "ai-manual"] diff --git a/java/ql/lib/ext/org.springframework.core.io.model.yml b/java/ql/lib/ext/org.springframework.core.io.model.yml new file mode 100644 index 00000000000..7f3f3718471 --- /dev/null +++ b/java/ql/lib/ext/org.springframework.core.io.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] # todo: look into whether this may also be a request forgery sink diff --git a/java/ql/lib/ext/org.yaml.snakeyaml.model.yml b/java/ql/lib/ext/org.yaml.snakeyaml.model.yml new file mode 100644 index 00000000000..e52ef0679bc --- /dev/null +++ b/java/ql/lib/ext/org.yaml.snakeyaml.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["org.yaml.snakeyaml", "Yaml", True, "load", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"] From 0f010afce10584d2b03bef3921162f6ce1461b36 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Tue, 6 Jun 2023 16:53:26 +0200 Subject: [PATCH 152/219] C#: Add dotnet test that targets dll. --- csharp/ql/integration-tests/posix-only/dotnet_test/test.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test/test.py b/csharp/ql/integration-tests/posix-only/dotnet_test/test.py index 7bc159e6720..1012454003b 100644 --- a/csharp/ql/integration-tests/posix-only/dotnet_test/test.py +++ b/csharp/ql/integration-tests/posix-only/dotnet_test/test.py @@ -1,5 +1,10 @@ from create_database_utils import * from diagnostics_test_utils import * -run_codeql_database_create(['dotnet test'], db=None, lang="csharp") +# Implicitly build and then run tests. +run_codeql_database_create(['dotnet test'], test_db="test-db", lang="csharp") check_diagnostics() + +# Explicitly build and then run tests. +run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout', 'dotnet test myout/dotnet_test.dll'], test_db="test2-db", lang="csharp") +check_diagnostics(test_db="test2-db") \ No newline at end of file From 4dae7ad35aa7c7a040142e56d081c1e4216eacea Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Tue, 6 Jun 2023 17:22:52 +0200 Subject: [PATCH 153/219] C#: Only inject the shared compilation flag, if argument is not exe or dll. --- csharp/tools/tracing-config.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 79b2ea2ca1c..7fa03af2de1 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -23,6 +23,7 @@ function RegisterExtractorPack(id) local match = false local dotnetRunNeedsSeparator = false; local dotnetRunInjectionIndex = nil; + local libOrExe = false; local argv = compilerArguments.argv if OperatingSystem == 'windows' then -- let's hope that this split matches the escaping rules `dotnet` applies to command line arguments @@ -37,7 +38,7 @@ function RegisterExtractorPack(id) if (not match) then Log(1, 'Dotnet subcommand detected: %s', arg) end - if arg == 'build' or arg == 'msbuild' or arg == 'publish' or arg == 'pack' or arg == 'test' then + if arg == 'build' or arg == 'msbuild' or arg == 'publish' or arg == 'pack' then match = true break end @@ -48,6 +49,14 @@ function RegisterExtractorPack(id) dotnetRunNeedsSeparator = true dotnetRunInjectionIndex = i + 1 end + if arg == 'test' then + match = true + end + -- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line + -- if a library or executable is being provided as an argument. + if arg:match('%.exe$') or arg:match('%.dll') then + libOrExe = true + end end -- if we see a separator to `dotnet run`, inject just prior to the existing separator if arg == '--' then @@ -62,7 +71,7 @@ function RegisterExtractorPack(id) dotnetRunInjectionIndex = i end end - if match then + if match and not libOrExe then local injections = { '-p:UseSharedCompilation=false', '-p:EmitCompilerGeneratedFiles=true' } if dotnetRunNeedsSeparator then table.insert(injections, '--') From 322b254cba0ae79516c17187f4b6fd0859de6490 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 6 Jun 2023 20:46:14 +0200 Subject: [PATCH 154/219] Type tracking: Use `noopt`+`inline_late` in `TypeBackTracker::[small]step` --- .../codeql/typetracking/TypeTracking.qll | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/shared/typetracking/codeql/typetracking/TypeTracking.qll b/shared/typetracking/codeql/typetracking/TypeTracking.qll index 6bfc31db5f3..5ab814e0ddd 100644 --- a/shared/typetracking/codeql/typetracking/TypeTracking.qll +++ b/shared/typetracking/codeql/typetracking/TypeTracking.qll @@ -630,6 +630,42 @@ module TypeTracking<TypeTrackingInput I> { TypeTracker end() { result.end() } } + pragma[nomagic] + private predicate backStepProj(LocalSourceNode nodeTo, StepSummary summary) { + step(_, nodeTo, summary) + } + + bindingset[t, nodeTo] + pragma[inline_late] + pragma[noopt] + private TypeBackTracker backStepInlineLate( + TypeBackTracker t, LocalSourceNode nodeFrom, LocalSourceNode nodeTo + ) { + exists(StepSummary summary | + backStepProj(nodeTo, summary) and + result = prepend(t, summary) and + step(nodeFrom, nodeTo, summary) + ) + } + + pragma[nomagic] + private predicate backSmallStepProj(LocalSourceNode nodeTo, StepSummary summary) { + smallStep(_, nodeTo, summary) + } + + bindingset[t, nodeTo] + pragma[inline_late] + pragma[noopt] + private TypeBackTracker backSmallStepInlineLate( + TypeBackTracker t, LocalSourceNode nodeFrom, LocalSourceNode nodeTo + ) { + exists(StepSummary summary | + backSmallStepProj(nodeTo, summary) and + result = prepend(t, summary) and + smallStep(nodeFrom, nodeTo, summary) + ) + } + /** * A summary of the steps needed to back-track a use of a value to a given dataflow node. * @@ -665,9 +701,6 @@ module TypeTracking<TypeTrackingInput I> { TypeBackTracker() { this = MkTypeBackTracker(hasReturn, content) } - /** Gets the summary resulting from prepending `step` to this type-tracking summary. */ - private TypeBackTracker prepend(StepSummary step) { result = prepend(this, step) } - /** Gets a textual representation of this summary. */ string toString() { exists(string withReturn, string withContent | @@ -704,13 +737,9 @@ module TypeTracking<TypeTrackingInput I> { * Gets the summary that corresponds to having taken a backwards * heap and/or inter-procedural step from `nodeTo` to `nodeFrom`. */ - bindingset[nodeTo, this] + pragma[inline] TypeBackTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) { - exists(StepSummary summary | - step(_, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and - result = pragma[only_bind_into](pragma[only_bind_out](this)).prepend(summary) and - step(nodeFrom, pragma[only_bind_into](pragma[only_bind_out](nodeTo)), summary) - ) + result = backStepInlineLate(this, nodeFrom, nodeTo) } /** @@ -737,13 +766,9 @@ module TypeTracking<TypeTrackingInput I> { * } * ``` */ - bindingset[nodeTo, this] + pragma[inline] TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallStep(_, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and - result = pragma[only_bind_into](pragma[only_bind_out](this)).prepend(summary) and - smallStep(nodeFrom, pragma[only_bind_into](pragma[only_bind_out](nodeTo)), summary) - ) + result = backSmallStepInlineLate(this, nodeFrom, nodeTo) or simpleLocalSmallStep(nodeFrom, nodeTo) and result = this From a14e7fa694b5f4e9746170cbc71b365e37ff5848 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 00:16:58 +0000 Subject: [PATCH 155/219] Add changed framework coverage reports --- java/documentation/library-coverage/coverage.csv | 4 ++-- java/documentation/library-coverage/coverage.rst | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 4e4b1ab7e1f..0e429b40b52 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -55,7 +55,7 @@ java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, java.io,44,,45,,22,,,,,,,,,,,,,,22,,,,,,,,,,,,,,,,,,,43,2 java.lang,18,,92,,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 java.net,13,3,20,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,20, -java.nio,38,,31,,3,,,,,,,,,,,,,,35,,,,,,,,,,,,,,,,,,,31, +java.nio,40,,35,,3,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,,35, java.sql,13,,3,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2,1 java.util,44,,484,,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,44,440 javafx.scene.web,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, @@ -75,7 +75,7 @@ javax.ws.rs.core,3,,149,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,2,,,,,,94,55 javax.xml.transform,2,,6,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,1,,,,6, javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,, jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 -kotlin,16,,1843,,,,,,,,,,,,,,,,14,,,,,,,,,2,,,,,,,,,,1836,7 +kotlin,16,,1847,,,,,,,,,,,,,,,,14,,,,,,,,,2,,,,,,,,,,1836,11 net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,, ognl,6,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, okhttp3,4,,47,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,22,25 diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index 644b4aaef6a..55b9a0a071d 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -18,10 +18,10 @@ Java framework & library support `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,41,7,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,, `JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,, - Java Standard Library,``java.*``,3,679,170,62,,9,,,17 + Java Standard Library,``java.*``,3,683,172,64,,9,,,17 Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 - Kotlin Standard Library,``kotlin*``,,1843,16,14,,,,,2 + Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,113,3,,28,14,,34 Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,890,520,60,,18,18,,193 - Totals,,255,9182,1973,242,10,122,33,1,382 + Totals,,255,9190,1975,244,10,122,33,1,382 From 2f12ae2e0d5e4d54d33cd4a723509096f3627770 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 08:57:12 +0200 Subject: [PATCH 156/219] Update java/ql/lib/ext/okhttp3.model.yml --- java/ql/lib/ext/okhttp3.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/ext/okhttp3.model.yml b/java/ql/lib/ext/okhttp3.model.yml index b7bfe8a10f7..a0662408708 100644 --- a/java/ql/lib/ext/okhttp3.model.yml +++ b/java/ql/lib/ext/okhttp3.model.yml @@ -58,4 +58,4 @@ extensions: - ["okhttp3", "HttpUrl$Builder", False, "setQueryParameter", "", "", "Argument[this]", "ReturnValue", "value", "manual"] - ["okhttp3", "HttpUrl$Builder", False, "setQueryParameter", "", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["okhttp3", "HttpUrl$Builder", False, "username", "", "", "Argument[this]", "ReturnValue", "value", "manual"] - - ["okhttp3", "Request$Builder", True, "build", "()", "", "Argument[undefined]", "ReturnValue", "taint", "ai-manual"] + - ["okhttp3", "Request$Builder", True, "build", "()", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"] From 4bf124bffe6b835519748107feb03e257f45afb2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 6 Jun 2023 15:40:04 +0200 Subject: [PATCH 157/219] Ruby/Python: Add `CallGraphConstruction` module for recursive type-tracking based call graph construction --- .../dataflow/new/internal/TypeTracker.qll | 345 ++++++++++++------ .../codeql/ruby/typetracking/TypeTracker.qll | 345 ++++++++++++------ 2 files changed, 454 insertions(+), 236 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll index 4be26f6cea9..25521f5f1a5 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll @@ -224,71 +224,47 @@ private module Cached { private import Cached +private predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { + stepNoCall(nodeFrom, nodeTo, summary) + or + stepCall(nodeFrom, nodeTo, summary) +} + pragma[nomagic] -private predicate stepNoCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { - stepNoCall(nodeFrom, _, summary) +private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) { + step(nodeFrom, _, summary) } bindingset[nodeFrom, t] pragma[inline_late] pragma[noopt] -private TypeTracker stepNoCallInlineLate( - TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { +private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { exists(StepSummary summary | - stepNoCallProj(nodeFrom, summary) and + stepProj(nodeFrom, summary) and result = t.append(summary) and - stepNoCall(nodeFrom, nodeTo, summary) + step(nodeFrom, nodeTo, summary) ) } +private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { + smallstepNoCall(nodeFrom, nodeTo, summary) + or + smallstepCall(nodeFrom, nodeTo, summary) +} + pragma[nomagic] -private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { - stepCall(nodeFrom, _, summary) +private predicate smallstepProj(Node nodeFrom, StepSummary summary) { + smallstep(nodeFrom, _, summary) } bindingset[nodeFrom, t] pragma[inline_late] pragma[noopt] -private TypeTracker stepCallInlineLate( - TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { +private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { exists(StepSummary summary | - stepCallProj(nodeFrom, summary) and + smallstepProj(nodeFrom, summary) and result = t.append(summary) and - stepCall(nodeFrom, nodeTo, summary) - ) -} - -pragma[nomagic] -private predicate smallstepNoCallProj(Node nodeFrom, StepSummary summary) { - smallstepNoCall(nodeFrom, _, summary) -} - -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepNoCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepNoCallProj(nodeFrom, summary) and - result = t.append(summary) and - smallstepNoCall(nodeFrom, nodeTo, summary) - ) -} - -pragma[nomagic] -private predicate smallstepCallProj(Node nodeFrom, StepSummary summary) { - smallstepCall(nodeFrom, _, summary) -} - -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepCallProj(nodeFrom, summary) and - result = t.append(summary) and - smallstepCall(nodeFrom, nodeTo, summary) + smallstep(nodeFrom, nodeTo, summary) ) } @@ -385,14 +361,7 @@ module StepSummary { /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate is inlined, which enables better join-orders when - * the call graph construction and type tracking are mutually recursive. - * In such cases, non-linear recursion involving `step` will be limited - * to non-linear recursion for the parts of `step` that involve the - * call graph. */ - pragma[inline] predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { stepNoCall(nodeFrom, nodeTo, summary) or @@ -424,7 +393,6 @@ module StepSummary { * Unlike `StepSummary::step`, this predicate does not compress * type-preserving steps. */ - pragma[inline] predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { smallstepNoCall(nodeFrom, nodeTo, summary) or @@ -529,66 +497,13 @@ class TypeTracker extends TTypeTracker { */ TypeTracker continue() { content = noContent() and result = this } - /** - * Gets the summary that corresponds to having taken a forwards - * intra-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker stepNoCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepNoCallInlineLate(this, nodeFrom, nodeTo) - } - - /** - * Gets the summary that corresponds to having taken a forwards - * inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker stepCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepCallInlineLate(this, nodeFrom, nodeTo) - } - /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ pragma[inline] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = this.stepNoCall(nodeFrom, nodeTo) - or - result = this.stepCall(nodeFrom, nodeTo) - } - - /** - * Gets the summary that corresponds to having taken a forwards - * intra-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker smallstepNoCall(Node nodeFrom, Node nodeTo) { - result = smallstepNoCallInlineLate(this, nodeFrom, nodeTo) - or - simpleLocalFlowStep(nodeFrom, nodeTo) and - result = this - } - - /** - * Gets the summary that corresponds to having taken a forwards - * inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker smallstepCall(Node nodeFrom, Node nodeTo) { - result = smallstepCallInlineLate(this, nodeFrom, nodeTo) + result = stepInlineLate(this, nodeFrom, nodeTo) } /** @@ -617,9 +532,10 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - result = this.smallstepNoCall(nodeFrom, nodeTo) + result = smallstepInlineLate(this, nodeFrom, nodeTo) or - result = this.smallstepCall(nodeFrom, nodeTo) + simpleLocalFlowStep(nodeFrom, nodeTo) and + result = this } } @@ -631,6 +547,39 @@ module TypeTracker { TypeTracker end() { result.end() } } +pragma[nomagic] +private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) { + step(_, nodeTo, summary) +} + +bindingset[nodeTo, t] +pragma[inline_late] +pragma[noopt] +private TypeBackTracker backStepInlineLate( + TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + backStepProj(nodeTo, summary) and + result = t.prepend(summary) and + step(nodeFrom, nodeTo, summary) + ) +} + +private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) { + smallstep(_, nodeTo, summary) +} + +bindingset[nodeTo, t] +pragma[inline_late] +pragma[noopt] +private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + backSmallstepProj(nodeTo, summary) and + result = t.prepend(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) +} + /** * A summary of the steps needed to back-track a use of a value to a given dataflow node. * @@ -714,10 +663,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and - this = result.prepend(pragma[only_bind_into](summary)) - ) + this = backStepInlineLate(result, nodeFrom, nodeTo) } /** @@ -746,10 +692,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - StepSummary::smallstep(nodeFrom, nodeTo, summary) and - this = result.prepend(summary) - ) + this = backSmallstepInlineLate(result, nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and this = result @@ -785,3 +728,169 @@ module TypeBackTracker { */ TypeBackTracker end() { result.end() } } + +/** + * INTERNAL: Do not use. + * + * Provides logic for constructing a call graph in mutual recursion with type tracking. + * + * When type tracking is used to construct a call graph, we cannot use the join-order + * from `stepInlineLate`, because `step` becomes a recursive call, which means that we + * will have a conjunct with 3 recursive calls: the call to `step`, the call to `stepProj`, + * and the recursive type tracking call itself. The solution is to split the three-way + * non-linear recursion into two non-linear predicates: one that first joins with the + * projected `stepCall` relation, followed by a predicate that joins with the full + * `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the + * same way as in `stepInlineLate`). + */ +module CallGraphConstruction { + /** The input to call graph construction. */ + signature module InputSig { + /** A state to track during type tracking. */ + class State; + + /** Holds if type tracking should start at `start` in state `state`. */ + predicate start(Node start, State state); + + /** + * Holds if type tracking should use the step from `nodeFrom` to `nodeTo`, + * which _does not_ depend on the call graph. + * + * Implementing this predicate using `StepSummary::[small]stepNoCall` yields + * standard type tracking. + */ + predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary); + + /** + * Holds if type tracking should use the step from `nodeFrom` to `nodeTo`, + * which _does_ depend on the call graph. + * + * Implementing this predicate using `StepSummary::[small]stepCall` yields + * standard type tracking. + */ + predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary); + + /** A projection of an element from the state space. */ + class StateProj; + + /** Gets the projection of `state`. */ + StateProj stateProj(State state); + + /** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */ + predicate filter(Node n, StateProj stateProj); + } + + /** Provides the `track` predicate for use in call graph construction. */ + module Make<InputSig Input> { + pragma[nomagic] + private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) { + Input::stepNoCall(nodeFrom, _, summary) + } + + pragma[nomagic] + private predicate stepCallProj(Node nodeFrom, StepSummary summary) { + Input::stepCall(nodeFrom, _, summary) + } + + bindingset[nodeFrom, t] + pragma[inline_late] + pragma[noopt] + private TypeTracker stepNoCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo + ) { + exists(StepSummary summary | + stepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + Input::stepNoCall(nodeFrom, nodeTo, summary) + ) + } + + bindingset[state] + pragma[inline_late] + private Input::StateProj stateProjInlineLate(Input::State state) { + result = Input::stateProj(state) + } + + pragma[nomagic] + private Node track(Input::State state, TypeTracker t) { + t.start() and Input::start(result, state) + or + exists(Input::StateProj stateProj | + stateProj = stateProjInlineLate(state) and + not Input::filter(result, stateProj) + | + exists(TypeTracker t2 | t = stepNoCallInlineLate(t2, track(state, t2), result)) + or + exists(StepSummary summary | + // non-linear recursion + Input::stepCall(trackCall(state, t, summary), result, summary) + ) + ) + } + + bindingset[t, summary] + pragma[inline_late] + private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) { + result = t.append(summary) + } + + pragma[nomagic] + private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = track(state, t2) and + stepCallProj(result, summary) and + t = appendInlineLate(t2, summary) + ) + } + + /** Gets a node that can be reached from _some_ start node in state `state`. */ + pragma[nomagic] + Node track(Input::State state) { result = track(state, TypeTracker::end()) } + } + + /** A simple version of `CallGraphConstruction` that uses standard type tracking. */ + module Simple { + /** The input to call graph construction. */ + signature module InputSig { + /** A state to track during type tracking. */ + class State; + + /** Holds if type tracking should start at `start` in state `state`. */ + predicate start(Node start, State state); + + /** Holds if type tracking should stop at `n`. */ + predicate filter(Node n); + } + + /** Provides the `track` predicate for use in call graph construction. */ + module Make<InputSig Input> { + private module I implements CallGraphConstruction::InputSig { + private import codeql.util.Unit + + class State = Input::State; + + predicate start(Node start, State state) { Input::start(start, state) } + + predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary) { + StepSummary::stepNoCall(nodeFrom, nodeTo, summary) + } + + predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary) { + StepSummary::stepCall(nodeFrom, nodeTo, summary) + } + + class StateProj = Unit; + + Unit stateProj(State state) { exists(state) and exists(result) } + + predicate filter(Node n, Unit u) { + Input::filter(n) and + exists(u) + } + } + + import CallGraphConstruction::Make<I> + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll index 4be26f6cea9..25521f5f1a5 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll @@ -224,71 +224,47 @@ private module Cached { private import Cached +private predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { + stepNoCall(nodeFrom, nodeTo, summary) + or + stepCall(nodeFrom, nodeTo, summary) +} + pragma[nomagic] -private predicate stepNoCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { - stepNoCall(nodeFrom, _, summary) +private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) { + step(nodeFrom, _, summary) } bindingset[nodeFrom, t] pragma[inline_late] pragma[noopt] -private TypeTracker stepNoCallInlineLate( - TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { +private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { exists(StepSummary summary | - stepNoCallProj(nodeFrom, summary) and + stepProj(nodeFrom, summary) and result = t.append(summary) and - stepNoCall(nodeFrom, nodeTo, summary) + step(nodeFrom, nodeTo, summary) ) } +private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { + smallstepNoCall(nodeFrom, nodeTo, summary) + or + smallstepCall(nodeFrom, nodeTo, summary) +} + pragma[nomagic] -private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { - stepCall(nodeFrom, _, summary) +private predicate smallstepProj(Node nodeFrom, StepSummary summary) { + smallstep(nodeFrom, _, summary) } bindingset[nodeFrom, t] pragma[inline_late] pragma[noopt] -private TypeTracker stepCallInlineLate( - TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { +private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { exists(StepSummary summary | - stepCallProj(nodeFrom, summary) and + smallstepProj(nodeFrom, summary) and result = t.append(summary) and - stepCall(nodeFrom, nodeTo, summary) - ) -} - -pragma[nomagic] -private predicate smallstepNoCallProj(Node nodeFrom, StepSummary summary) { - smallstepNoCall(nodeFrom, _, summary) -} - -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepNoCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepNoCallProj(nodeFrom, summary) and - result = t.append(summary) and - smallstepNoCall(nodeFrom, nodeTo, summary) - ) -} - -pragma[nomagic] -private predicate smallstepCallProj(Node nodeFrom, StepSummary summary) { - smallstepCall(nodeFrom, _, summary) -} - -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepCallInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepCallProj(nodeFrom, summary) and - result = t.append(summary) and - smallstepCall(nodeFrom, nodeTo, summary) + smallstep(nodeFrom, nodeTo, summary) ) } @@ -385,14 +361,7 @@ module StepSummary { /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate is inlined, which enables better join-orders when - * the call graph construction and type tracking are mutually recursive. - * In such cases, non-linear recursion involving `step` will be limited - * to non-linear recursion for the parts of `step` that involve the - * call graph. */ - pragma[inline] predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { stepNoCall(nodeFrom, nodeTo, summary) or @@ -424,7 +393,6 @@ module StepSummary { * Unlike `StepSummary::step`, this predicate does not compress * type-preserving steps. */ - pragma[inline] predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { smallstepNoCall(nodeFrom, nodeTo, summary) or @@ -529,66 +497,13 @@ class TypeTracker extends TTypeTracker { */ TypeTracker continue() { content = noContent() and result = this } - /** - * Gets the summary that corresponds to having taken a forwards - * intra-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker stepNoCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepNoCallInlineLate(this, nodeFrom, nodeTo) - } - - /** - * Gets the summary that corresponds to having taken a forwards - * inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker stepCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepCallInlineLate(this, nodeFrom, nodeTo) - } - /** * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ pragma[inline] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = this.stepNoCall(nodeFrom, nodeTo) - or - result = this.stepCall(nodeFrom, nodeTo) - } - - /** - * Gets the summary that corresponds to having taken a forwards - * intra-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker smallstepNoCall(Node nodeFrom, Node nodeTo) { - result = smallstepNoCallInlineLate(this, nodeFrom, nodeTo) - or - simpleLocalFlowStep(nodeFrom, nodeTo) and - result = this - } - - /** - * Gets the summary that corresponds to having taken a forwards - * inter-procedural step from `nodeFrom` to `nodeTo`. - * - * This predicate should normally not be used; consider using `step` - * instead. - */ - pragma[inline] - TypeTracker smallstepCall(Node nodeFrom, Node nodeTo) { - result = smallstepCallInlineLate(this, nodeFrom, nodeTo) + result = stepInlineLate(this, nodeFrom, nodeTo) } /** @@ -617,9 +532,10 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - result = this.smallstepNoCall(nodeFrom, nodeTo) + result = smallstepInlineLate(this, nodeFrom, nodeTo) or - result = this.smallstepCall(nodeFrom, nodeTo) + simpleLocalFlowStep(nodeFrom, nodeTo) and + result = this } } @@ -631,6 +547,39 @@ module TypeTracker { TypeTracker end() { result.end() } } +pragma[nomagic] +private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) { + step(_, nodeTo, summary) +} + +bindingset[nodeTo, t] +pragma[inline_late] +pragma[noopt] +private TypeBackTracker backStepInlineLate( + TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo +) { + exists(StepSummary summary | + backStepProj(nodeTo, summary) and + result = t.prepend(summary) and + step(nodeFrom, nodeTo, summary) + ) +} + +private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) { + smallstep(_, nodeTo, summary) +} + +bindingset[nodeTo, t] +pragma[inline_late] +pragma[noopt] +private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + backSmallstepProj(nodeTo, summary) and + result = t.prepend(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) +} + /** * A summary of the steps needed to back-track a use of a value to a given dataflow node. * @@ -714,10 +663,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and - this = result.prepend(pragma[only_bind_into](summary)) - ) + this = backStepInlineLate(result, nodeFrom, nodeTo) } /** @@ -746,10 +692,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - StepSummary::smallstep(nodeFrom, nodeTo, summary) and - this = result.prepend(summary) - ) + this = backSmallstepInlineLate(result, nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and this = result @@ -785,3 +728,169 @@ module TypeBackTracker { */ TypeBackTracker end() { result.end() } } + +/** + * INTERNAL: Do not use. + * + * Provides logic for constructing a call graph in mutual recursion with type tracking. + * + * When type tracking is used to construct a call graph, we cannot use the join-order + * from `stepInlineLate`, because `step` becomes a recursive call, which means that we + * will have a conjunct with 3 recursive calls: the call to `step`, the call to `stepProj`, + * and the recursive type tracking call itself. The solution is to split the three-way + * non-linear recursion into two non-linear predicates: one that first joins with the + * projected `stepCall` relation, followed by a predicate that joins with the full + * `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the + * same way as in `stepInlineLate`). + */ +module CallGraphConstruction { + /** The input to call graph construction. */ + signature module InputSig { + /** A state to track during type tracking. */ + class State; + + /** Holds if type tracking should start at `start` in state `state`. */ + predicate start(Node start, State state); + + /** + * Holds if type tracking should use the step from `nodeFrom` to `nodeTo`, + * which _does not_ depend on the call graph. + * + * Implementing this predicate using `StepSummary::[small]stepNoCall` yields + * standard type tracking. + */ + predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary); + + /** + * Holds if type tracking should use the step from `nodeFrom` to `nodeTo`, + * which _does_ depend on the call graph. + * + * Implementing this predicate using `StepSummary::[small]stepCall` yields + * standard type tracking. + */ + predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary); + + /** A projection of an element from the state space. */ + class StateProj; + + /** Gets the projection of `state`. */ + StateProj stateProj(State state); + + /** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */ + predicate filter(Node n, StateProj stateProj); + } + + /** Provides the `track` predicate for use in call graph construction. */ + module Make<InputSig Input> { + pragma[nomagic] + private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) { + Input::stepNoCall(nodeFrom, _, summary) + } + + pragma[nomagic] + private predicate stepCallProj(Node nodeFrom, StepSummary summary) { + Input::stepCall(nodeFrom, _, summary) + } + + bindingset[nodeFrom, t] + pragma[inline_late] + pragma[noopt] + private TypeTracker stepNoCallInlineLate( + TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo + ) { + exists(StepSummary summary | + stepNoCallProj(nodeFrom, summary) and + result = t.append(summary) and + Input::stepNoCall(nodeFrom, nodeTo, summary) + ) + } + + bindingset[state] + pragma[inline_late] + private Input::StateProj stateProjInlineLate(Input::State state) { + result = Input::stateProj(state) + } + + pragma[nomagic] + private Node track(Input::State state, TypeTracker t) { + t.start() and Input::start(result, state) + or + exists(Input::StateProj stateProj | + stateProj = stateProjInlineLate(state) and + not Input::filter(result, stateProj) + | + exists(TypeTracker t2 | t = stepNoCallInlineLate(t2, track(state, t2), result)) + or + exists(StepSummary summary | + // non-linear recursion + Input::stepCall(trackCall(state, t, summary), result, summary) + ) + ) + } + + bindingset[t, summary] + pragma[inline_late] + private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) { + result = t.append(summary) + } + + pragma[nomagic] + private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) { + exists(TypeTracker t2 | + // non-linear recursion + result = track(state, t2) and + stepCallProj(result, summary) and + t = appendInlineLate(t2, summary) + ) + } + + /** Gets a node that can be reached from _some_ start node in state `state`. */ + pragma[nomagic] + Node track(Input::State state) { result = track(state, TypeTracker::end()) } + } + + /** A simple version of `CallGraphConstruction` that uses standard type tracking. */ + module Simple { + /** The input to call graph construction. */ + signature module InputSig { + /** A state to track during type tracking. */ + class State; + + /** Holds if type tracking should start at `start` in state `state`. */ + predicate start(Node start, State state); + + /** Holds if type tracking should stop at `n`. */ + predicate filter(Node n); + } + + /** Provides the `track` predicate for use in call graph construction. */ + module Make<InputSig Input> { + private module I implements CallGraphConstruction::InputSig { + private import codeql.util.Unit + + class State = Input::State; + + predicate start(Node start, State state) { Input::start(start, state) } + + predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary) { + StepSummary::stepNoCall(nodeFrom, nodeTo, summary) + } + + predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary) { + StepSummary::stepCall(nodeFrom, nodeTo, summary) + } + + class StateProj = Unit; + + Unit stateProj(State state) { exists(state) and exists(result) } + + predicate filter(Node n, Unit u) { + Input::filter(n) and + exists(u) + } + } + + import CallGraphConstruction::Make<I> + } + } +} From 88c5700c2452aa1208ae321e4d25b8aa4e3be948 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 6 Jun 2023 15:41:11 +0200 Subject: [PATCH 158/219] Ruby: Use `CallGraphConstruction` in call graph construction --- .../dataflow/internal/DataFlowDispatch.qll | 557 ++++++++---------- 1 file changed, 238 insertions(+), 319 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll index 410867c7ead..625cc226b96 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll @@ -8,6 +8,8 @@ private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImplSpecific as FlowSummaryImplSpecific private import codeql.ruby.dataflow.FlowSummary private import codeql.ruby.dataflow.SSA +private import codeql.util.Boolean +private import codeql.util.Unit /** * A `LocalSourceNode` for a `self` variable. This is the implicit `self` @@ -470,49 +472,22 @@ private module Cached { import Cached -pragma[nomagic] -private predicate stepCallProj(DataFlow::LocalSourceNode nodeFrom, StepSummary summary) { - StepSummary::stepCall(nodeFrom, _, summary) -} - pragma[nomagic] private predicate isNotSelf(DataFlow::Node n) { not n instanceof SelfParameterNodeImpl } -pragma[nomagic] -private DataFlow::LocalSourceNode trackModuleAccess(Module m, TypeTracker t) { - t.start() and m = resolveConstantReadAccess(result.asExpr().getExpr()) - or +private module TrackModuleInput implements CallGraphConstruction::Simple::InputSig { + class State = Module; + + predicate start(DataFlow::Node start, Module m) { + m = resolveConstantReadAccess(start.asExpr().getExpr()) + } + // We exclude steps into `self` parameters, and instead rely on the type of the // enclosing module - isNotSelf(result) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(trackModuleAccess(m, t2), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(trackModuleAccessCall(m, t, summary), result, summary) - ) - ) + predicate filter(DataFlow::Node n) { n instanceof SelfParameterNodeImpl } } -bindingset[t, summary] -pragma[inline_late] -private TypeTracker append(TypeTracker t, StepSummary summary) { result = t.append(summary) } - -pragma[nomagic] -private DataFlow::LocalSourceNode trackModuleAccessCall(Module m, TypeTracker t, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = trackModuleAccess(m, t2) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) -} - -pragma[nomagic] -private DataFlow::LocalSourceNode trackModuleAccess(Module m) { - result = trackModuleAccess(m, TypeTracker::end()) -} +predicate trackModuleAccess = CallGraphConstruction::Simple::Make<TrackModuleInput>::track/1; pragma[nomagic] private predicate hasUserDefinedNew(Module m) { @@ -552,182 +527,162 @@ private predicate isStandardNewCall(RelevantCall new, Module m, boolean exact) { ) } -/** Holds if `n` is an instance of type `tp`. */ -private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) { - n.asExpr().getExpr() instanceof NilLiteral and - tp = TResolved("NilClass") and - exact = true - or - n.asExpr().getExpr().(BooleanLiteral).isFalse() and - tp = TResolved("FalseClass") and - exact = true - or - n.asExpr().getExpr().(BooleanLiteral).isTrue() and - tp = TResolved("TrueClass") and - exact = true - or - n.asExpr().getExpr() instanceof IntegerLiteral and - tp = TResolved("Integer") and - exact = true - or - n.asExpr().getExpr() instanceof FloatLiteral and - tp = TResolved("Float") and - exact = true - or - n.asExpr().getExpr() instanceof RationalLiteral and - tp = TResolved("Rational") and - exact = true - or - n.asExpr().getExpr() instanceof ComplexLiteral and - tp = TResolved("Complex") and - exact = true - or - n.asExpr().getExpr() instanceof StringlikeLiteral and - tp = TResolved("String") and - exact = true - or - n.asExpr() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode and - tp = TResolved("Array") and - exact = true - or - n.asExpr() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode and - tp = TResolved("Hash") and - exact = true - or - n.asExpr().getExpr() instanceof MethodBase and - tp = TResolved("Symbol") and - exact = true - or - n.asParameter() instanceof BlockParameter and - tp = TResolved("Proc") and - exact = true - or - n.asExpr().getExpr() instanceof Lambda and - tp = TResolved("Proc") and - exact = true - or - isStandardNewCall(n.asExpr(), tp, exact) - or - // `self` reference in method or top-level (but not in module or singleton method, - // where instance methods cannot be called; only singleton methods) - n = - any(SelfLocalSourceNode self | - exists(MethodBase m | - selfInMethod(self.getVariable(), m, tp) and - not m instanceof SingletonMethod and - if m.getEnclosingModule() instanceof Toplevel then exact = true else exact = false - ) - or - selfInToplevel(self.getVariable(), tp) and - exact = true - ) - or - // `in C => c then c.foo` - asModulePattern(n, tp) and - exact = false - or - // `case object when C then object.foo` - hasAdjacentTypeCheckedReads(_, _, n.asExpr(), tp) and - exact = false -} - private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { localFlowStepTypeTracker(nodeFrom, nodeTo) and summary.toString() = "level" } -pragma[nomagic] -private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) { - hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _) -} - -pragma[nomagic] -private predicate smallStepNoCallForTrackInstance0( - DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary -) { - // We exclude steps into `self` parameters. For those, we instead rely on the type of - // the enclosing module - StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and - isNotSelf(nodeTo) - or - // We exclude steps into type checked variables. For those, we instead rely on the - // type being checked against - localFlowStep(nodeFrom, nodeTo, summary) and - not hasAdjacentTypeCheckedReads(nodeTo) -} - -pragma[nomagic] -private predicate smallStepNoCallForTrackInstance0Proj(DataFlow::Node nodeFrom, StepSummary summary) { - smallStepNoCallForTrackInstance0(nodeFrom, _, summary) -} - -bindingset[t, nodeFrom] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallStepNoCallForTrackInstance( - TypeTracker t, DataFlow::Node nodeFrom, DataFlow::Node nodeTo -) { - exists(StepSummary summary | - smallStepNoCallForTrackInstance0Proj(nodeFrom, summary) and - result = t.append(summary) and - smallStepNoCallForTrackInstance0(nodeFrom, nodeTo, summary) - ) -} - -pragma[nomagic] -private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) { - t.start() and - ( - isInstance(result, tp, exact) +private module TrackInstanceInput implements CallGraphConstruction::InputSig { + pragma[nomagic] + private predicate isInstanceNoCall(DataFlow::Node n, Module tp, boolean exact) { + n.asExpr().getExpr() instanceof NilLiteral and + tp = TResolved("NilClass") and + exact = true or - exists(Module m | - (if m.isClass() then tp = TResolved("Class") else tp = TResolved("Module")) and - exact = true - | - // needed for e.g. `C.new` - m = resolveConstantReadAccess(result.asExpr().getExpr()) + n.asExpr().getExpr().(BooleanLiteral).isFalse() and + tp = TResolved("FalseClass") and + exact = true + or + n.asExpr().getExpr().(BooleanLiteral).isTrue() and + tp = TResolved("TrueClass") and + exact = true + or + n.asExpr().getExpr() instanceof IntegerLiteral and + tp = TResolved("Integer") and + exact = true + or + n.asExpr().getExpr() instanceof FloatLiteral and + tp = TResolved("Float") and + exact = true + or + n.asExpr().getExpr() instanceof RationalLiteral and + tp = TResolved("Rational") and + exact = true + or + n.asExpr().getExpr() instanceof ComplexLiteral and + tp = TResolved("Complex") and + exact = true + or + n.asExpr().getExpr() instanceof StringlikeLiteral and + tp = TResolved("String") and + exact = true + or + n.asExpr() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode and + tp = TResolved("Array") and + exact = true + or + n.asExpr() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode and + tp = TResolved("Hash") and + exact = true + or + n.asExpr().getExpr() instanceof MethodBase and + tp = TResolved("Symbol") and + exact = true + or + n.asParameter() instanceof BlockParameter and + tp = TResolved("Proc") and + exact = true + or + n.asExpr().getExpr() instanceof Lambda and + tp = TResolved("Proc") and + exact = true + or + // `self` reference in method or top-level (but not in module or singleton method, + // where instance methods cannot be called; only singleton methods) + n = + any(SelfLocalSourceNode self | + exists(MethodBase m | + selfInMethod(self.getVariable(), m, tp) and + not m instanceof SingletonMethod and + if m.getEnclosingModule() instanceof Toplevel then exact = true else exact = false + ) + or + selfInToplevel(self.getVariable(), tp) and + exact = true + ) + or + // `in C => c then c.foo` + asModulePattern(n, tp) and + exact = false + or + // `case object when C then object.foo` + hasAdjacentTypeCheckedReads(_, _, n.asExpr(), tp) and + exact = false + } + + pragma[nomagic] + private predicate isInstanceCall(DataFlow::Node n, Module tp, boolean exact) { + isStandardNewCall(n.asExpr(), tp, exact) + } + + /** Holds if `n` is an instance of type `tp`. */ + pragma[inline] + private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) { + isInstanceNoCall(n, tp, exact) + or + isInstanceCall(n, tp, exact) + } + + pragma[nomagic] + private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) { + hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _) + } + + newtype State = additional MkState(Module m, Boolean exact) + + predicate start(DataFlow::Node start, State state) { + exists(Module tp, boolean exact | state = MkState(tp, exact) | + isInstance(start, tp, exact) or - // needed for e.g. `self.include` - selfInModule(result.(SelfLocalSourceNode).getVariable(), m) - or - // needed for e.g. `self.puts` - selfInMethod(result.(SelfLocalSourceNode).getVariable(), any(SingletonMethod sm), m) + exists(Module m | + (if m.isClass() then tp = TResolved("Class") else tp = TResolved("Module")) and + exact = true + | + // needed for e.g. `C.new` + m = resolveConstantReadAccess(start.asExpr().getExpr()) + or + // needed for e.g. `self.include` + selfInModule(start.(SelfLocalSourceNode).getVariable(), m) + or + // needed for e.g. `self.puts` + selfInMethod(start.(SelfLocalSourceNode).getVariable(), any(SingletonMethod sm), m) + ) ) - ) - or - exists(TypeTracker t2 | - t = smallStepNoCallForTrackInstance(t2, trackInstance(tp, exact, t2), result) - ) - or - // We exclude steps into `self` parameters. For those, we instead rely on the type of - // the enclosing module - exists(StepSummary summary | - // non-linear recursion - StepSummary::smallstepCall(trackInstanceCall(tp, t, exact, summary), result, summary) and - isNotSelf(result) - ) -} + } -pragma[nomagic] -private predicate smallStepCallProj(DataFlow::Node nodeFrom, StepSummary summary) { - StepSummary::smallstepCall(nodeFrom, _, summary) -} + pragma[nomagic] + predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { + // We exclude steps into `self` parameters. For those, we instead rely on the type of + // the enclosing module + StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and + isNotSelf(nodeTo) + or + // We exclude steps into type checked variables. For those, we instead rely on the + // type being checked against + localFlowStep(nodeFrom, nodeTo, summary) and + not hasAdjacentTypeCheckedReads(nodeTo) + } -pragma[nomagic] -private DataFlow::Node trackInstanceCall( - Module tp, TypeTracker t, boolean exact, StepSummary summary -) { - exists(TypeTracker t2 | - // non-linear recursion - result = trackInstance(tp, exact, t2) and - smallStepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { + StepSummary::smallstepCall(nodeFrom, nodeTo, summary) + } + + class StateProj = Unit; + + Unit stateProj(State state) { exists(state) and exists(result) } + + // We exclude steps into `self` parameters, and instead rely on the type of the + // enclosing module + predicate filter(DataFlow::Node n, Unit u) { + n instanceof SelfParameterNodeImpl and + exists(u) + } } pragma[nomagic] private DataFlow::Node trackInstance(Module tp, boolean exact) { - result = trackInstance(tp, exact, TypeTracker::end()) + result = + CallGraphConstruction::Make<TrackInstanceInput>::track(TrackInstanceInput::MkState(tp, exact)) } pragma[nomagic] @@ -768,37 +723,17 @@ private CfgScope getTargetInstance(RelevantCall call, string method) { ) } -pragma[nomagic] -private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) { - t.start() and result.asExpr().getExpr() = block - or - // We exclude steps into `self` parameters, which may happen when the code - // base contains implementations of `call`. - isNotSelf(result) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(trackBlock(block, t2), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(trackBlockCall(block, t, summary), result, summary) - ) - ) +private module TrackBlockInput implements CallGraphConstruction::Simple::InputSig { + class State = Block; + + predicate start(DataFlow::Node start, Block block) { start.asExpr().getExpr() = block } + + // We exclude steps into `self` parameters, and instead rely on the type of the + // enclosing module + predicate filter(DataFlow::Node n) { n instanceof SelfParameterNodeImpl } } -pragma[nomagic] -private DataFlow::LocalSourceNode trackBlockCall(Block block, TypeTracker t, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = trackBlock(block, t2) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) -} - -pragma[nomagic] -private DataFlow::LocalSourceNode trackBlock(Block block) { - result = trackBlock(block, TypeTracker::end()) -} +private predicate trackBlock = CallGraphConstruction::Simple::Make<TrackBlockInput>::track/1; /** Holds if `m` is a singleton method named `name`, defined on `object. */ private predicate singletonMethod(MethodBase m, string name, Expr object) { @@ -965,72 +900,81 @@ predicate singletonMethodOnInstance(MethodBase method, string name, Expr object) ) } -/** - * Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter. - * - * This is only used for tracking singleton methods, where we want to be able - * to handle cases like - * - * ```rb - * def add_singleton x - * def x.foo; end - * end - * - * y = add_singleton C.new - * y.foo - * ``` - * - * and - * - * ```rb - * class C - * def add_singleton_to_self - * def self.foo; end - * end - * end - * - * y = C.new - * y.add_singleton_to_self - * y.foo - * ``` - */ -pragma[nomagic] -private predicate paramReturnFlow( - DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary -) { - exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr | - TypeTrackerSpecific::callStep(call, arg, p) and - nodeTo.getPreUpdateNode() = arg and - summary.toString() = "return" and - ( - nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() +private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruction::InputSig { + /** + * Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter. + * + * This is only used for tracking singleton methods, where we want to be able + * to handle cases like + * + * ```rb + * def add_singleton x + * def x.foo; end + * end + * + * y = add_singleton C.new + * y.foo + * ``` + * + * and + * + * ```rb + * class C + * def add_singleton_to_self + * def self.foo; end + * end + * end + * + * y = C.new + * y.add_singleton_to_self + * y.foo + * ``` + */ + pragma[nomagic] + private predicate paramReturnFlow( + DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary + ) { + exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr | + TypeTrackerSpecific::callStep(call, arg, p) and + nodeTo.getPreUpdateNode() = arg and + summary.toString() = "return" and + ( + nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() + or + nodeFromPreExpr = nodeFrom.asExpr().getExpr() and + singletonMethodOnInstance(_, _, nodeFromPreExpr) + ) + | + nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess() or - nodeFromPreExpr = nodeFrom.asExpr().getExpr() and - singletonMethodOnInstance(_, _, nodeFromPreExpr) + nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfVariable().getAnAccess() ) - | - nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess() - or - nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfVariable().getAnAccess() - ) -} + } -pragma[nomagic] -private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string name, TypeTracker t) { - t.start() and - singletonMethodOnInstance(method, name, result.asExpr().getExpr()) - or - ( - exists(TypeTracker t2 | - t = t2.smallstepNoCall(trackSingletonMethodOnInstance(method, name, t2), result) - ) + class State = MethodBase; + + predicate start(DataFlow::Node start, MethodBase method) { + singletonMethodOnInstance(method, _, start.asExpr().getExpr()) + } + + predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { + StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) or - exists(StepSummary summary | - // non-linear recursion - smallStepCallForTrackSingletonMethodOnInstance(trackSingletonMethodOnInstanceCall(method, - name, t, summary), result, summary) - ) - ) and + localFlowStep(nodeFrom, nodeTo, summary) + } + + predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) { + StepSummary::smallstepCall(nodeFrom, nodeTo, summary) + or + paramReturnFlow(nodeFrom, nodeTo, summary) + } + + class StateProj extends string { + StateProj() { singletonMethodOnInstance(_, this, _) } + } + + StateProj stateProj(MethodBase method) { singletonMethodOnInstance(method, result, _) } + // Stop flow at redefinitions. // // Example: @@ -1039,40 +983,15 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string // def x.foo; end // x.foo # <- we want to resolve this call to the second definition only // ``` - not singletonMethodOnInstance(_, name, result.asExpr().getExpr()) -} - -pragma[nomagic] -private predicate smallStepCallForTrackSingletonMethodOnInstance( - DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary -) { - StepSummary::smallstepCall(nodeFrom, nodeTo, summary) - or - paramReturnFlow(nodeFrom, nodeTo, summary) -} - -pragma[nomagic] -private predicate smallStepCallForTrackSingletonMethodOnInstanceProj( - DataFlow::Node nodeFrom, StepSummary summary -) { - smallStepCallForTrackSingletonMethodOnInstance(nodeFrom, _, summary) -} - -pragma[nomagic] -private DataFlow::Node trackSingletonMethodOnInstanceCall( - MethodBase method, string name, TypeTracker t, StepSummary summary -) { - exists(TypeTracker t2 | - // non-linear recursion - result = trackSingletonMethodOnInstance(method, name, t2) and - smallStepCallForTrackSingletonMethodOnInstanceProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(DataFlow::Node n, StateProj name) { + singletonMethodOnInstance(_, name, n.asExpr().getExpr()) + } } pragma[nomagic] private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string name) { - result = trackSingletonMethodOnInstance(method, name, TypeTracker::end()) + result = CallGraphConstruction::Make<TrackSingletonMethodOnInstanceInput>::track(method) and + singletonMethodOnInstance(method, name, _) } /** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */ From 48ac3e58ee6bb7fdb26c079da1c413ab5c58fc2b Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 6 Jun 2023 16:09:10 +0200 Subject: [PATCH 159/219] Python: Use `CallGraphConstruction` in call graph construction --- .../new/internal/DataFlowDispatch.qll | 425 ++++++------------ 1 file changed, 144 insertions(+), 281 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 958bca246cb..895ef74b41e 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -38,6 +38,7 @@ private import DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImplSpecific as FlowSummaryImplSpecific private import semmle.python.internal.CachedStages +private import semmle.python.dataflow.new.internal.TypeTracker::CallGraphConstruction as CallGraphConstruction newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ @@ -464,189 +465,105 @@ private predicate ignoreForCallGraph(File f) { f.getAbsolutePath().matches("%/site-packages/sympy/%") } -bindingset[n] -pragma[inline_late] -private predicate includeInCallGraph(TypeTrackingNode n) { - not ignoreForCallGraph(n.getLocation().getFile()) -} +private module TrackFunctionInput implements CallGraphConstruction::Simple::InputSig { + class State = Function; -pragma[nomagic] -private predicate stepCallProj(TypeTrackingNode nodeFrom, StepSummary summary) { - StepSummary::stepCall(nodeFrom, _, summary) -} - -bindingset[t, summary] -pragma[inline_late] -private TypeTracker append(TypeTracker t, StepSummary summary) { result = t.append(summary) } - -/** - * Gets a reference to the function `func`. - */ -private TypeTrackingNode functionTracker(TypeTracker t, Function func) { - includeInCallGraph(result) and - ( - t.start() and - ( - result.asExpr() = func.getDefinition() - or - // when a function is decorated, it's the result of the (last) decorator call that - // is used - result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() - ) + predicate start(Node start, Function func) { + start.asExpr() = func.getDefinition() or - ( - exists(TypeTracker t2 | t = t2.stepNoCall(functionTracker(t2, func), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(functionTrackerCall(t, func, summary), result, summary) - ) - ) - ) -} + // when a function is decorated, it's the result of the (last) decorator call that + // is used + start.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() + } -pragma[nomagic] -private TypeTrackingNode functionTrackerCall(TypeTracker t, Function func, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = functionTracker(t2, func) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { ignoreForCallGraph(n.getLocation().getFile()) } } /** * Gets a reference to the function `func`. */ -Node functionTracker(Function func) { functionTracker(TypeTracker::end(), func).flowsTo(result) } +Node functionTracker(Function func) { + CallGraphConstruction::Simple::Make<TrackFunctionInput>::track(func) + .(LocalSourceNode) + .flowsTo(result) +} -/** - * Gets a reference to the class `cls`. - */ -private TypeTrackingNode classTracker(TypeTracker t, Class cls) { - includeInCallGraph(result) and - ( - t.start() and - ( - result.asExpr() = cls.getParent() - or - // when a class is decorated, it's the result of the (last) decorator call that - // is used - result.asExpr() = cls.getParent().getADecoratorCall() - or - // `type(obj)`, where obj is an instance of this class - result = getTypeCall() and - result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) - ) +private module TrackClassInput implements CallGraphConstruction::Simple::InputSig { + class State = Class; + + predicate start(Node start, Class cls) { + start.asExpr() = cls.getParent() or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(classTracker(t2, cls), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(classTrackerCall(t, cls, summary), result, summary) - ) - ) - ) -} + // when a class is decorated, it's the result of the (last) decorator call that + // is used + start.asExpr() = cls.getParent().getADecoratorCall() + or + // `type(obj)`, where obj is an instance of this class + start = getTypeCall() and + start.(CallCfgNode).getArg(0) = classInstanceTracker(cls) + } -pragma[nomagic] -private TypeTrackingNode classTrackerCall(TypeTracker t, Class cls, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = classTracker(t2, cls) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** * Gets a reference to the class `cls`. */ -Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(result) } +Node classTracker(Class cls) { + CallGraphConstruction::Simple::Make<TrackClassInput>::track(cls).(LocalSourceNode).flowsTo(result) +} -/** - * Gets a reference to an instance of the class `cls`. - */ -private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { - includeInCallGraph(result) and - ( - t.start() and - resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) +private module TrackClassInstanceInput implements CallGraphConstruction::Simple::InputSig { + class State = Class; + + predicate start(Node start, Class cls) { + resolveClassCall(start.(CallCfgNode).asCfgNode(), cls) or // result of `super().__new__` as used in a `__new__` method implementation - t.start() and exists(Class classUsedInSuper | - fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and + fromSuperNewCall(start.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and classUsedInSuper = getADirectSuperclass*(cls) ) - or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(classInstanceTracker(t2, cls), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(classInstanceTrackerCall(t, cls, summary), result, summary) - ) - ) - ) -} + } -pragma[nomagic] -private TypeTrackingNode classInstanceTrackerCall(TypeTracker t, Class cls, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = classInstanceTracker(t2, cls) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** * Gets a reference to an instance of the class `cls`. */ Node classInstanceTracker(Class cls) { - classInstanceTracker(TypeTracker::end(), cls).flowsTo(result) + CallGraphConstruction::Simple::Make<TrackClassInstanceInput>::track(cls) + .(LocalSourceNode) + .flowsTo(result) } -/** - * Gets a reference to the `self` argument of a method on class `classWithMethod`. - * The method cannot be a `staticmethod` or `classmethod`. - */ -private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { - includeInCallGraph(result) and - ( - t.start() and +private module TrackSelfInput implements CallGraphConstruction::Simple::InputSig { + class State = Class; + + predicate start(Node start, Class classWithMethod) { exists(Function func | func = classWithMethod.getAMethod() and not isStaticmethod(func) and not isClassmethod(func) | - result.asExpr() = func.getArg(0) + start.asExpr() = func.getArg(0) ) - or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(selfTracker(t2, classWithMethod), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(selfTrackerCall(t, classWithMethod, summary), result, summary) - ) - ) - ) -} + } -pragma[nomagic] -private TypeTrackingNode selfTrackerCall(TypeTracker t, Class classWithMethod, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = selfTracker(t2, classWithMethod) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** @@ -654,53 +571,32 @@ private TypeTrackingNode selfTrackerCall(TypeTracker t, Class classWithMethod, S * The method cannot be a `staticmethod` or `classmethod`. */ Node selfTracker(Class classWithMethod) { - selfTracker(TypeTracker::end(), classWithMethod).flowsTo(result) + CallGraphConstruction::Simple::Make<TrackSelfInput>::track(classWithMethod) + .(LocalSourceNode) + .flowsTo(result) } -/** - * Gets a reference to the enclosing class `classWithMethod` from within one of its - * methods, either through the `cls` argument from a `classmethod` or from `type(self)` - * from a normal method. - */ -private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) { - includeInCallGraph(result) and - ( - t.start() and - ( - exists(Function func | - func = classWithMethod.getAMethod() and - isClassmethod(func) - | - result.asExpr() = func.getArg(0) - ) - or - // type(self) - result = getTypeCall() and - result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) +private module TrackClsArgumentInput implements CallGraphConstruction::Simple::InputSig { + class State = Class; + + predicate start(Node start, Class classWithMethod) { + exists(Function func | + func = classWithMethod.getAMethod() and + isClassmethod(func) + | + start.asExpr() = func.getArg(0) ) or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(clsArgumentTracker(t2, classWithMethod), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(clsArgumentTrackerCall(t, classWithMethod, summary), result, summary) - ) - ) - ) -} + // type(self) + start = getTypeCall() and + start.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) + } -pragma[nomagic] -private TypeTrackingNode clsArgumentTrackerCall( - TypeTracker t, Class classWithMethod, StepSummary summary -) { - exists(TypeTracker t2 | - // non-linear recursion - result = clsArgumentTracker(t2, classWithMethod) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** @@ -709,46 +605,28 @@ private TypeTrackingNode clsArgumentTrackerCall( * from a normal method. */ Node clsArgumentTracker(Class classWithMethod) { - clsArgumentTracker(TypeTracker::end(), classWithMethod).flowsTo(result) + CallGraphConstruction::Simple::Make<TrackClsArgumentInput>::track(classWithMethod) + .(LocalSourceNode) + .flowsTo(result) } -/** - * Gets a reference to the result of calling `super` without any argument, where the - * call happened in the method `func` (either a method or a classmethod). - */ -private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { - includeInCallGraph(result) and - ( - t.start() and +private module TrackSuperCallNoArgumentInput implements CallGraphConstruction::Simple::InputSig { + class State = Function; + + predicate start(Node start, Function func) { not isStaticmethod(func) and - exists(CallCfgNode call | result = call | + exists(CallCfgNode call | start = call | call = getSuperCall() and not exists(call.getArg(_)) and call.getScope() = func ) - or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(superCallNoArgumentTracker(t2, func), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(superCallNoArgumentTrackerCall(t, func, summary), result, summary) - ) - ) - ) -} + } -pragma[nomagic] -private TypeTrackingNode superCallNoArgumentTrackerCall( - TypeTracker t, Function func, StepSummary summary -) { - exists(TypeTracker t2 | - // non-linear recursion - result = functionTracker(t2, func) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** @@ -756,45 +634,30 @@ private TypeTrackingNode superCallNoArgumentTrackerCall( * call happened in the method `func` (either a method or a classmethod). */ Node superCallNoArgumentTracker(Function func) { - superCallNoArgumentTracker(TypeTracker::end(), func).flowsTo(result) + CallGraphConstruction::Simple::Make<TrackSuperCallNoArgumentInput>::track(func) + .(LocalSourceNode) + .flowsTo(result) } -/** - * Gets a reference to the result of calling `super` with 2 arguments, where the - * first is a reference to the class `cls`, and the second argument is `obj`. - */ -private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, Node obj) { - includeInCallGraph(result) and - ( - t.start() and - exists(CallCfgNode call | result = call | - call = getSuperCall() and - call.getArg(0) = classTracker(cls) and - call.getArg(1) = obj - ) +private module TrackSuperCallTwoArgumentInput implements CallGraphConstruction::Simple::InputSig { + additional predicate superCall(CallCfgNode call, Class cls, Node obj) { + call = getSuperCall() and + call.getArg(0) = classTracker(cls) and + call.getArg(1) = obj + } + + class State = CallCfgNode; + + predicate start(Node start, CallCfgNode call) { + superCall(call, _, _) and + start = call + } + + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) or - not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) and - ( - exists(TypeTracker t2 | t = t2.stepNoCall(superCallTwoArgumentTracker(t2, cls, obj), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(superCallTwoArgumentTrackerCall(t, cls, obj, summary), result, summary) - ) - ) - ) -} - -pragma[nomagic] -private TypeTrackingNode superCallTwoArgumentTrackerCall( - TypeTracker t, Class cls, Node obj, StepSummary summary -) { - exists(TypeTracker t2 | - // non-linear recursion - result = superCallTwoArgumentTracker(t2, cls, obj) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** @@ -802,7 +665,12 @@ private TypeTrackingNode superCallTwoArgumentTrackerCall( * first is a reference to the class `cls`, and the second argument is `obj`. */ Node superCallTwoArgumentTracker(Class cls, Node obj) { - superCallTwoArgumentTracker(TypeTracker::end(), cls, obj).flowsTo(result) + exists(CallCfgNode call | + TrackSuperCallTwoArgumentInput::superCall(call, cls, obj) and + CallGraphConstruction::Simple::Make<TrackSuperCallTwoArgumentInput>::track(call) + .(LocalSourceNode) + .flowsTo(result) + ) } // ============================================================================= @@ -946,35 +814,30 @@ Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, strin // ============================================================================= // attribute trackers // ============================================================================= -/** Gets a reference to the attribute read `attr` */ -private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) { - t.start() and - result = attr and - attr.getObject() in [ - classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_), - superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _) - ] - or - exists(TypeTracker t2 | t = t2.stepNoCall(attrReadTracker(t2, attr), result)) - or - exists(StepSummary summary | - // non-linear recursion - StepSummary::stepCall(attrReadTrackerCall(t, attr, summary), result, summary) - ) -} +private module TrackAttrReadInput implements CallGraphConstruction::Simple::InputSig { + class State = AttrRead; -pragma[nomagic] -private TypeTrackingNode attrReadTrackerCall(TypeTracker t, AttrRead attr, StepSummary summary) { - exists(TypeTracker t2 | - // non-linear recursion - result = attrReadTracker(t2, attr) and - stepCallProj(result, summary) and - t = append(t2, summary) - ) + predicate start(Node start, AttrRead attr) { + start = attr and + attr.getObject() in [ + classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_), + superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _) + ] + } + + predicate filter(Node n) { + ignoreForCallGraph(n.getLocation().getFile()) + or + n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) + } } /** Gets a reference to the attribute read `attr` */ -Node attrReadTracker(AttrRead attr) { attrReadTracker(TypeTracker::end(), attr).flowsTo(result) } +Node attrReadTracker(AttrRead attr) { + CallGraphConstruction::Simple::Make<TrackAttrReadInput>::track(attr) + .(LocalSourceNode) + .flowsTo(result) +} // ============================================================================= // call and argument resolution From 60725e9580b2a19095de5d111ec445910de60bb6 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:07:22 +0200 Subject: [PATCH 160/219] Update java/ql/lib/ext/org.springframework.core.io.model.yml --- java/ql/lib/ext/org.springframework.core.io.model.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/lib/ext/org.springframework.core.io.model.yml b/java/ql/lib/ext/org.springframework.core.io.model.yml index 7f3f3718471..b6dd35c8096 100644 --- a/java/ql/lib/ext/org.springframework.core.io.model.yml +++ b/java/ql/lib/ext/org.springframework.core.io.model.yml @@ -3,4 +3,5 @@ extensions: pack: codeql/java-all extensible: sinkModel data: - - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] # todo: look into whether this may also be a request forgery sink + - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] + - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "(String)", "", "Argument[0]", "request-forgery", "manual"] From 8001ae9669ffe778732f2b5b4b2ff83d81f23b14 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:08:24 +0200 Subject: [PATCH 161/219] Update java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com> --- java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll index 68365db51c2..8261aef9fb3 100644 --- a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll @@ -50,7 +50,7 @@ private class FileCreationSink extends DataFlow::Node { /** * Holds if `sink` is a path creation node that doesn't imply a read/write filesystem operation. * This is to avoid creating new spurious alerts, since `PathCreation` sinks weren't - * previosuly part of this query. + * previously part of this query. */ private predicate isPathCreation(DataFlow::Node sink) { exists(PathCreation pc | From 700e3d5e5317974facfad004e3fddcf8add57a06 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli <redsun82@github.com> Date: Wed, 7 Jun 2023 09:12:39 +0200 Subject: [PATCH 162/219] Codegen: rename `ipa` to `synth` --- misc/codegen/generators/cppgen.py | 2 +- misc/codegen/generators/dbschemegen.py | 4 +- misc/codegen/generators/qlgen.py | 74 +++++++++---------- misc/codegen/lib/ql.py | 38 +++++----- misc/codegen/lib/schema.py | 12 +-- misc/codegen/lib/schemadefs.py | 4 +- misc/codegen/loaders/schemaloader.py | 32 ++++---- misc/codegen/templates/ql_stub.mustache | 8 +- ...che => ql_synth_constructor_stub.mustache} | 8 +- ...types.mustache => ql_synth_types.mustache} | 16 ++-- misc/codegen/test/test_cppgen.py | 8 +- misc/codegen/test/test_dbschemegen.py | 12 +-- misc/codegen/test/test_ql.py | 4 +- misc/codegen/test/test_qlgen.py | 20 ++--- misc/codegen/test/test_schemaloader.py | 34 ++++----- 15 files changed, 138 insertions(+), 138 deletions(-) rename misc/codegen/templates/{ql_ipa_constructor_stub.mustache => ql_synth_constructor_stub.mustache} (61%) rename misc/codegen/templates/{ql_ipa_types.mustache => ql_synth_types.mustache} (91%) diff --git a/misc/codegen/generators/cppgen.py b/misc/codegen/generators/cppgen.py index 8f522dc1435..de53b771d35 100644 --- a/misc/codegen/generators/cppgen.py +++ b/misc/codegen/generators/cppgen.py @@ -85,7 +85,7 @@ class Processor: def get_classes(self): ret = {'': []} for k, cls in self._classmap.items(): - if not cls.ipa: + if not cls.synth: ret.setdefault(cls.group, []).append(self._get_class(cls.name)) return ret diff --git a/misc/codegen/generators/dbschemegen.py b/misc/codegen/generators/dbschemegen.py index bc45ae3022f..2c3cd5598d5 100755 --- a/misc/codegen/generators/dbschemegen.py +++ b/misc/codegen/generators/dbschemegen.py @@ -40,10 +40,10 @@ def dbtype(typename: str, add_or_none_except: typing.Optional[str] = None) -> st def cls_to_dbscheme(cls: schema.Class, lookup: typing.Dict[str, schema.Class], add_or_none_except: typing.Optional[str] = None): """ Yield all dbscheme entities needed to model class `cls` """ - if cls.ipa: + if cls.synth: return if cls.derived: - yield Union(dbtype(cls.name), (dbtype(c) for c in cls.derived if not lookup[c].ipa)) + yield Union(dbtype(cls.name), (dbtype(c) for c in cls.derived if not lookup[c].synth)) dir = pathlib.Path(cls.group) if cls.group else None # output a table specific to a class only if it is a leaf class or it has 1-to-1 properties # Leaf classes need a table to bind the `@` ids diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index 99aca88add4..0dad9d3322f 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -111,7 +111,7 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dic is_predicate=prop.is_predicate, is_unordered=prop.is_unordered, description=prop.description, - synth=bool(cls.ipa) or prop.synth, + synth=bool(cls.synth) or prop.synth, type_is_hideable=lookup[prop.type].hideable if prop.type in lookup else False, ) if prop.is_single: @@ -179,26 +179,26 @@ def _to_db_type(x: str) -> str: _final_db_class_lookup = {} -def get_ql_ipa_class_db(name: str) -> ql.Synth.FinalClassDb: +def get_ql_synth_class_db(name: str) -> ql.Synth.FinalClassDb: return _final_db_class_lookup.setdefault(name, ql.Synth.FinalClassDb(name=name, params=[ ql.Synth.Param("id", _to_db_type(name))])) -def get_ql_ipa_class(cls: schema.Class): +def get_ql_synth_class(cls: schema.Class): if cls.derived: return ql.Synth.NonFinalClass(name=cls.name, derived=sorted(cls.derived), root=not cls.bases) - if cls.ipa and cls.ipa.from_class is not None: - source = cls.ipa.from_class - get_ql_ipa_class_db(source).subtract_type(cls.name) - return ql.Synth.FinalClassDerivedIpa(name=cls.name, - params=[ql.Synth.Param("id", _to_db_type(source))]) - if cls.ipa and cls.ipa.on_arguments is not None: - return ql.Synth.FinalClassFreshIpa(name=cls.name, - params=[ql.Synth.Param(k, _to_db_type(v)) - for k, v in cls.ipa.on_arguments.items()]) - return get_ql_ipa_class_db(cls.name) + if cls.synth and cls.synth.from_class is not None: + source = cls.synth.from_class + get_ql_synth_class_db(source).subtract_type(cls.name) + return ql.Synth.FinalClassDerivedSynth(name=cls.name, + params=[ql.Synth.Param("id", _to_db_type(source))]) + if cls.synth and cls.synth.on_arguments is not None: + return ql.Synth.FinalClassFreshSynth(name=cls.name, + params=[ql.Synth.Param(k, _to_db_type(v)) + for k, v in cls.synth.on_arguments.items()]) + return get_ql_synth_class_db(cls.name) def get_import(file: pathlib.Path, root_dir: pathlib.Path): @@ -291,26 +291,26 @@ def _should_skip_qltest(cls: schema.Class, lookup: typing.Dict[str, schema.Class def _get_stub(cls: schema.Class, base_import: str, generated_import_prefix: str) -> ql.Stub: - if isinstance(cls.ipa, schema.IpaInfo): - if cls.ipa.from_class is not None: + if isinstance(cls.synth, schema.SynthInfo): + if cls.synth.from_class is not None: accessors = [ - ql.IpaUnderlyingAccessor( + ql.SynthUnderlyingAccessor( argument="Entity", - type=_to_db_type(cls.ipa.from_class), + type=_to_db_type(cls.synth.from_class), constructorparams=["result"] ) ] - elif cls.ipa.on_arguments is not None: + elif cls.synth.on_arguments is not None: accessors = [ - ql.IpaUnderlyingAccessor( + ql.SynthUnderlyingAccessor( argument=inflection.camelize(arg), type=_to_db_type(type), - constructorparams=["result" if a == arg else "_" for a in cls.ipa.on_arguments] - ) for arg, type in cls.ipa.on_arguments.items() + constructorparams=["result" if a == arg else "_" for a in cls.synth.on_arguments] + ) for arg, type in cls.synth.on_arguments.items() ] else: accessors = [] - return ql.Stub(name=cls.name, base_import=base_import, import_prefix=generated_import_prefix, ipa_accessors=accessors) + return ql.Stub(name=cls.name, base_import=base_import, import_prefix=generated_import_prefix, synth_accessors=accessors) def generate(opts, renderer): @@ -344,7 +344,7 @@ def generate(opts, renderer): with renderer.manage(generated=generated, stubs=stubs, registry=opts.generated_registry, force=opts.force) as renderer: - db_classes = [cls for name, cls in classes.items() if not data.classes[name].ipa] + db_classes = [cls for name, cls in classes.items() if not data.classes[name].synth] renderer.render(ql.DbClasses(db_classes), out / "Raw.qll") classes_by_dir_and_name = sorted(classes.values(), key=lambda cls: (cls.dir, cls.name)) @@ -401,32 +401,32 @@ def generate(opts, renderer): elements_module=elements_module, property=p), test_dir / f"{c.name}_{p.getter}.ql") - final_ipa_types = [] - non_final_ipa_types = [] + final_synth_types = [] + non_final_synth_types = [] constructor_imports = [] - ipa_constructor_imports = [] + synth_constructor_imports = [] stubs = {} for cls in sorted(data.classes.values(), key=lambda cls: (cls.group, cls.name)): - ipa_type = get_ql_ipa_class(cls) - if ipa_type.is_final: - final_ipa_types.append(ipa_type) - if ipa_type.has_params: + synth_type = get_ql_synth_class(cls) + if synth_type.is_final: + final_synth_types.append(synth_type) + if synth_type.has_params: stub_file = stub_out / cls.group / f"{cls.name}Constructor.qll" if not renderer.is_customized_stub(stub_file): - # stub rendering must be postponed as we might not have yet all subtracted ipa types in `ipa_type` - stubs[stub_file] = ql.Synth.ConstructorStub(ipa_type, import_prefix=generated_import_prefix) + # stub rendering must be postponed as we might not have yet all subtracted synth types in `synth_type` + stubs[stub_file] = ql.Synth.ConstructorStub(synth_type, import_prefix=generated_import_prefix) constructor_import = get_import(stub_file, opts.root_dir) constructor_imports.append(constructor_import) - if ipa_type.is_ipa: - ipa_constructor_imports.append(constructor_import) + if synth_type.is_synth: + synth_constructor_imports.append(constructor_import) else: - non_final_ipa_types.append(ipa_type) + non_final_synth_types.append(synth_type) for stub_file, data in stubs.items(): renderer.render(data, stub_file) renderer.render(ql.Synth.Types(root.name, generated_import_prefix, - final_ipa_types, non_final_ipa_types), out / "Synth.qll") + final_synth_types, non_final_synth_types), out / "Synth.qll") renderer.render(ql.ImportList(constructor_imports), out / "SynthConstructors.qll") - renderer.render(ql.ImportList(ipa_constructor_imports), out / "PureSynthConstructors.qll") + renderer.render(ql.ImportList(synth_constructor_imports), out / "PureSynthConstructors.qll") if opts.ql_format: format(opts.codeql_binary, renderer.written) diff --git a/misc/codegen/lib/ql.py b/misc/codegen/lib/ql.py index a5f82a3d64b..59a672ab3ce 100644 --- a/misc/codegen/lib/ql.py +++ b/misc/codegen/lib/ql.py @@ -147,7 +147,7 @@ class Class: @dataclass -class IpaUnderlyingAccessor: +class SynthUnderlyingAccessor: argument: str type: str constructorparams: List[Param] @@ -165,11 +165,11 @@ class Stub: name: str base_import: str import_prefix: str - ipa_accessors: List[IpaUnderlyingAccessor] = field(default_factory=list) + synth_accessors: List[SynthUnderlyingAccessor] = field(default_factory=list) @property - def has_ipa_accessors(self) -> bool: - return bool(self.ipa_accessors) + def has_synth_accessors(self) -> bool: + return bool(self.synth_accessors) @dataclass @@ -245,8 +245,8 @@ class Synth: @dataclass class FinalClass(Class): is_final: ClassVar = True - is_derived_ipa: ClassVar = False - is_fresh_ipa: ClassVar = False + is_derived_synth: ClassVar = False + is_fresh_synth: ClassVar = False is_db: ClassVar = False params: List["Synth.Param"] = field(default_factory=list) @@ -256,37 +256,37 @@ class Synth: self.params[0].first = True @property - def is_ipa(self): - return self.is_fresh_ipa or self.is_derived_ipa + def is_synth(self): + return self.is_fresh_synth or self.is_derived_synth @property def has_params(self) -> bool: return bool(self.params) @dataclass - class FinalClassIpa(FinalClass): + class FinalClassSynth(FinalClass): pass @dataclass - class FinalClassDerivedIpa(FinalClassIpa): - is_derived_ipa: ClassVar = True + class FinalClassDerivedSynth(FinalClassSynth): + is_derived_synth: ClassVar = True @dataclass - class FinalClassFreshIpa(FinalClassIpa): - is_fresh_ipa: ClassVar = True + class FinalClassFreshSynth(FinalClassSynth): + is_fresh_synth: ClassVar = True @dataclass class FinalClassDb(FinalClass): is_db: ClassVar = True - subtracted_ipa_types: List["Synth.Class"] = field(default_factory=list) + subtracted_synth_types: List["Synth.Class"] = field(default_factory=list) def subtract_type(self, type: str): - self.subtracted_ipa_types.append(Synth.Class(type, first=not self.subtracted_ipa_types)) + self.subtracted_synth_types.append(Synth.Class(type, first=not self.subtracted_synth_types)) @property - def has_subtracted_ipa_types(self) -> bool: - return bool(self.subtracted_ipa_types) + def has_subtracted_synth_types(self) -> bool: + return bool(self.subtracted_synth_types) @property def db_id(self) -> str: @@ -304,7 +304,7 @@ class Synth: @dataclass class Types: - template: ClassVar = "ql_ipa_types" + template: ClassVar = "ql_synth_types" root: str import_prefix: str @@ -317,7 +317,7 @@ class Synth: @dataclass class ConstructorStub: - template: ClassVar = "ql_ipa_constructor_stub" + template: ClassVar = "ql_synth_constructor_stub" cls: "Synth.FinalClass" import_prefix: str diff --git a/misc/codegen/lib/schema.py b/misc/codegen/lib/schema.py index 6c1869e92ce..bc1a90f9e25 100644 --- a/misc/codegen/lib/schema.py +++ b/misc/codegen/lib/schema.py @@ -75,7 +75,7 @@ RepeatedUnorderedProperty = functools.partial(Property, Property.Kind.REPEATED_U @dataclass -class IpaInfo: +class SynthInfo: from_class: Optional[str] = None on_arguments: Optional[Dict[str, str]] = None @@ -88,7 +88,7 @@ class Class: properties: List[Property] = field(default_factory=list) group: str = "" pragmas: List[str] = field(default_factory=list) - ipa: Optional[Union[IpaInfo, bool]] = None + synth: Optional[Union[SynthInfo, bool]] = None """^^^ filled with `True` for non-final classes with only synthesized final descendants """ doc: List[str] = field(default_factory=list) default_doc_name: Optional[str] = None @@ -105,10 +105,10 @@ class Class: _check_type(d, known) for p in self.properties: _check_type(p.type, known) - if self.ipa is not None: - _check_type(self.ipa.from_class, known) - if self.ipa.on_arguments is not None: - for t in self.ipa.on_arguments.values(): + if self.synth is not None: + _check_type(self.synth.from_class, known) + if self.synth.on_arguments is not None: + for t in self.synth.on_arguments.values(): _check_type(t, known) diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py index b0d6e1c0f6b..61abbec75a5 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -160,7 +160,7 @@ def group(name: str = "") -> _ClassDecorator: return _annotate(group=name) -synth.from_class = lambda ref: _annotate(ipa=_schema.IpaInfo( +synth.from_class = lambda ref: _annotate(synth=_schema.SynthInfo( from_class=_schema.get_type_name(ref))) synth.on_arguments = lambda **kwargs: _annotate( - ipa=_schema.IpaInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})) + synth=_schema.SynthInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})) diff --git a/misc/codegen/loaders/schemaloader.py b/misc/codegen/loaders/schemaloader.py index 64f4d03cb57..c81c2061d91 100644 --- a/misc/codegen/loaders/schemaloader.py +++ b/misc/codegen/loaders/schemaloader.py @@ -40,7 +40,7 @@ def _get_class(cls: type) -> schema.Class: hideable=getattr(cls, "_hideable", False), # in the following we don't use `getattr` to avoid inheriting pragmas=cls.__dict__.get("_pragmas", []), - ipa=cls.__dict__.get("_ipa", None), + synth=cls.__dict__.get("_synth", None), properties=[ a | _PropertyNamer(n) for n, a in cls.__dict__.get("__annotations__", {}).items() @@ -65,34 +65,34 @@ def _toposort_classes_by_group(classes: typing.Dict[str, schema.Class]) -> typin return ret -def _fill_ipa_information(classes: typing.Dict[str, schema.Class]): - """ Take a dictionary where the `ipa` field is filled for all explicitly synthesized classes +def _fill_synth_information(classes: typing.Dict[str, schema.Class]): + """ Take a dictionary where the `synth` field is filled for all explicitly synthesized classes and update it so that all non-final classes that have only synthesized final descendants - get `True` as` value for the `ipa` field + get `True` as` value for the `synth` field """ if not classes: return - is_ipa: typing.Dict[str, bool] = {} + is_synth: typing.Dict[str, bool] = {} - def fill_is_ipa(name: str): - if name not in is_ipa: + def fill_is_synth(name: str): + if name not in is_synth: cls = classes[name] for d in cls.derived: - fill_is_ipa(d) - if cls.ipa is not None: - is_ipa[name] = True + fill_is_synth(d) + if cls.synth is not None: + is_synth[name] = True elif not cls.derived: - is_ipa[name] = False + is_synth[name] = False else: - is_ipa[name] = all(is_ipa[d] for d in cls.derived) + is_synth[name] = all(is_synth[d] for d in cls.derived) root = next(iter(classes)) - fill_is_ipa(root) + fill_is_synth(root) for name, cls in classes.items(): - if cls.ipa is None and is_ipa[name]: - cls.ipa = True + if cls.synth is None and is_synth[name]: + cls.synth = True def _fill_hideable_information(classes: typing.Dict[str, schema.Class]): @@ -134,7 +134,7 @@ def load(m: types.ModuleType) -> schema.Schema: null = name cls.is_null_class = True - _fill_ipa_information(classes) + _fill_synth_information(classes) _fill_hideable_information(classes) return schema.Schema(includes=includes, classes=_toposort_classes_by_group(classes), null=null) diff --git a/misc/codegen/templates/ql_stub.mustache b/misc/codegen/templates/ql_stub.mustache index 7e17efc6d46..b5b6a9d70cb 100644 --- a/misc/codegen/templates/ql_stub.mustache +++ b/misc/codegen/templates/ql_stub.mustache @@ -1,9 +1,9 @@ // generated by {{generator}}, remove this comment if you wish to edit this file private import {{base_import}} -{{#has_ipa_accessors}} +{{#has_synth_accessors}} private import {{import_prefix}}.Raw private import {{import_prefix}}.Synth -{{/has_ipa_accessors}} +{{/has_synth_accessors}} {{#ql_internal}} /** @@ -11,8 +11,8 @@ private import {{import_prefix}}.Synth */ {{/ql_internal}} class {{name}} extends Generated::{{name}} { - {{#ipa_accessors}} + {{#synth_accessors}} private cached {{type}} getUnderlying{{argument}}() { this = Synth::T{{name}}({{#constructorparams}}{{^first}},{{/first}}{{param}}{{/constructorparams}})} - {{/ipa_accessors}} + {{/synth_accessors}} } diff --git a/misc/codegen/templates/ql_ipa_constructor_stub.mustache b/misc/codegen/templates/ql_synth_constructor_stub.mustache similarity index 61% rename from misc/codegen/templates/ql_ipa_constructor_stub.mustache rename to misc/codegen/templates/ql_synth_constructor_stub.mustache index e5e525417d3..3425e8c618f 100644 --- a/misc/codegen/templates/ql_ipa_constructor_stub.mustache +++ b/misc/codegen/templates/ql_synth_constructor_stub.mustache @@ -2,15 +2,15 @@ private import {{import_prefix}}.Raw {{#cls}} {{#is_db}} -{{#has_subtracted_ipa_types}} +{{#has_subtracted_synth_types}} private import {{import_prefix}}.PureSynthConstructors -{{/has_subtracted_ipa_types}} +{{/has_subtracted_synth_types}} {{/is_db}} predicate construct{{name}}({{#params}}{{^first}}, {{/first}}{{type}} {{param}}{{/params}}) { {{#is_db}} - {{#subtracted_ipa_types}}{{^first}} and {{/first}}not construct{{name}}(id){{/subtracted_ipa_types}} - {{^subtracted_ipa_types}}any(){{/subtracted_ipa_types}} + {{#subtracted_synth_types}}{{^first}} and {{/first}}not construct{{name}}(id){{/subtracted_synth_types}} + {{^subtracted_synth_types}}any(){{/subtracted_synth_types}} {{/is_db}} {{^is_db}} none() diff --git a/misc/codegen/templates/ql_ipa_types.mustache b/misc/codegen/templates/ql_synth_types.mustache similarity index 91% rename from misc/codegen/templates/ql_ipa_types.mustache rename to misc/codegen/templates/ql_synth_types.mustache index d4244690930..a174d141a6b 100644 --- a/misc/codegen/templates/ql_ipa_types.mustache +++ b/misc/codegen/templates/ql_synth_types.mustache @@ -38,12 +38,12 @@ cached module Synth { * Converts a raw element to a synthesized `T{{name}}`, if possible. */ cached T{{name}} convert{{name}}FromRaw(Raw::Element e) { - {{^is_fresh_ipa}} + {{^is_fresh_synth}} result = T{{name}}(e) - {{/is_fresh_ipa}} - {{#is_fresh_ipa}} + {{/is_fresh_synth}} + {{#is_fresh_synth}} none() - {{/is_fresh_ipa}} + {{/is_fresh_synth}} } {{/final_classes}} @@ -68,12 +68,12 @@ cached module Synth { * Converts a synthesized `T{{name}}` to a raw DB element, if possible. */ cached Raw::Element convert{{name}}ToRaw(T{{name}} e) { - {{^is_fresh_ipa}} + {{^is_fresh_synth}} e = T{{name}}(result) - {{/is_fresh_ipa}} - {{#is_fresh_ipa}} + {{/is_fresh_synth}} + {{#is_fresh_synth}} none() - {{/is_fresh_ipa}} + {{/is_fresh_synth}} } {{/final_classes}} diff --git a/misc/codegen/test/test_cppgen.py b/misc/codegen/test/test_cppgen.py index ebb7b3887ef..fcd9b15e8d0 100644 --- a/misc/codegen/test/test_cppgen.py +++ b/misc/codegen/test/test_cppgen.py @@ -181,19 +181,19 @@ def test_cpp_skip_pragma(generate): ] -def test_ipa_classes_ignored(generate): +def test_synth_classes_ignored(generate): assert generate([ schema.Class( name="W", - ipa=schema.IpaInfo(), + synth=schema.SynthInfo(), ), schema.Class( name="X", - ipa=schema.IpaInfo(from_class="A"), + synth=schema.SynthInfo(from_class="A"), ), schema.Class( name="Y", - ipa=schema.IpaInfo(on_arguments={"a": "A", "b": "int"}), + synth=schema.SynthInfo(on_arguments={"a": "A", "b": "int"}), ), schema.Class( name="Z", diff --git a/misc/codegen/test/test_dbschemegen.py b/misc/codegen/test/test_dbschemegen.py index 45b5718a876..1fbbc046785 100644 --- a/misc/codegen/test/test_dbschemegen.py +++ b/misc/codegen/test/test_dbschemegen.py @@ -534,11 +534,11 @@ def test_null_class(generate): ) -def test_ipa_classes_ignored(generate): +def test_synth_classes_ignored(generate): assert generate([ - schema.Class(name="A", ipa=schema.IpaInfo()), - schema.Class(name="B", ipa=schema.IpaInfo(from_class="A")), - schema.Class(name="C", ipa=schema.IpaInfo(on_arguments={"x": "A"})), + schema.Class(name="A", synth=schema.SynthInfo()), + schema.Class(name="B", synth=schema.SynthInfo(from_class="A")), + schema.Class(name="C", synth=schema.SynthInfo(on_arguments={"x": "A"})), ]) == dbscheme.Scheme( src=schema_file.name, includes=[], @@ -546,10 +546,10 @@ def test_ipa_classes_ignored(generate): ) -def test_ipa_derived_classes_ignored(generate): +def test_synth_derived_classes_ignored(generate): assert generate([ schema.Class(name="A", derived={"B", "C"}), - schema.Class(name="B", bases=["A"], ipa=schema.IpaInfo()), + schema.Class(name="B", bases=["A"], synth=schema.SynthInfo()), schema.Class(name="C", bases=["A"]), ]) == dbscheme.Scheme( src=schema_file.name, diff --git a/misc/codegen/test/test_ql.py b/misc/codegen/test/test_ql.py index 6d1e2181194..35b3af77399 100644 --- a/misc/codegen/test/test_ql.py +++ b/misc/codegen/test/test_ql.py @@ -169,9 +169,9 @@ def test_class_without_description(): assert prop.has_description is False -def test_ipa_accessor_has_first_constructor_param_marked(): +def test_synth_accessor_has_first_constructor_param_marked(): params = ["a", "b", "c"] - x = ql.IpaUnderlyingAccessor("foo", "bar", params) + x = ql.SynthUnderlyingAccessor("foo", "bar", params) assert x.constructorparams[0].first assert [p.param for p in x.constructorparams] == params diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 12d5d28bca6..2a0fab2bbf2 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -848,13 +848,13 @@ def test_property_on_class_with_default_doc_name(generate_classes): } -def test_stub_on_class_with_ipa_from_class(generate_classes): +def test_stub_on_class_with_synth_from_class(generate_classes): assert generate_classes([ - schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A"), + schema.Class("MyObject", synth=schema.SynthInfo(from_class="A"), properties=[schema.SingleProperty("foo", "bar")]), ]) == { - "MyObject.qll": (a_ql_stub(name="MyObject", ipa_accessors=[ - ql.IpaUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]), + "MyObject.qll": (a_ql_stub(name="MyObject", synth_accessors=[ + ql.SynthUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]), ]), a_ql_class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, @@ -863,15 +863,15 @@ def test_stub_on_class_with_ipa_from_class(generate_classes): } -def test_stub_on_class_with_ipa_on_arguments(generate_classes): +def test_stub_on_class_with_synth_on_arguments(generate_classes): assert generate_classes([ - schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"}), + schema.Class("MyObject", synth=schema.SynthInfo(on_arguments={"base": "A", "index": "int", "label": "string"}), properties=[schema.SingleProperty("foo", "bar")]), ]) == { - "MyObject.qll": (a_ql_stub(name="MyObject", ipa_accessors=[ - ql.IpaUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]), - ql.IpaUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]), - ql.IpaUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]), + "MyObject.qll": (a_ql_stub(name="MyObject", synth_accessors=[ + ql.SynthUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]), + ql.SynthUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]), + ql.SynthUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]), ]), a_ql_class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", type="bar", tablename="my_objects", synth=True, diff --git a/misc/codegen/test/test_schemaloader.py b/misc/codegen/test/test_schemaloader.py index ed35f4b0271..d5772bea447 100644 --- a/misc/codegen/test/test_schemaloader.py +++ b/misc/codegen/test/test_schemaloader.py @@ -337,7 +337,7 @@ def test_class_with_pragmas(): } -def test_ipa_from_class(): +def test_synth_from_class(): @load class data: class A: @@ -348,12 +348,12 @@ def test_ipa_from_class(): pass assert data.classes == { - 'A': schema.Class('A', derived={'B'}, ipa=True), - 'B': schema.Class('B', bases=['A'], ipa=schema.IpaInfo(from_class="A")), + 'A': schema.Class('A', derived={'B'}, synth=True), + 'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(from_class="A")), } -def test_ipa_from_class_ref(): +def test_synth_from_class_ref(): @load class data: @defs.synth.from_class("B") @@ -364,12 +364,12 @@ def test_ipa_from_class_ref(): pass assert data.classes == { - 'A': schema.Class('A', derived={'B'}, ipa=schema.IpaInfo(from_class="B")), + 'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(from_class="B")), 'B': schema.Class('B', bases=['A']), } -def test_ipa_from_class_dangling(): +def test_synth_from_class_dangling(): with pytest.raises(schema.Error): @load class data: @@ -378,7 +378,7 @@ def test_ipa_from_class_dangling(): pass -def test_ipa_class_on(): +def test_synth_class_on(): @load class data: class A: @@ -389,12 +389,12 @@ def test_ipa_class_on(): pass assert data.classes == { - 'A': schema.Class('A', derived={'B'}, ipa=True), - 'B': schema.Class('B', bases=['A'], ipa=schema.IpaInfo(on_arguments={'a': 'A', 'i': 'int'})), + 'A': schema.Class('A', derived={'B'}, synth=True), + 'B': schema.Class('B', bases=['A'], synth=schema.SynthInfo(on_arguments={'a': 'A', 'i': 'int'})), } -def test_ipa_class_on_ref(): +def test_synth_class_on_ref(): class A: pass @@ -408,12 +408,12 @@ def test_ipa_class_on_ref(): pass assert data.classes == { - 'A': schema.Class('A', derived={'B'}, ipa=schema.IpaInfo(on_arguments={'b': 'B', 'i': 'int'})), + 'A': schema.Class('A', derived={'B'}, synth=schema.SynthInfo(on_arguments={'b': 'B', 'i': 'int'})), 'B': schema.Class('B', bases=['A']), } -def test_ipa_class_on_dangling(): +def test_synth_class_on_dangling(): with pytest.raises(schema.Error): @load class data: @@ -422,7 +422,7 @@ def test_ipa_class_on_dangling(): pass -def test_ipa_class_hierarchy(): +def test_synth_class_hierarchy(): @load class data: class Root: @@ -447,10 +447,10 @@ def test_ipa_class_hierarchy(): assert data.classes == { 'Root': schema.Class('Root', derived={'Base', 'C'}), - 'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, ipa=True), - 'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, ipa=True), - 'A': schema.Class('A', bases=['Intermediate'], ipa=schema.IpaInfo(on_arguments={'a': 'Base', 'i': 'int'})), - 'B': schema.Class('B', bases=['Base'], ipa=schema.IpaInfo(from_class='Base')), + 'Base': schema.Class('Base', bases=['Root'], derived={'Intermediate', 'B'}, synth=True), + 'Intermediate': schema.Class('Intermediate', bases=['Base'], derived={'A'}, synth=True), + 'A': schema.Class('A', bases=['Intermediate'], synth=schema.SynthInfo(on_arguments={'a': 'Base', 'i': 'int'})), + 'B': schema.Class('B', bases=['Base'], synth=schema.SynthInfo(from_class='Base')), 'C': schema.Class('C', bases=['Root']), } From 27763d6bbed3823c91058f1bd82834b1fc3c1da6 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:25:42 +0200 Subject: [PATCH 163/219] Improve ZipSlip exclusion to take varargs into account --- java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll index 8261aef9fb3..074153ffd8f 100644 --- a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll @@ -54,7 +54,10 @@ private class FileCreationSink extends DataFlow::Node { */ private predicate isPathCreation(DataFlow::Node sink) { exists(PathCreation pc | - pc.getAnInput() = sink.asExpr() and + pc.getAnInput() = sink.asExpr() + or + pc.getAnInput().(Argument).isVararg() and sink.(DataFlow::ImplicitVarargsArray).getCall() = pc + | // exclude actual read/write operations included in `PathCreation` not pc.(Call) .getCallee() From 0c8b4251cf6bc10e59977033d6252d95838e3b00 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 7 Jun 2023 10:07:01 +0200 Subject: [PATCH 164/219] Python: Avoid duplicated query-id --- .../ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql b/python/ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql index 671bc0998fd..5a38a673080 100644 --- a/python/ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql +++ b/python/ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql @@ -5,7 +5,7 @@ * @problem.severity error * @security-severity 9.3 * @precision high - * @id py/command-injection + * @id py/paramiko-command-injection * @tags security * experimental * external/cwe/cwe-074 From 416d3d587dd547270cb7fda929d1df9562bbf29e Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 10:33:17 +0200 Subject: [PATCH 165/219] Accept test changes An uncovered test case is now correctly covered --- .../query-tests/security/CWE-552/UnsafeUrlForward.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected index 11a8bc6c248..a39906b4115 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected @@ -3,6 +3,7 @@ edges | UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | UnsafeLoadSpringResource.java:35:31:35:33 | clr | | UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String | UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | | UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | +| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName | | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:17:20:17:25 | params : Map | | UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | @@ -35,6 +36,8 @@ nodes | UnsafeLoadSpringResource.java:35:31:35:33 | clr | semmle.label | clr | | UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | semmle.label | fileName : String | | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | semmle.label | fileName | +| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | semmle.label | fileName : String | +| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | semmle.label | fileName | | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | semmle.label | getServletPath(...) : String | | UnsafeRequestPath.java:23:33:23:36 | path | semmle.label | path | | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map | @@ -83,6 +86,7 @@ subpaths #select | UnsafeLoadSpringResource.java:35:31:35:33 | clr | UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | UnsafeLoadSpringResource.java:35:31:35:33 | clr | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:27:32:27:77 | fileName | user-provided value | | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:68:32:68:77 | fileName | user-provided value | +| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:108:32:108:77 | fileName | user-provided value | | UnsafeRequestPath.java:23:33:23:36 | path | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | Potentially untrusted URL forward due to $@. | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) | user-provided value | | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) | user-provided value | | UnsafeResourceGet2.java:37:20:37:22 | url | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:37:20:37:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) | user-provided value | From 0f75449abb71c17a60a96774d59f3509bb7e8b8c Mon Sep 17 00:00:00 2001 From: Tamas Vajk <tamasvajk@github.com> Date: Wed, 7 Jun 2023 10:40:58 +0200 Subject: [PATCH 166/219] Improve code quality --- csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index bae6a2b55ec..3729a5d2528 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -245,7 +245,7 @@ namespace Semmle.Extraction.CSharp.Entities // Retrieve the original method kind if (methodDecl.ExplicitInterfaceImplementations.IsEmpty) { - throw new InternalError(methodDecl, $"Couldn't get the original method kind for an explicit interface implementation"); + throw new InternalError(methodDecl, "Couldn't get the original method kind for an explicit interface implementation"); } methodKind = methodDecl.ExplicitInterfaceImplementations.Select(m => m.MethodKind).First(); From 76e1c6f76f0c1e1b23d7f24e0112e1ce07752e3f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 7 Jun 2023 11:18:53 +0200 Subject: [PATCH 167/219] java: test type tracking through flow summaries --- .../dispatch/CallableViaSummary.java | 31 +++++++++++++++++++ .../dispatch/viaSummary.expected | 2 ++ .../test/library-tests/dispatch/viaSummary.ql | 9 ++++++ 3 files changed, 42 insertions(+) create mode 100644 java/ql/test/library-tests/dispatch/CallableViaSummary.java create mode 100644 java/ql/test/library-tests/dispatch/viaSummary.expected create mode 100644 java/ql/test/library-tests/dispatch/viaSummary.ql diff --git a/java/ql/test/library-tests/dispatch/CallableViaSummary.java b/java/ql/test/library-tests/dispatch/CallableViaSummary.java new file mode 100644 index 00000000000..da7c7d86efd --- /dev/null +++ b/java/ql/test/library-tests/dispatch/CallableViaSummary.java @@ -0,0 +1,31 @@ +import java.util.*; + +public class CallableViaSummary { + public interface Element { + public void handle(String message); + } + + public void main(String[] args) { + List<Element> elements = new ArrayList<>(); + + List<Element> elements2 = new ArrayList<>(); + + elements.add(new Element() { + @Override + public void handle(String message) { + System.out.println(message); + } + }); + + elements.add(message -> System.out.println(message)); + + // This dispatches to the two added elements because + // the summary of ArrayList causes flow via type tracking. + elements.get(0).handle("Hello, world!"); + + // This does not dispatch to anything, showing that the + // open-world assumption does not apply + // (and hence that type tracking is necessary above). + elements2.get(0).handle("Hello, world!"); + } +} \ No newline at end of file diff --git a/java/ql/test/library-tests/dispatch/viaSummary.expected b/java/ql/test/library-tests/dispatch/viaSummary.expected new file mode 100644 index 00000000000..7c311587d9a --- /dev/null +++ b/java/ql/test/library-tests/dispatch/viaSummary.expected @@ -0,0 +1,2 @@ +| CallableViaSummary.java:24:9:24:47 | handle(...) | CallableViaSummary.java:15:25:15:30 | handle | +| CallableViaSummary.java:24:9:24:47 | handle(...) | CallableViaSummary.java:20:22:20:59 | handle | diff --git a/java/ql/test/library-tests/dispatch/viaSummary.ql b/java/ql/test/library-tests/dispatch/viaSummary.ql new file mode 100644 index 00000000000..c421e1c9904 --- /dev/null +++ b/java/ql/test/library-tests/dispatch/viaSummary.ql @@ -0,0 +1,9 @@ +import java +import semmle.code.java.dispatch.VirtualDispatch + +from MethodAccess ma, Method m +where + m = viableImpl(ma) and + m.fromSource() and + ma.getFile().toString().matches("CallableViaSummary") +select ma, m From aec1e4a7131554595e7cbfc82647471ca8ef796a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 7 Jun 2023 11:40:50 +0200 Subject: [PATCH 168/219] java: address ql alert --- java/ql/test/library-tests/dispatch/viaSummary.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/test/library-tests/dispatch/viaSummary.ql b/java/ql/test/library-tests/dispatch/viaSummary.ql index c421e1c9904..a7a88d0749d 100644 --- a/java/ql/test/library-tests/dispatch/viaSummary.ql +++ b/java/ql/test/library-tests/dispatch/viaSummary.ql @@ -5,5 +5,5 @@ from MethodAccess ma, Method m where m = viableImpl(ma) and m.fromSource() and - ma.getFile().toString().matches("CallableViaSummary") + ma.getFile().toString() = "CallableViaSummary" select ma, m From 5c9b0b9b76552929c283e539553dd75f38a053b8 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Wed, 7 Jun 2023 09:49:23 +0200 Subject: [PATCH 169/219] C#: Address review comments. --- .../integration-tests/posix-only/dotnet_test/test.py | 2 +- csharp/tools/tracing-config.lua | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test/test.py b/csharp/ql/integration-tests/posix-only/dotnet_test/test.py index 1012454003b..f69d01b2188 100644 --- a/csharp/ql/integration-tests/posix-only/dotnet_test/test.py +++ b/csharp/ql/integration-tests/posix-only/dotnet_test/test.py @@ -7,4 +7,4 @@ check_diagnostics() # Explicitly build and then run tests. run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout', 'dotnet test myout/dotnet_test.dll'], test_db="test2-db", lang="csharp") -check_diagnostics(test_db="test2-db") \ No newline at end of file +check_diagnostics(test_db="test2-db") diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 7fa03af2de1..5ba1a078079 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -21,9 +21,9 @@ function RegisterExtractorPack(id) -- if that's `build`, we append `-p:UseSharedCompilation=false` to the command line, -- otherwise we do nothing. local match = false + local testMatch = false; local dotnetRunNeedsSeparator = false; local dotnetRunInjectionIndex = nil; - local libOrExe = false; local argv = compilerArguments.argv if OperatingSystem == 'windows' then -- let's hope that this split matches the escaping rules `dotnet` applies to command line arguments @@ -35,7 +35,7 @@ function RegisterExtractorPack(id) -- dotnet options start with either - or / (both are legal) local firstCharacter = string.sub(arg, 1, 1) if not (firstCharacter == '-') and not (firstCharacter == '/') then - if (not match) then + if (not match and not testMatch) then Log(1, 'Dotnet subcommand detected: %s', arg) end if arg == 'build' or arg == 'msbuild' or arg == 'publish' or arg == 'pack' then @@ -50,12 +50,12 @@ function RegisterExtractorPack(id) dotnetRunInjectionIndex = i + 1 end if arg == 'test' then - match = true + testMatch = true end -- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line -- if a library or executable is being provided as an argument. - if arg:match('%.exe$') or arg:match('%.dll') then - libOrExe = true + if testMatch and (arg:match('%.exe$') or arg:match('%.dll')) then + testMatch = false end end -- if we see a separator to `dotnet run`, inject just prior to the existing separator @@ -71,7 +71,7 @@ function RegisterExtractorPack(id) dotnetRunInjectionIndex = i end end - if match and not libOrExe then + if match or testMatch then local injections = { '-p:UseSharedCompilation=false', '-p:EmitCompilerGeneratedFiles=true' } if dotnetRunNeedsSeparator then table.insert(injections, '--') From 3eb3178ba5d045a4b39e65a8f8948d2b10c01e62 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Wed, 7 Jun 2023 10:10:51 +0200 Subject: [PATCH 170/219] C#: Add change note. --- csharp/ql/lib/change-notes/2023-06-06-dotnettest.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-06-06-dotnettest.md diff --git a/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md b/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md new file mode 100644 index 00000000000..8e04877da1e --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C#: Update the LUA tracer such that `-p:SharedCompilation=false` is not injected when `dotnet test` is applied to a `dll` or `exe` file. \ No newline at end of file From d4d571e43569d281b01bb797f871a952f9cbe984 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Wed, 7 Jun 2023 12:44:36 +0200 Subject: [PATCH 171/219] C#: Better change note. Co-authored-by: Michael B. Gale <mbg@github.com> --- csharp/ql/lib/change-notes/2023-06-06-dotnettest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md b/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md index 8e04877da1e..e7179b93189 100644 --- a/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md +++ b/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* C#: Update the LUA tracer such that `-p:SharedCompilation=false` is not injected when `dotnet test` is applied to a `dll` or `exe` file. \ No newline at end of file +* C#: Analysis of the `dotnet test` command supplied with a `dll` or `exe` file as argument no longer fails due to the addition of an erroneous `-p:SharedCompilation=false` argument. \ No newline at end of file From d6ac5cdc9446a48a0c53bbdc8c7c67b969b77b22 Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Wed, 7 Jun 2023 12:39:00 +0100 Subject: [PATCH 172/219] Kotlin: Remove kotlin-explorer This was an exploration tool that I don't think has been used for some time. --- .github/labeler.yml | 3 +- CODEOWNERS | 1 - java/kotlin-explorer/.gitignore | 10 - java/kotlin-explorer/README | 9 - java/kotlin-explorer/build.gradle | 28 --- java/kotlin-explorer/gradle.properties | 7 - java/kotlin-explorer/settings.gradle | 8 - .../src/main/kotlin/Explorer.kt | 217 ------------------ 8 files changed, 1 insertion(+), 282 deletions(-) delete mode 100644 java/kotlin-explorer/.gitignore delete mode 100644 java/kotlin-explorer/README delete mode 100644 java/kotlin-explorer/build.gradle delete mode 100644 java/kotlin-explorer/gradle.properties delete mode 100644 java/kotlin-explorer/settings.gradle delete mode 100644 java/kotlin-explorer/src/main/kotlin/Explorer.kt diff --git a/.github/labeler.yml b/.github/labeler.yml index 503833fc4d7..5401e6afd71 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -11,7 +11,7 @@ Go: - change-notes/**/*go.* Java: - - any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/kotlin-explorer/**/*', '!java/ql/test/kotlin/**/*' ] + - any: [ 'java/**/*', '!java/kotlin-extractor/**/*', '!java/ql/test/kotlin/**/*' ] - change-notes/**/*java.* JS: @@ -20,7 +20,6 @@ JS: Kotlin: - java/kotlin-extractor/**/* - - java/kotlin-explorer/**/* - java/ql/test/kotlin/**/* Python: diff --git a/CODEOWNERS b/CODEOWNERS index 6e2dd9dc66b..b2eb53f0bb0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,7 +8,6 @@ /swift/ @github/codeql-swift /misc/codegen/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin -/java/kotlin-explorer/ @github/codeql-kotlin # ML-powered queries /javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers diff --git a/java/kotlin-explorer/.gitignore b/java/kotlin-explorer/.gitignore deleted file mode 100644 index 9c076360bbb..00000000000 --- a/java/kotlin-explorer/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.classpath -.gradle -.idea -.project -.settings -bin/ -build/ -gradle/ -gradlew -gradlew.bat diff --git a/java/kotlin-explorer/README b/java/kotlin-explorer/README deleted file mode 100644 index 0f500d7c25b..00000000000 --- a/java/kotlin-explorer/README +++ /dev/null @@ -1,9 +0,0 @@ - -This shows what is encoded in the kotlin.Metadata section shown in the -output of `javap -v SomeKotlinClass`. - -It is not currently able to extract the information from .class files -itself; the values are hard coded in src/main/kotlin/Explorer.kt - -Run `gradle run` in this directory to run it. - diff --git a/java/kotlin-explorer/build.gradle b/java/kotlin-explorer/build.gradle deleted file mode 100644 index b122d811d4f..00000000000 --- a/java/kotlin-explorer/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -plugins { - id 'org.jetbrains.kotlin.jvm' version "${kotlinVersion}" - id 'org.jetbrains.dokka' version '1.4.32' - id "com.vanniktech.maven.publish" version '0.15.1' - id 'application' -} - -group 'com.github.codeql' -version '0.0.1' - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib" - implementation "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.3.0" -} - -repositories { - mavenCentral() -} - -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = "1.8" - } -} - -application { - mainClass = 'com.github.codeql.ExplorerKt' -} diff --git a/java/kotlin-explorer/gradle.properties b/java/kotlin-explorer/gradle.properties deleted file mode 100644 index 0854241bcda..00000000000 --- a/java/kotlin-explorer/gradle.properties +++ /dev/null @@ -1,7 +0,0 @@ -kotlin.code.style=official -kotlinVersion=1.5.21 - -GROUP=com.github.codeql -VERSION_NAME=0.0.1 -POM_DESCRIPTION=CodeQL Kotlin explorer - diff --git a/java/kotlin-explorer/settings.gradle b/java/kotlin-explorer/settings.gradle deleted file mode 100644 index 18f679f7b75..00000000000 --- a/java/kotlin-explorer/settings.gradle +++ /dev/null @@ -1,8 +0,0 @@ -pluginManagement { - repositories { - mavenCentral() - gradlePluginPortal() - } -} - -rootProject.name = 'codeql-kotlin-explorer' diff --git a/java/kotlin-explorer/src/main/kotlin/Explorer.kt b/java/kotlin-explorer/src/main/kotlin/Explorer.kt deleted file mode 100644 index 31c3eb18dcb..00000000000 --- a/java/kotlin-explorer/src/main/kotlin/Explorer.kt +++ /dev/null @@ -1,217 +0,0 @@ -package com.github.codeql -import kotlinx.metadata.internal.metadata.jvm.deserialization.JvmMetadataVersion -import kotlinx.metadata.jvm.* -import kotlinx.metadata.* - -fun main(args : Array<String>) { - /* - Values from `javap -v` on TestKt.class from: - - class MyClass {} - - class MyParamClass<T> {} - - fun f(x: MyClass, y: MyClass?, - l1: MyParamClass<MyClass>, - l2: MyParamClass<MyClass?>, - l3: MyParamClass<MyClass>?, - l4: MyParamClass<MyClass?>?) { - } - */ - val kind = 2 - val metadataVersion = intArrayOf(1, 5, 1) - val data1 = arrayOf("\u0000\u0018\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0003\u001aX\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00032\b\u0010\u0004\u001a\u0004\u0018\u00010\u00032\u000c\u0010\u0005\u001a\b\u0012\u0004\u0012\u00020\u00030\u00062\u000e\u0010\u0007\u001a\n\u0012\u0006\u0012\u0004\u0018\u00010\u00030\u00062\u000e\u0010\b\u001a\n\u0012\u0004\u0012\u00020\u0003\u0018\u00010\u00062\u0010\u0010\t\u001a\u000c\u0012\u0006\u0012\u0004\u0018\u00010\u0003\u0018\u00010\u0006") - val data2 = arrayOf("f","","x","LMyClass;","y","l1","LMyParamClass;","l2","l3","l4") - val extraString = null - val packageName = null - val extraInt = 48 - val kch = KotlinClassHeader(kind, metadataVersion, data1, data2, extraString, packageName, extraInt) - - val md = KotlinClassMetadata.read(kch) - when (md) { - is KotlinClassMetadata.Class -> println("Metadata for Class not yet supported") - is KotlinClassMetadata.FileFacade -> { - println("Metadata for FileFacade:") - val kmp = md.toKmPackage() - kmp.accept(MyPackageVisitor(0)) - } - is KotlinClassMetadata.SyntheticClass -> println("Metadata for SyntheticClass not yet supported") - is KotlinClassMetadata.MultiFileClassFacade -> println("Metadata for MultiFileClassFacade not yet supported") - is KotlinClassMetadata.MultiFileClassPart -> println("Metadata for MultiFileClassPart not yet supported") - is KotlinClassMetadata.Unknown -> println("Unknown kind") - else -> println("Unexpected kind") - } -} - -fun pr(indent: Int, s: String) { - println(" ".repeat(indent) + s) -} - -class MyPackageVisitor(val indent: Int): KmPackageVisitor() { - override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? { - pr(indent, "=> Function; flags:$flags, name:$name") - return MyFunctionVisitor(indent + 1) - } - - override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? { - pr(indent, "=> Properties not yet handled") - return null - } - - override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? { - pr(indent, "=> Type aliases not yet handled") - return null - } - - override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? { - pr(indent, "=> Package extensions; type:$type") - when (type) { - JvmPackageExtensionVisitor.TYPE -> return MyJvmPackageExtensionVisitor(indent + 1) - else -> { - pr(indent, "- Not yet handled") - return null - } - } - } -} - -class MyFunctionVisitor(val indent: Int): KmFunctionVisitor() { - override fun visitTypeParameter(flags: Flags, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? { - pr(indent, "=> Type parameter; flags:$flags, name:$name, id:$id, variance:$variance") - pr(indent, " -> Not yet handled") - return null - } - override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> Receiver parameter type; flags:$flags") - pr(indent, " -> Not yet handled") - return null - } - - override fun visitValueParameter(flags: Flags, name: String): KmValueParameterVisitor? { - pr(indent, "=> Value parameter; flags:$flags, name:$name") - return MyValueParameterVisitor(indent + 1) - } - - override fun visitReturnType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> Return type; flags:$flags") - return MyTypeVisitor(indent + 1) - } - - override fun visitVersionRequirement(): KmVersionRequirementVisitor? { - pr(indent, "=> VersionRequirement not yet handled") - return null - } - - override fun visitContract(): KmContractVisitor? { - pr(indent, "=> Contract not yet handled") - return null - } - - override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? { - pr(indent, "=> Function extensions; type:$type") - when (type) { - JvmFunctionExtensionVisitor.TYPE -> return MyJvmFunctionExtensionVisitor(indent + 1) - else -> { - pr(indent, "- Not yet handled") - return null - } - } - } -} - -class MyValueParameterVisitor(val indent: Int): KmValueParameterVisitor() { - override fun visitType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> Type; flags:$flags") - return MyTypeVisitor(indent + 1) - } - - override fun visitVarargElementType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> VarargElementType not yet handled") - return null - } - - override fun visitExtensions(type: KmExtensionType): KmValueParameterExtensionVisitor? { - pr(indent, "=> Value parameter extensions; type:$type; not yet handled") - return null - } -} - -class MyTypeVisitor(val indent: Int): KmTypeVisitor() { - override fun visitClass(name: ClassName) { - pr(indent, "=> Class; name:$name") - } - - override fun visitTypeAlias(name: ClassName) { - pr(indent, "=> Type alias; name:$name") - } - - override fun visitTypeParameter(id: Int) { - pr(indent, "=> Type parameter; id:$id") - } - - override fun visitArgument(flags: Flags, variance: KmVariance): KmTypeVisitor? { - pr(indent, "=> Argument; flags:$flags, variance:$variance") - return MyTypeVisitor(indent + 1) - } - - override fun visitStarProjection() { - pr(indent, "=> Star projection") - } - - override fun visitAbbreviatedType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> AbbreviatedType not yet handled") - return null - } - - override fun visitOuterType(flags: Flags): KmTypeVisitor? { - pr(indent, "=> OuterType not yet handled") - return null - } - - override fun visitFlexibleTypeUpperBound(flags: Flags, typeFlexibilityId: String?): KmTypeVisitor? { - pr(indent, "=> FlexibleTypeUpperBound not yet handled") - return null - } - - override fun visitExtensions(type: KmExtensionType): KmTypeExtensionVisitor? { - pr(indent, "=> Type extensions; type:$type") - when (type) { - JvmTypeExtensionVisitor.TYPE -> return MyJvmTypeExtensionVisitor(indent + 1) - else -> { - pr(indent, "- Not yet handled") - return null - } - } - } -} - -class MyJvmTypeExtensionVisitor(val indent: Int): JvmTypeExtensionVisitor() { - override fun visit(isRaw: Boolean) { - pr(indent, "=> isRaw:$isRaw") - } - - override fun visitAnnotation(annotation: KmAnnotation) { - pr(indent, "=> Annotation; annotation:$annotation") - } -} - -class MyJvmPackageExtensionVisitor(val indent: Int): JvmPackageExtensionVisitor() { - override fun visitLocalDelegatedProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? { - pr(indent, "=> Local delegate not yet handled") - return null - } - - override fun visitModuleName(name: String) { - pr(indent, "=> Module name; name:$name") - } -} - -class MyJvmFunctionExtensionVisitor(val indent: Int): JvmFunctionExtensionVisitor() { - override fun visit(signature: JvmMethodSignature?) { - pr(indent, "=> signature:$signature") - } - - override fun visitLambdaClassOriginName(internalName: String) { - pr(indent, "=> LambdaClassOriginName; internalName:$internalName") - } -} From 35b4c438ff09bd431858bc166121007bae933cca Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 14:12:20 +0200 Subject: [PATCH 173/219] Fix Gson's JsonArray.add models When the type of the argument isn't JsonElement, the summary must be taint flow instead of value flow --- java/ql/lib/ext/com.google.gson.model.yml | 7 +++++- .../library-tests/frameworks/gson/Test.java | 24 +++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/java/ql/lib/ext/com.google.gson.model.yml b/java/ql/lib/ext/com.google.gson.model.yml index 96f5355b2dc..73e14cf7cc8 100644 --- a/java/ql/lib/ext/com.google.gson.model.yml +++ b/java/ql/lib/ext/com.google.gson.model.yml @@ -26,7 +26,12 @@ extensions: - ["com.google.gson", "JsonElement", True, "getAsJsonPrimitive", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["com.google.gson", "JsonElement", True, "getAsString", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["com.google.gson", "JsonElement", True, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - - ["com.google.gson", "JsonArray", True, "add", "", "", "Argument[0]", "Argument[this].Element", "value", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(Boolean)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(Character)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(JsonElement)", "", "Argument[0]", "Argument[this].Element", "value", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(Number)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(String)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] + - ["com.google.gson", "JsonArray", True, "add", "(JsonArray)", "", "Argument[0].Element", "Argument[this].Element", "value", "manual"] - ["com.google.gson", "JsonArray", True, "asList", "", "", "Argument[this].Element", "ReturnValue.Element", "value", "manual"] - ["com.google.gson", "JsonArray", True, "get", "", "", "Argument[this].Element", "ReturnValue", "value", "manual"] - ["com.google.gson", "JsonArray", True, "set", "", "", "Argument[1]", "Argument[this].Element", "value", "manual"] diff --git a/java/ql/test/library-tests/frameworks/gson/Test.java b/java/ql/test/library-tests/frameworks/gson/Test.java index eb3e1e526f0..00811587e8b 100644 --- a/java/ql/test/library-tests/frameworks/gson/Test.java +++ b/java/ql/test/library-tests/frameworks/gson/Test.java @@ -25,7 +25,7 @@ public class Test { <K> K getMapKeyDefault(Map.Entry<K,?> container) { return container.getKey(); } JsonElement getMapValueDefault(JsonObject container) { return container.get(null); } <V> V getMapValueDefault(Map.Entry<?,V> container) { return container.getValue(); } - JsonArray newWithElementDefault(String element) { JsonArray a = new JsonArray(); a.add(element); return a; } + JsonArray newWithElementDefault(JsonElement element) { JsonArray a = new JsonArray(); a.add(element); return a; } JsonObject newWithMapKeyDefault(String key) { JsonObject o = new JsonObject(); o.add(key, (JsonElement) null); return o; } JsonObject newWithMapValueDefault(JsonElement element) { JsonObject o = new JsonObject(); o.add(null, element); return o; } Object source() { return null; } @@ -232,51 +232,51 @@ public class Test { sink(out); // $ hasTaintFlow } { - // "com.google.gson;JsonArray;true;add;;;Argument[0];Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(Boolean);;Argument[0];Argument[this].Element;taint;manual" JsonArray out = null; Boolean in = (Boolean)source(); out.add(in); - sink(getElement(out)); // $ hasValueFlow + sink(getElement(out)); // $ hasTaintFlow } { - // "com.google.gson;JsonArray;true;add;;;Argument[0];Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(Character);;Argument[0];Argument[this].Element;taint;manual" JsonArray out = null; Character in = (Character)source(); out.add(in); - sink(getElement(out)); // $ hasValueFlow + sink(getElement(out)); // $ hasTaintFlow } { - // "com.google.gson;JsonArray;true;add;;;Argument[0];Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(JsonElement);;Argument[0];Argument[this].Element;value;manual" JsonArray out = null; JsonElement in = (JsonElement)source(); out.add(in); sink(getElement(out)); // $ hasValueFlow } { - // "com.google.gson;JsonArray;true;add;;;Argument[0];Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(Number);;Argument[0];Argument[this].Element;taint;manual" JsonArray out = null; Number in = (Number)source(); out.add(in); - sink(getElement(out)); // $ hasValueFlow + sink(getElement(out)); // $ hasTaintFlow } { - // "com.google.gson;JsonArray;true;add;;;Argument[0];Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(JsonArray);;Argument[0].Element;Argument[this].Element;value;manual" JsonArray out = null; - String in = (String)source(); + JsonElement in = (JsonElement)source(); out.add(in); sink(getElement(out)); // $ hasValueFlow } { // "com.google.gson;JsonArray;true;asList;;;Argument[this].Element;ReturnValue.Element;value;manual" List out = null; - JsonArray in = (JsonArray)newWithElementDefault((String) source()); + JsonArray in = (JsonArray)newWithElementDefault((JsonElement) source()); out = in.asList(); sink(getElement(out)); // $ hasValueFlow } { // "com.google.gson;JsonArray;true;get;;;Argument[this].Element;ReturnValue;value;manual" JsonElement out = null; - JsonArray in = (JsonArray)newWithElementDefault((String) source()); + JsonArray in = (JsonArray)newWithElementDefault((JsonElement) source()); out = in.get(0); sink(out); // $ hasValueFlow } From f9c890be3548a0e4eb25b75fa5aedbf2b00a9c54 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Wed, 7 Jun 2023 14:49:04 +0200 Subject: [PATCH 174/219] C#: Address review comments. --- csharp/tools/tracing-config.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 5ba1a078079..49044226da3 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -21,7 +21,6 @@ function RegisterExtractorPack(id) -- if that's `build`, we append `-p:UseSharedCompilation=false` to the command line, -- otherwise we do nothing. local match = false - local testMatch = false; local dotnetRunNeedsSeparator = false; local dotnetRunInjectionIndex = nil; local argv = compilerArguments.argv @@ -35,7 +34,7 @@ function RegisterExtractorPack(id) -- dotnet options start with either - or / (both are legal) local firstCharacter = string.sub(arg, 1, 1) if not (firstCharacter == '-') and not (firstCharacter == '/') then - if (not match and not testMatch) then + if (not match) then Log(1, 'Dotnet subcommand detected: %s', arg) end if arg == 'build' or arg == 'msbuild' or arg == 'publish' or arg == 'pack' then @@ -50,12 +49,13 @@ function RegisterExtractorPack(id) dotnetRunInjectionIndex = i + 1 end if arg == 'test' then - testMatch = true + match = true end - -- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line + -- for `dotnet [test|run]`, we should not append `-p:UseSharedCompilation=false` to the command line -- if a library or executable is being provided as an argument. - if testMatch and (arg:match('%.exe$') or arg:match('%.dll')) then - testMatch = false + if arg:match('%.exe$') or arg:match('%.dll') then + match = false + break end end -- if we see a separator to `dotnet run`, inject just prior to the existing separator @@ -71,7 +71,7 @@ function RegisterExtractorPack(id) dotnetRunInjectionIndex = i end end - if match or testMatch then + if match then local injections = { '-p:UseSharedCompilation=false', '-p:EmitCompilerGeneratedFiles=true' } if dotnetRunNeedsSeparator then table.insert(injections, '--') From c0135673fac4bf62bef7da411eef2b10ad51d696 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:18:32 +0200 Subject: [PATCH 175/219] Fix JsonArray.addAll model Properly test JsonArray.add(String) and JsonArray.addAll(JsonArray) as well --- java/ql/lib/ext/com.google.gson.model.yml | 2 +- .../test/library-tests/frameworks/gson/Test.java | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/java/ql/lib/ext/com.google.gson.model.yml b/java/ql/lib/ext/com.google.gson.model.yml index 73e14cf7cc8..7b41b57083a 100644 --- a/java/ql/lib/ext/com.google.gson.model.yml +++ b/java/ql/lib/ext/com.google.gson.model.yml @@ -31,7 +31,7 @@ extensions: - ["com.google.gson", "JsonArray", True, "add", "(JsonElement)", "", "Argument[0]", "Argument[this].Element", "value", "manual"] - ["com.google.gson", "JsonArray", True, "add", "(Number)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] - ["com.google.gson", "JsonArray", True, "add", "(String)", "", "Argument[0]", "Argument[this].Element", "taint", "manual"] - - ["com.google.gson", "JsonArray", True, "add", "(JsonArray)", "", "Argument[0].Element", "Argument[this].Element", "value", "manual"] + - ["com.google.gson", "JsonArray", True, "addAll", "(JsonArray)", "", "Argument[0].Element", "Argument[this].Element", "value", "manual"] - ["com.google.gson", "JsonArray", True, "asList", "", "", "Argument[this].Element", "ReturnValue.Element", "value", "manual"] - ["com.google.gson", "JsonArray", True, "get", "", "", "Argument[this].Element", "ReturnValue", "value", "manual"] - ["com.google.gson", "JsonArray", True, "set", "", "", "Argument[1]", "Argument[this].Element", "value", "manual"] diff --git a/java/ql/test/library-tests/frameworks/gson/Test.java b/java/ql/test/library-tests/frameworks/gson/Test.java index 00811587e8b..6fa1fd2a1e5 100644 --- a/java/ql/test/library-tests/frameworks/gson/Test.java +++ b/java/ql/test/library-tests/frameworks/gson/Test.java @@ -260,23 +260,30 @@ public class Test { sink(getElement(out)); // $ hasTaintFlow } { - // "com.google.gson;JsonArray;true;add;(JsonArray);;Argument[0].Element;Argument[this].Element;value;manual" + // "com.google.gson;JsonArray;true;add;(String);;Argument[0];Argument[this].Element;taint;manual" JsonArray out = null; - JsonElement in = (JsonElement)source(); + String in = (String)source(); out.add(in); + sink(getElement(out)); // $ hasTaintFlow + } + { + // "com.google.gson;JsonArray;true;addAll;(JsonArray);;Argument[0].Element;Argument[this].Element;value;manual" + JsonArray out = null; + JsonArray in = newWithElementDefault((JsonElement) source()); + out.addAll(in); sink(getElement(out)); // $ hasValueFlow } { // "com.google.gson;JsonArray;true;asList;;;Argument[this].Element;ReturnValue.Element;value;manual" List out = null; - JsonArray in = (JsonArray)newWithElementDefault((JsonElement) source()); + JsonArray in = newWithElementDefault((JsonElement) source()); out = in.asList(); sink(getElement(out)); // $ hasValueFlow } { // "com.google.gson;JsonArray;true;get;;;Argument[this].Element;ReturnValue;value;manual" JsonElement out = null; - JsonArray in = (JsonArray)newWithElementDefault((JsonElement) source()); + JsonArray in = newWithElementDefault((JsonElement) source()); out = in.get(0); sink(out); // $ hasValueFlow } From 69854638b6fb5f333ccafc2785f26ae87ef6edba Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Wed, 7 Jun 2023 15:51:21 +0100 Subject: [PATCH 176/219] Add Go version table for --identify-environment --- go/extractor/cli/go-autobuilder/go-autobuilder.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go index 9fcad68d42a..f7fc575d0c1 100644 --- a/go/extractor/cli/go-autobuilder/go-autobuilder.go +++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go @@ -910,6 +910,17 @@ func getVersionWhenGoModVersionSupported(v versionInfo) (msg, version string) { // Check the versions of Go found in the environment and in the `go.mod` file, and return a // version to install. If the version is the empty string then no installation is required. +// We never return a version of Go that is outside of the supported range. +// +// +-----------------------+-----------------------+-----------------------+-----------------------------------------------------+------------------------------------------------+ +// | Found in go.mod > | *None* | *Below min supported* | *In supported range* | *Above max supported | +// | Installed \/ | | | | | +// |-----------------------|-----------------------|-----------------------|-----------------------------------------------------|------------------------------------------------| +// | *None* | Install max supported | Install min supported | Install version from go.mod | Install max supported | +// | *Below min supported* | Install max supported | Install min supported | Install version from go.mod | Install max supported | +// | *In supported range* | No action | No action | Install version from go.mod if newer than installed | Install max supported if newer than installed | +// | *Above max supported* | Install max supported | Install min supported | Install version from go.mod | No action | +// +-----------------------+-----------------------+-----------------------+-----------------------------------------------------+------------------------------------------------+ func getVersionToInstall(v versionInfo) (msg, version string) { if !v.goModVersionFound { return getVersionWhenGoModVersionNotFound(v) From 19e1bab10245836ab79f80f639bb2ee131b6eeb4 Mon Sep 17 00:00:00 2001 From: Taus <tausbn@github.com> Date: Wed, 7 Jun 2023 15:26:52 +0000 Subject: [PATCH 177/219] Python: Update expected output for syntax error queries --- .../2/query-tests/Imports/syntax_error/SyntaxError.expected | 2 +- .../3/query-tests/Imports/syntax_error/SyntaxError.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.expected b/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.expected index 7fc3fd5d706..b645e2ef286 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.expected +++ b/python/ql/test/2/query-tests/Imports/syntax_error/SyntaxError.expected @@ -1 +1 @@ -| nonsense.py:0:1:0:1 | Syntax Error | Syntax Error (in Python 2). | +| nonsense.py:1:1:1:1 | Syntax Error | Syntax Error (in Python 2). | diff --git a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected index 2f8b8b32ce1..480891f7381 100644 --- a/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected +++ b/python/ql/test/3/query-tests/Imports/syntax_error/SyntaxError.expected @@ -1 +1 @@ -| nonsense.py:0:1:0:1 | Syntax Error | Syntax Error (in Python 3). | +| nonsense.py:1:2:1:2 | Syntax Error | Syntax Error (in Python 3). | From 0efa212c4077564a9545d7c6a6dd5c16e795c619 Mon Sep 17 00:00:00 2001 From: Arthur Baars <aibaars@github.com> Date: Wed, 7 Jun 2023 19:27:46 +0200 Subject: [PATCH 178/219] Ruby: update tree-sitter-ruby --- ruby/extractor/Cargo.lock | Bin 31065 -> 31065 bytes ruby/extractor/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/extractor/Cargo.lock b/ruby/extractor/Cargo.lock index 85c546b9b96e189aae02de3062127274df104d7b..f048f2d7725d8d6e8b86e41a63b538afe657ba31 100644 GIT binary patch delta 99 zcmccliSgzq#tkc?0?bX)Qc_J*P1BN$l9Eg<%`FlWQ&Y_?EKLn9EK-vUEiKc`(-M=@ S43vpfIQgJ}_-6iSFF63U^dL9@ delta 100 zcmccliSgzq#tkc?0*wsJlFbdw%?-^=jLnUbO)bsR(h@CF6BARCEKQ6}lZ`AaO$?3A SOq7XLIQgQe*k=A{FF61&_#I6E diff --git a/ruby/extractor/Cargo.toml b/ruby/extractor/Cargo.toml index 133233f2f14..6857162af5e 100644 --- a/ruby/extractor/Cargo.toml +++ b/ruby/extractor/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" [dependencies] tree-sitter = "0.20" tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "203f7bd3c1bbfbd98fc19add4b8fcb213c059205" } -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "206c7077164372c596ffa8eaadb9435c28941364" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "74fde5e5fb2bb5978aaee7895188eb199f7facf0" } clap = { version = "4.2", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } From cbbd885e229823ad50aa77e554bb2078a955dce7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 00:17:14 +0000 Subject: [PATCH 179/219] Add changed framework coverage reports --- .../documentation/library-coverage/coverage.csv | 17 ++++++++++++----- .../documentation/library-coverage/coverage.rst | 8 ++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 0e429b40b52..93c93f8ef46 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -12,10 +12,11 @@ androidx.core.app,6,,95,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,12,83 androidx.fragment.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, androidx.slice,2,5,88,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,5,,27,61 cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.alibaba.druid.sql,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +com.fasterxml.jackson.databind,2,,6,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,6, com.google.common.base,4,,87,,,,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,63,24 com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 @@ -23,6 +24,7 @@ com.google.common.flogger,29,,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,, com.google.common.io,8,,73,,1,,,,,,,,,,,,,,7,,,,,,,,,,,,,,,,,,,72,1 com.google.gson,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,14 com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, +com.jcraft.jsch,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,1, com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,, com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, @@ -41,7 +43,7 @@ io.netty.bootstrap,3,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,, io.netty.buffer,,,207,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,130,77 io.netty.channel,9,2,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,2,, io.netty.handler.codec,4,13,259,,,,,,,,,,,,,,,,1,,,,,,,,,3,,,,,,,,,13,143,116 -io.netty.handler.ssl,2,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,, +io.netty.handler.ssl,4,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,, io.netty.handler.stream,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, io.netty.resolver,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, io.netty.util,2,,23,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,,,,,,,21,2 @@ -52,10 +54,10 @@ jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,94,55 java.awt,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3 java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -java.io,44,,45,,22,,,,,,,,,,,,,,22,,,,,,,,,,,,,,,,,,,43,2 +java.io,49,,45,,22,,,,,,,,,,,,,,27,,,,,,,,,,,,,,,,,,,43,2 java.lang,18,,92,,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 java.net,13,3,20,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,20, -java.nio,40,,35,,3,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,,,35, +java.nio,47,,35,,3,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,35, java.sql,13,,3,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2,1 java.util,44,,484,,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,44,440 javafx.scene.web,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, @@ -78,7 +80,8 @@ jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 kotlin,16,,1847,,,,,,,,,,,,,,,,14,,,,,,,,,2,,,,,,,,,,1836,11 net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,, ognl,6,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,, -okhttp3,4,,47,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,22,25 +okhttp3,4,,48,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,23,25 +org.antlr.runtime,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 @@ -119,8 +122,10 @@ org.codehaus.cargo.container.installer,3,,,,,,,,,,,,,,,,,,2,,,,,,,,,1,,,,,,,,,,, org.codehaus.groovy.control,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,, org.eclipse.jetty.client,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, +org.fusesource.leveldbjni,1,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, org.geogebra.web.full.main,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,, org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,, +org.influxdb,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, org.jboss.logging,324,,,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,, org.jdbi.v3.core,6,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,, org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,, @@ -134,6 +139,7 @@ org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 org.springframework.boot.jdbc,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +org.springframework.core.io,2,,,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,,,,,,,, org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 org.springframework.http,14,,71,,,,,,,,,,,,,,,,,,,,,,,,,14,,,,,,,,,,61,10 org.springframework.jdbc.core,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,, @@ -153,6 +159,7 @@ org.springframework.web.util,,,165,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,140,25 org.thymeleaf,2,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,2, org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, +org.yaml.snakeyaml,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, play.libs.ws,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, play.mvc,,13,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,24, ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index 55b9a0a071d..ffd3ce0ed91 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -18,10 +18,10 @@ Java framework & library support `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,41,7,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,, `JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,, - Java Standard Library,``java.*``,3,683,172,64,,9,,,17 + Java Standard Library,``java.*``,3,683,184,76,,9,,,17 Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 - `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,113,3,,28,14,,34 - Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,890,520,60,,18,18,,193 - Totals,,255,9190,1975,244,10,122,33,1,382 + `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,115,4,,28,14,,35 + Others,"``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,894,528,66,,18,18,,195 + Totals,,255,9194,1997,263,10,122,33,1,385 From 65e651506ce0291c9e42dd936c4c3a43e76a74a5 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Thu, 8 Jun 2023 08:51:21 +0200 Subject: [PATCH 180/219] C#: Address review comments. --- csharp/tools/tracing-config.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/csharp/tools/tracing-config.lua b/csharp/tools/tracing-config.lua index 49044226da3..f04169caff5 100644 --- a/csharp/tools/tracing-config.lua +++ b/csharp/tools/tracing-config.lua @@ -21,6 +21,7 @@ function RegisterExtractorPack(id) -- if that's `build`, we append `-p:UseSharedCompilation=false` to the command line, -- otherwise we do nothing. local match = false + local testMatch = false local dotnetRunNeedsSeparator = false; local dotnetRunInjectionIndex = nil; local argv = compilerArguments.argv @@ -50,10 +51,11 @@ function RegisterExtractorPack(id) end if arg == 'test' then match = true + testMatch = true end - -- for `dotnet [test|run]`, we should not append `-p:UseSharedCompilation=false` to the command line - -- if a library or executable is being provided as an argument. - if arg:match('%.exe$') or arg:match('%.dll') then + -- for `dotnet test`, we should not append `-p:UseSharedCompilation=false` to the command line + -- if an `exe` or `dll` is passed as an argument as the call is forwarded to vstest. + if testMatch and (arg:match('%.exe$') or arg:match('%.dll')) then match = false break end From 2fece9d72148593f39a770c5660ddd1f93bb1c44 Mon Sep 17 00:00:00 2001 From: Michael Nebel <michaelnebel@github.com> Date: Thu, 8 Jun 2023 09:58:52 +0200 Subject: [PATCH 181/219] C#: Add MSTEST test project and check that the call to vstest doesn't get the UseSharedCompilation=false flag forwarded. --- .../dotnet_test_mstest/UnitTest1.cs | 10 ++++++++++ .../posix-only/dotnet_test_mstest/Usings.cs | 1 + .../dotnet_test_mstest.csproj | 19 +++++++++++++++++++ .../posix-only/dotnet_test_mstest/test.py | 10 ++++++++++ 4 files changed, 40 insertions(+) create mode 100644 csharp/ql/integration-tests/posix-only/dotnet_test_mstest/UnitTest1.cs create mode 100644 csharp/ql/integration-tests/posix-only/dotnet_test_mstest/Usings.cs create mode 100644 csharp/ql/integration-tests/posix-only/dotnet_test_mstest/dotnet_test_mstest.csproj create mode 100644 csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/UnitTest1.cs b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/UnitTest1.cs new file mode 100644 index 00000000000..7e3b2ce1d1c --- /dev/null +++ b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace dotnet_test_mstest; + +[TestClass] +public class UnitTest1 +{ + [TestMethod] + public void TestMethod1() + { + } +} diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/Usings.cs b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/Usings.cs new file mode 100644 index 00000000000..540383dcf43 --- /dev/null +++ b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/dotnet_test_mstest.csproj b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/dotnet_test_mstest.csproj new file mode 100644 index 00000000000..95c7586e04e --- /dev/null +++ b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/dotnet_test_mstest.csproj @@ -0,0 +1,19 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net7.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + + <IsPackable>false</IsPackable> + <OutputType>Exe</OutputType> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" /> + <PackageReference Include="MSTest.TestAdapter" Version="2.2.10" /> + <PackageReference Include="MSTest.TestFramework" Version="2.2.10" /> + <PackageReference Include="coverlet.collector" Version="3.1.2" /> + </ItemGroup> + +</Project> diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py new file mode 100644 index 00000000000..345d26a1516 --- /dev/null +++ b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py @@ -0,0 +1,10 @@ +from create_database_utils import * +from diagnostics_test_utils import * + +# Implicitly build and then run tests. +run_codeql_database_create(['dotnet test'], test_db="test-db", lang="csharp") +check_diagnostics() + +# Explicitly build and then run tests. +run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout --os win', 'dotnet test myout/dotnet_test_mstest.exe'], test_db="test2-db", lang="csharp") +check_diagnostics(test_db="test2-db") From a4ef8619c68bb28b7ad006cda1530c52e6d5ba8a Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 09:44:30 +0200 Subject: [PATCH 182/219] delete old deprecations --- cpp/ql/lib/semmle/code/cpp/Class.qll | 14 - cpp/ql/lib/semmle/code/cpp/File.qll | 20 - cpp/ql/lib/semmle/code/cpp/PrintAST.qll | 12 - .../lib/semmle/code/cpp/controlflow/SSA.qll | 3 - .../semmle/code/cpp/controlflow/SSAUtils.qll | 3 - .../code/cpp/controlflow/internal/CFG.qll | 9 - .../aliased_ssa/internal/AliasedSSA.qll | 3 - .../ir/implementation/internal/TOperand.qll | 14 - .../raw/internal/IRConstruction.qll | 5 - .../raw/internal/TranslatedExpr.qll | 3 - .../code/cpp/rangeanalysis/RangeSSA.qll | 3 - .../src/Security/CWE/CWE-020/ExternalAPIs.qll | 6 - .../CWE/CWE-020/ExternalAPIsSpecific.qll | 6 - .../CWE/CWE-020/SafeExternalAPIFunction.qll | 3 - .../Security/CWE/CWE-020/ir/ExternalAPIs.qll | 6 - .../CWE/CWE-020/ir/ExternalAPIsSpecific.qll | 6 - .../CWE-020/ir/SafeExternalAPIFunction.qll | 3 - cpp/ql/src/external/CodeDuplication.qll | 373 ------------------ .../library-tests/dataflow/fields/Nodes.qll | 3 - 19 files changed, 495 deletions(-) delete mode 100644 cpp/ql/src/external/CodeDuplication.qll diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll index 2aba033329d..5f79ceefd26 100644 --- a/cpp/ql/lib/semmle/code/cpp/Class.qll +++ b/cpp/ql/lib/semmle/code/cpp/Class.qll @@ -176,20 +176,6 @@ class Class extends UserType { /** Holds if this class, struct or union has a constructor. */ predicate hasConstructor() { exists(this.getAConstructor()) } - /** - * Holds if this class has a copy constructor that is either explicitly - * declared (though possibly `= delete`) or is auto-generated, non-trivial - * and called from somewhere. - * - * DEPRECATED: There is more than one reasonable definition of what it means - * to have a copy constructor, and we do not want to promote one particular - * definition by naming it with this predicate. Having a copy constructor - * could mean that such a member is declared or defined in the source or that - * it is callable by a particular caller. For C++11, there's also a question - * of whether to include members that are defaulted or deleted. - */ - deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor } - /** * Like accessOfBaseMember but returns multiple results if there are multiple * paths to `base` through the inheritance graph. diff --git a/cpp/ql/lib/semmle/code/cpp/File.qll b/cpp/ql/lib/semmle/code/cpp/File.qll index b2e4e0a41a5..bac9b66965e 100644 --- a/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/cpp/ql/lib/semmle/code/cpp/File.qll @@ -34,14 +34,6 @@ class Container extends Locatable, @container { */ string getAbsolutePath() { none() } // overridden by subclasses - /** - * DEPRECATED: Use `getLocation` instead. - * Gets a URL representing the location of this container. - * - * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). - */ - deprecated string getURL() { none() } // overridden by subclasses - /** * Gets the relative path of this file or folder from the root folder of the * analyzed source location. The relative path of the root folder itself is @@ -183,12 +175,6 @@ class Folder extends Container, @folder { } override string getAPrimaryQlClass() { result = "Folder" } - - /** - * DEPRECATED: Use `getLocation` instead. - * Gets the URL of this folder. - */ - deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } } /** @@ -213,12 +199,6 @@ class File extends Container, @file { result.hasLocationInfo(_, 0, 0, 0, 0) } - /** - * DEPRECATED: Use `getLocation` instead. - * Gets the URL of this file. - */ - deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - /** Holds if this file was compiled as C (at any point). */ predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") } diff --git a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll index b4d89eb8c1d..11e1791ba60 100644 --- a/cpp/ql/lib/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/lib/semmle/code/cpp/PrintAST.qll @@ -27,9 +27,6 @@ class PrintAstConfiguration extends TPrintAstConfiguration { predicate shouldPrintFunction(Function func) { any() } } -/** DEPRECATED: Alias for PrintAstConfiguration */ -deprecated class PrintASTConfiguration = PrintAstConfiguration; - private predicate shouldPrintFunction(Function func) { exists(PrintAstConfiguration config | config.shouldPrintFunction(func)) } @@ -239,9 +236,6 @@ class PrintAstNode extends TPrintAstNode { } } -/** DEPRECATED: Alias for PrintAstNode */ -deprecated class PrintASTNode = PrintAstNode; - /** * Class that restricts the elements that we compute `qlClass` for. */ @@ -286,9 +280,6 @@ abstract class BaseAstNode extends PrintAstNode { deprecated Locatable getAST() { result = this.getAst() } } -/** DEPRECATED: Alias for BaseAstNode */ -deprecated class BaseASTNode = BaseAstNode; - /** * A node representing an AST node other than a `DeclarationEntry`. */ @@ -296,9 +287,6 @@ abstract class AstNode extends BaseAstNode, TAstNode { AstNode() { this = TAstNode(ast) } } -/** DEPRECATED: Alias for AstNode */ -deprecated class ASTNode = AstNode; - /** * A node representing an `Expr`. */ diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll index 4732cd06184..f9dad008661 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll @@ -14,9 +14,6 @@ library class StandardSsa extends SsaHelper { StandardSsa() { this = 0 } } -/** DEPRECATED: Alias for StandardSsa */ -deprecated class StandardSSA = StandardSsa; - /** * A definition of one or more SSA variables, including phi node definitions. * An _SSA variable_, as defined in the literature, is effectively the pair of diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll index 45ef36f339d..5e9f85581b8 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll @@ -312,6 +312,3 @@ library class SsaHelper extends int { ssa_use(v, result, _, _) } } - -/** DEPRECATED: Alias for SsaHelper */ -deprecated class SSAHelper = SsaHelper; diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll index 25fdba90d52..99aed9702a9 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll @@ -1385,9 +1385,6 @@ private module Cached { conditionalSuccessor(n1, _, n2) } - /** DEPRECATED: Alias for qlCfgSuccessor */ - deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2; - /** * Holds if `n2` is a control-flow node such that the control-flow * edge `(n1, n2)` may be taken when `n1` is an expression that is true. @@ -1398,9 +1395,6 @@ private module Cached { not conditionalSuccessor(n1, false, n2) } - /** DEPRECATED: Alias for qlCfgTrueSuccessor */ - deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2; - /** * Holds if `n2` is a control-flow node such that the control-flow * edge `(n1, n2)` may be taken when `n1` is an expression that is false. @@ -1410,7 +1404,4 @@ private module Cached { conditionalSuccessor(n1, false, n2) and not conditionalSuccessor(n1, true, n2) } - - /** DEPRECATED: Alias for qlCfgFalseSuccessor */ - deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2; } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll index 1dd116d6c0e..10fddf6352b 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll @@ -577,9 +577,6 @@ private Overlap getVariableMemoryLocationOverlap( */ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) } -/** DEPRECATED: Alias for canReuseSsaForOldResult */ -deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1; - bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 607b88fa58d..8a330114fe9 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -74,20 +74,12 @@ private module Shared { class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand; - /** DEPRECATED: Alias for TNonSsaMemoryOperand */ - deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand; - /** * Returns the non-Phi memory operand with the specified parameters. */ TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { result = Internal::TNonSsaMemoryOperand(useInstr, tag) } - - /** DEPRECATED: Alias for nonSsaMemoryOperand */ - deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { - result = nonSsaMemoryOperand(useInstr, tag) - } } /** @@ -167,9 +159,6 @@ module UnaliasedSsaOperands { TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } } -/** DEPRECATED: Alias for UnaliasedSsaOperands */ -deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands; - /** * Provides wrappers for the constructors of each branch of `TOperand` that is used by the * aliased SSA stage. @@ -217,6 +206,3 @@ module AliasedSsaOperands { result = Internal::TAliasedChiOperand(useInstr, tag) } } - -/** DEPRECATED: Alias for AliasedSsaOperands */ -deprecated module AliasedSSAOperands = AliasedSsaOperands; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 1cfd8a2041e..8c0695247f8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -375,11 +375,6 @@ Locatable getInstructionAst(TStageInstruction instr) { ) } -/** DEPRECATED: Alias for getInstructionAst */ -deprecated Locatable getInstructionAST(TStageInstruction instr) { - result = getInstructionAst(instr) -} - CppType getInstructionResultType(TStageInstruction instr) { getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result) or diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 3080848b153..5832aa9f928 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -76,9 +76,6 @@ abstract class TranslatedExpr extends TranslatedElement { final override Locatable getAst() { result = expr } - /** DEPRECATED: Alias for getAst */ - deprecated override Locatable getAST() { result = this.getAst() } - final override Declaration getFunction() { result = getEnclosingDeclaration(expr) } /** diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll index 2503e4713d8..849dd70a9a3 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -40,9 +40,6 @@ library class RangeSsa extends SsaHelper { } } -/** DEPRECATED: Alias for RangeSsa */ -deprecated class RangeSSA = RangeSsa; - private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) { guardCondition(guard, v, branch) and guardSuccessor(guard, branch, b) diff --git a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll index 5135aab8d83..51dad0fc18c 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll @@ -16,9 +16,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** An external API which is used with untrusted data. */ private newtype TExternalApi = /** An untrusted API method `m` where untrusted data is passed at `index`. */ @@ -51,6 +48,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { ) } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll index 2505f718bc6..2d9502f2f43 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll @@ -41,9 +41,6 @@ class ExternalApiDataNode extends DataFlow::Node { string getFunctionDescription() { result = this.getExternalFunction().toString() } } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" } @@ -58,9 +55,6 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } } -/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ -deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; - /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { diff --git a/cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll b/cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll index de59e82e552..aecbe148290 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll @@ -10,9 +10,6 @@ private import semmle.code.cpp.models.interfaces.SideEffect */ abstract class SafeExternalApiFunction extends Function { } -/** DEPRECATED: Alias for SafeExternalApiFunction */ -deprecated class SafeExternalAPIFunction = SafeExternalApiFunction; - /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction { DefaultSafeExternalApiFunction() { diff --git a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll index 5135aab8d83..51dad0fc18c 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll @@ -16,9 +16,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** An external API which is used with untrusted data. */ private newtype TExternalApi = /** An untrusted API method `m` where untrusted data is passed at `index`. */ @@ -51,6 +48,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { ) } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll index 93da5497a22..87e1d6bd7c5 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll @@ -41,9 +41,6 @@ class ExternalApiDataNode extends DataFlow::Node { string getFunctionDescription() { result = this.getExternalFunction().toString() } } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" } @@ -53,9 +50,6 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } } -/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ -deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; - /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } diff --git a/cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll b/cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll index de59e82e552..aecbe148290 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll @@ -10,9 +10,6 @@ private import semmle.code.cpp.models.interfaces.SideEffect */ abstract class SafeExternalApiFunction extends Function { } -/** DEPRECATED: Alias for SafeExternalApiFunction */ -deprecated class SafeExternalAPIFunction = SafeExternalApiFunction; - /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction { DefaultSafeExternalApiFunction() { diff --git a/cpp/ql/src/external/CodeDuplication.qll b/cpp/ql/src/external/CodeDuplication.qll deleted file mode 100644 index be2dc162e74..00000000000 --- a/cpp/ql/src/external/CodeDuplication.qll +++ /dev/null @@ -1,373 +0,0 @@ -/** Provides classes for detecting duplicate or similar code. */ - -import cpp - -deprecated private newtype TDuplicationOrSimilarity = MKDuplicationOrSimilarity() - -/** - * DEPRECATED: This class is no longer used. - * - * A token block used for detection of duplicate and similar code. - */ -deprecated class Copy extends TDuplicationOrSimilarity { - /** Gets the index of the token in this block starting at the location `loc`, if any. */ - int tokenStartingAt(Location loc) { none() } - - /** Gets the index of the token in this block ending at the location `loc`, if any. */ - int tokenEndingAt(Location loc) { none() } - - /** Gets the line on which the first token in this block starts. */ - int sourceStartLine() { none() } - - /** Gets the column on which the first token in this block starts. */ - int sourceStartColumn() { none() } - - /** Gets the line on which the last token in this block ends. */ - int sourceEndLine() { none() } - - /** Gets the column on which the last token in this block ends. */ - int sourceEndColumn() { none() } - - /** Gets the number of lines containing at least (part of) one token in this block. */ - int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() } - - /** Gets an opaque identifier for the equivalence class of this block. */ - int getEquivalenceClass() { none() } - - /** Gets the source file in which this block appears. */ - File sourceFile() { none() } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.sourceFile().getAbsolutePath() = filepath and - startline = this.sourceStartLine() and - startcolumn = this.sourceStartColumn() and - endline = this.sourceEndLine() and - endcolumn = this.sourceEndColumn() - } - - /** Gets a textual representation of this element. */ - string toString() { none() } -} - -/** - * DEPRECATED: This class is no longer used. - * - * A block of duplicated code. - */ -deprecated class DuplicateBlock extends Copy { - override string toString() { - result = "Duplicate code: " + this.sourceLines() + " duplicated lines." - } -} - -/** - * DEPRECATED: This class is no longer used. - * - * A block of similar code. - */ -deprecated class SimilarBlock extends Copy { - override string toString() { - result = "Similar code: " + this.sourceLines() + " almost duplicated lines." - } -} - -/** - * DEPRECATED: The `CodeDuplication` library will be removed in a future release. - * - * Gets a function with a body and a location. - */ -deprecated FunctionDeclarationEntry sourceMethod() { - result.isDefinition() and - exists(result.getLocation()) and - numlines(unresolveElement(result.getFunction()), _, _, _) -} - -/** - * DEPRECATED: The `CodeDuplication` library will be removed in a future release. - * - * Gets the number of member functions in `c` with a body and a location. - */ -deprecated int numberOfSourceMethods(Class c) { - result = - count(FunctionDeclarationEntry m | - m = sourceMethod() and - m.getFunction().getDeclaringType() = c - ) -} - -deprecated private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) { - exists(DuplicateBlock b, Location loc | - stmt.getLocation() = loc and - first = b.tokenStartingAt(loc) and - last = b.tokenEndingAt(loc) and - b.getEquivalenceClass() = equivClass - ) -} - -deprecated private Stmt statementInMethod(FunctionDeclarationEntry m) { - result.getParent+() = m.getBlock() and - not result.getLocation() instanceof UnknownStmtLocation and - not result instanceof BlockStmt -} - -deprecated private predicate duplicateStatement( - FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, Stmt s1, Stmt s2 -) { - exists(int equivClass, int first, int last | - s1 = statementInMethod(m1) and - s2 = statementInMethod(m2) and - blockCoversStatement(equivClass, first, last, s1) and - blockCoversStatement(equivClass, first, last, s2) and - s1 != s2 and - m1 != m2 - ) -} - -/** - * DEPRECATED: Information on duplicated statements is no longer available. - * - * Holds if `m1` is a function with `total` lines, and `m2` is a function - * that has `duplicate` lines in common with `m1`. - */ -deprecated predicate duplicateStatements( - FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total -) { - duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and - total = strictcount(statementInMethod(m1)) -} - -/** - * DEPRECATED: Information on duplicated methods is no longer available. - * - * Holds if `m` and other are identical functions. - */ -deprecated predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) { - exists(int total | duplicateStatements(m, other, total, total)) -} - -/** - * DEPRECATED: Information on similar lines is no longer available. - * - * INTERNAL: do not use. - * - * Holds if `line` in `f` is similar to a line somewhere else. - */ -deprecated predicate similarLines(File f, int line) { - exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) -} - -deprecated private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(SimilarBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -deprecated private predicate similarLinesCoveredFiles(File f, File otherFile) { - exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - similarLinesPerEquivalenceClass(equivClass, num, f) and - similarLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - (coveredApprox * 100) / numLines > 75 - ) - ) -} - -/** - * DEPRECATED: Information on similar lines is no longer available. - * - * Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. - */ -deprecated predicate similarLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | - similarLinesCoveredFiles(f, otherFile) and - exists(int notCovered | - notCovered = - count(int j | - j in [1 .. numLines] and - not similarLines(f, j) - ) and - coveredLines = numLines - notCovered - ) - ) -} - -/** - * DEPRECATED: Information on duplicate lines is no longer available. - * - * INTERNAL: do not use. - * - * Holds if `line` in `f` is duplicated by a line somewhere else. - */ -deprecated predicate duplicateLines(File f, int line) { - exists(DuplicateBlock b | - b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] - ) -} - -deprecated private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) { - lines = - strictsum(DuplicateBlock b, int toSum | - (b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and - toSum = b.sourceLines() - | - toSum - ) -} - -/** - * DEPRECATED: Information on duplicate lines is no longer available. - * - * Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. - */ -deprecated predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { - exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | - exists(int coveredApprox | - coveredApprox = - strictsum(int num | - exists(int equivClass | - duplicateLinesPerEquivalenceClass(equivClass, num, f) and - duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and - f != otherFile - ) - ) and - (coveredApprox * 100) / numLines > 75 - ) and - exists(int notCovered | - notCovered = - count(int j | - j in [1 .. numLines] and - not duplicateLines(f, j) - ) and - coveredLines = numLines - notCovered - ) - ) -} - -/** - * DEPRECATED: Information on similar files is no longer available. - * - * Holds if most of `f` (`percent`%) is similar to `other`. - */ -deprecated predicate similarFiles(File f, File other, int percent) { - exists(int covered, int total | - similarLinesCovered(f, covered, other) and - total = f.getMetrics().getNumberOfLines() and - covered * 100 / total = percent and - percent > 80 - ) and - not duplicateFiles(f, other, _) -} - -/** - * DEPRECATED: Information on duplicate files is no longer available. - * - * Holds if most of `f` (`percent`%) is duplicated by `other`. - */ -deprecated predicate duplicateFiles(File f, File other, int percent) { - exists(int covered, int total | - duplicateLinesCovered(f, covered, other) and - total = f.getMetrics().getNumberOfLines() and - covered * 100 / total = percent and - percent > 70 - ) -} - -/** - * DEPRECATED: Information on duplicate classes is no longer available. - * - * Holds if most member functions of `c` (`numDup` out of `total`) are - * duplicates of member functions in `other`. - */ -deprecated predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { - numDup = - strictcount(FunctionDeclarationEntry m1 | - exists(FunctionDeclarationEntry m2 | - duplicateMethod(m1, m2) and - m1 = sourceMethod() and - exists(Function f | f = m1.getFunction() and f.getDeclaringType() = c) and - exists(Function f | f = m2.getFunction() and f.getDeclaringType() = other) and - c != other - ) - ) and - total = numberOfSourceMethods(c) and - (numDup * 100) / total > 80 -} - -/** - * DEPRECATED: Information on duplicate classes is no longer available. - * - * Holds if most member functions of `c` are duplicates of member functions in - * `other`. Provides the human-readable `message` to describe the amount of - * duplication. - */ -deprecated predicate mostlyDuplicateClass(Class c, Class other, string message) { - exists(int numDup, int total | - mostlyDuplicateClassBase(c, other, numDup, total) and - ( - total != numDup and - exists(string s1, string s2, string s3, string name | - s1 = " out of " and - s2 = " methods in " and - s3 = " are duplicated in $@." and - name = c.getName() - | - message = numDup + s1 + total + s2 + name + s3 - ) - or - total = numDup and - exists(string s1, string s2, string name | - s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName() - | - message = s1 + name + s2 - ) - ) - ) -} - -/** - * DEPRECATED: Information on file duplication is no longer available. - * - * Holds if `f` and `other` are similar or duplicates. - */ -deprecated predicate fileLevelDuplication(File f, File other) { - similarFiles(f, other, _) or duplicateFiles(f, other, _) -} - -/** - * DEPRECATED: Information on class duplication is no longer available. - * - * Holds if most member functions of `c` are duplicates of member functions in - * `other`. - */ -deprecated predicate classLevelDuplication(Class c, Class other) { - mostlyDuplicateClass(c, other, _) -} - -/** - * DEPRECATED: The CodeDuplication library will be removed in a future release. - * - * Holds if `line` in `f` should be allowed to be duplicated. This is the case - * for `#include` directives. - */ -deprecated predicate whitelistedLineForDuplication(File f, int line) { - exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line) -} diff --git a/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll index 7313518af91..8c4c547f4c8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll +++ b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll @@ -34,9 +34,6 @@ class AstNode extends Node, TAstNode { override Location getLocation() { result = n.getLocation() } } -/** DEPRECATED: Alias for AstNode */ -deprecated class ASTNode = AstNode; - class IRNode extends Node, TIRNode { IR::DataFlow::Node n; From 2241350d321e4ac86c4dbb1cb153e85687569198 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Wed, 7 Jun 2023 22:35:11 +0200 Subject: [PATCH 183/219] wait with deprecating Container::getURL() --- cpp/ql/lib/semmle/code/cpp/File.qll | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/File.qll b/cpp/ql/lib/semmle/code/cpp/File.qll index bac9b66965e..b2e4e0a41a5 100644 --- a/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/cpp/ql/lib/semmle/code/cpp/File.qll @@ -34,6 +34,14 @@ class Container extends Locatable, @container { */ string getAbsolutePath() { none() } // overridden by subclasses + /** + * DEPRECATED: Use `getLocation` instead. + * Gets a URL representing the location of this container. + * + * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). + */ + deprecated string getURL() { none() } // overridden by subclasses + /** * Gets the relative path of this file or folder from the root folder of the * analyzed source location. The relative path of the root folder itself is @@ -175,6 +183,12 @@ class Folder extends Container, @folder { } override string getAPrimaryQlClass() { result = "Folder" } + + /** + * DEPRECATED: Use `getLocation` instead. + * Gets the URL of this folder. + */ + deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } } /** @@ -199,6 +213,12 @@ class File extends Container, @file { result.hasLocationInfo(_, 0, 0, 0, 0) } + /** + * DEPRECATED: Use `getLocation` instead. + * Gets the URL of this file. + */ + deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } + /** Holds if this file was compiled as C (at any point). */ predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") } From 39438c619690038b27b12d5908259250e0f328e0 Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 8 Jun 2023 10:15:32 +0200 Subject: [PATCH 184/219] add change-note --- cpp/ql/lib/change-notes/2022-08-06-delete-deps.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2022-08-06-delete-deps.md diff --git a/cpp/ql/lib/change-notes/2022-08-06-delete-deps.md b/cpp/ql/lib/change-notes/2022-08-06-delete-deps.md new file mode 100644 index 00000000000..c234c189484 --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-08-06-delete-deps.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`. +* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `CodeDuplication.qll` file. \ No newline at end of file From dc7a286948abf93a1233c63bcd3e34fb604b01aa Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 8 Jun 2023 11:29:04 +0100 Subject: [PATCH 185/219] Swift: Add lines of code to SummaryStats.ql. --- swift/ql/src/queries/Summary/SummaryStats.ql | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/swift/ql/src/queries/Summary/SummaryStats.ql b/swift/ql/src/queries/Summary/SummaryStats.ql index 444c4da2ca2..9174dd19aee 100644 --- a/swift/ql/src/queries/Summary/SummaryStats.ql +++ b/swift/ql/src/queries/Summary/SummaryStats.ql @@ -12,6 +12,15 @@ import codeql.swift.security.SensitiveExprs import codeql.swift.dataflow.DataFlow import codeql.swift.dataflow.TaintTracking +int linesOfCode() { + // approximate number of lines of code in the database + result = count(File f, int line | + exists(Location loc | + not loc instanceof UnknownLocation and loc.getFile() = f and loc.getStartLine() = line + ) + ) +} + /** * A taint configuration for tainted data reaching any node. */ @@ -37,6 +46,8 @@ float taintReach() { result = (taintedNodesCount() * 1000000.0) / count(DataFlow predicate statistic(string what, string value) { what = "Files" and value = count(File f).toString() or + what = "Lines of code" and value = linesOfCode().toString() + or what = "Expressions" and value = count(Expr e | not e.getFile() instanceof UnknownFile).toString() or what = "Local flow sources" and value = count(LocalFlowSource s).toString() From e0f16f46d2ca17ba21268e1b1a7cb8361a904d52 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 8 Jun 2023 11:35:08 +0100 Subject: [PATCH 186/219] Swift: Add compile errors / warnings to SummaryStats.ql. --- swift/ql/src/queries/Summary/SummaryStats.ql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swift/ql/src/queries/Summary/SummaryStats.ql b/swift/ql/src/queries/Summary/SummaryStats.ql index 9174dd19aee..73b80b7f147 100644 --- a/swift/ql/src/queries/Summary/SummaryStats.ql +++ b/swift/ql/src/queries/Summary/SummaryStats.ql @@ -48,6 +48,10 @@ predicate statistic(string what, string value) { or what = "Lines of code" and value = linesOfCode().toString() or + what = "Compiler errors" and value = count(CompilerError d).toString() + or + what = "Compiler warnings" and value = count(CompilerWarning d).toString() + or what = "Expressions" and value = count(Expr e | not e.getFile() instanceof UnknownFile).toString() or what = "Local flow sources" and value = count(LocalFlowSource s).toString() From dabb4dd643b5cfc519487df289541dfd966c7bd8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 8 Jun 2023 13:02:54 +0200 Subject: [PATCH 187/219] Java: Improve join-order for FunctionalInterface. --- java/ql/lib/semmle/code/java/Type.qll | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index f60fdcc8e5d..fcf31e3be0d 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -987,6 +987,17 @@ private string getAPublicObjectMethodSignature() { ) } +pragma[nomagic] +private predicate interfaceInheritsOverridingNonAbstractMethod(Interface interface, Method m) { + interface.inherits(m) and + not m.isAbstract() and + m.overrides(_) +} + +bindingset[m] +pragma[inline_late] +private Method getAnOverridden(Method m) { m.overrides(result) } + private Method getAnAbstractMethod(Interface interface) { interface.inherits(result) and result.isAbstract() and @@ -995,9 +1006,8 @@ private Method getAnAbstractMethod(Interface interface) { // Make sure that there is no other non-abstract method // (e.g. `default`) which overrides the abstract one not exists(Method m | - interface.inherits(m) and - not m.isAbstract() and - m.overrides(result) + interfaceInheritsOverridingNonAbstractMethod(interface, m) and + result = getAnOverridden(m) ) } From a3ef5c69184ee9c501f2097a5f1e73e316c2ecbe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 8 Jun 2023 11:35:18 +0100 Subject: [PATCH 188/219] Swift: QLDoc Diagnostics.qll. --- .../lib/codeql/swift/elements/Diagnostics.qll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/swift/ql/lib/codeql/swift/elements/Diagnostics.qll b/swift/ql/lib/codeql/swift/elements/Diagnostics.qll index aec6d2be8f4..a0ec9995355 100644 --- a/swift/ql/lib/codeql/swift/elements/Diagnostics.qll +++ b/swift/ql/lib/codeql/swift/elements/Diagnostics.qll @@ -1,8 +1,14 @@ private import codeql.swift.generated.Diagnostics +/** + * A compiler-generated error, warning, note or remark. + */ class Diagnostics extends Generated::Diagnostics { override string toString() { result = this.getSeverity() + ": " + this.getText() } + /** + * Gets a string representing the severity of this compiler diagnostic. + */ string getSeverity() { this.getKind() = 1 and result = "error" or @@ -14,18 +20,30 @@ class Diagnostics extends Generated::Diagnostics { } } +/** + * A compiler error message. + */ class CompilerError extends Diagnostics { CompilerError() { this.getSeverity() = "error" } } +/** + * A compiler-generated warning. + */ class CompilerWarning extends Diagnostics { CompilerWarning() { this.getSeverity() = "warning" } } +/** + * A compiler-generated note (typically attached to an error or warning). + */ class CompilerNote extends Diagnostics { CompilerNote() { this.getSeverity() = "note" } } +/** + * A compiler-generated remark (milder than a warning, this does not indicate an issue). + */ class CompilerRemark extends Diagnostics { CompilerRemark() { this.getSeverity() = "remark" } } From 5727d49cce2b8729678becaff8835c12ace3e7f7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 8 Jun 2023 11:44:39 +0100 Subject: [PATCH 189/219] Swift: Take out common code for lines of code. --- swift/ql/lib/codeql/swift/elements/File.qll | 15 +++++++++++++++ .../src/diagnostics/SuccessfullyExtractedLines.ql | 6 +----- swift/ql/src/queries/Summary/SummaryStats.ql | 11 +---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/swift/ql/lib/codeql/swift/elements/File.qll b/swift/ql/lib/codeql/swift/elements/File.qll index 1c47cd163c2..b6da771ef60 100644 --- a/swift/ql/lib/codeql/swift/elements/File.qll +++ b/swift/ql/lib/codeql/swift/elements/File.qll @@ -1,4 +1,6 @@ private import codeql.swift.generated.File +private import codeql.swift.elements.Location +private import codeql.swift.elements.UnknownLocation class File extends Generated::File { /** toString */ @@ -17,4 +19,17 @@ class File extends Generated::File { string getBaseName() { result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) } + + /** + * Gets the number of lines containing code in this file. This value + * is approximate. + */ + int getNumberOfLinesOfCode() { + result = + count(int line | + exists(Location loc | + not loc instanceof UnknownLocation and loc.getFile() = this and loc.getStartLine() = line + ) + ) + } } diff --git a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql index 59b1d5bc8bc..373b6c4bd0f 100644 --- a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql +++ b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql @@ -8,8 +8,4 @@ import swift -select count(File f, int line | - exists(Location loc | - not loc instanceof UnknownLocation and loc.getFile() = f and loc.getStartLine() = line - ) - ) +select sum(File f | | f.getNumberOfLinesOfCode()) diff --git a/swift/ql/src/queries/Summary/SummaryStats.ql b/swift/ql/src/queries/Summary/SummaryStats.ql index 73b80b7f147..30122e666e3 100644 --- a/swift/ql/src/queries/Summary/SummaryStats.ql +++ b/swift/ql/src/queries/Summary/SummaryStats.ql @@ -12,15 +12,6 @@ import codeql.swift.security.SensitiveExprs import codeql.swift.dataflow.DataFlow import codeql.swift.dataflow.TaintTracking -int linesOfCode() { - // approximate number of lines of code in the database - result = count(File f, int line | - exists(Location loc | - not loc instanceof UnknownLocation and loc.getFile() = f and loc.getStartLine() = line - ) - ) -} - /** * A taint configuration for tainted data reaching any node. */ @@ -46,7 +37,7 @@ float taintReach() { result = (taintedNodesCount() * 1000000.0) / count(DataFlow predicate statistic(string what, string value) { what = "Files" and value = count(File f).toString() or - what = "Lines of code" and value = linesOfCode().toString() + what = "Lines of code" and value = sum(File f | | f.getNumberOfLinesOfCode()).toString() or what = "Compiler errors" and value = count(CompilerError d).toString() or From 57ae1e9ff790c6ae6710624300e5e20619f4c59e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 8 Jun 2023 12:49:08 +0100 Subject: [PATCH 190/219] C++: Add a testcase that started to fail in #13326. --- .../dataflow/taint-tests/localTaint.expected | 7 +++++++ cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 907cccd197b..f6a7625b57a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -6584,6 +6584,13 @@ | taint.cpp:691:18:691:18 | s [post update] | taint.cpp:695:7:695:7 | s | | | taint.cpp:691:20:691:20 | ref arg x | taint.cpp:694:9:694:9 | x | | | taint.cpp:694:7:694:7 | s [post update] | taint.cpp:695:7:695:7 | s | | +| taint.cpp:700:13:700:18 | call to source | taint.cpp:702:11:702:11 | s | | +| taint.cpp:701:9:701:9 | p | taint.cpp:702:4:702:4 | p | | +| taint.cpp:702:4:702:4 | p | taint.cpp:702:4:702:6 | ... ++ | | +| taint.cpp:702:4:702:6 | ... ++ | taint.cpp:702:3:702:6 | * ... | TAINT | +| taint.cpp:702:4:702:6 | ... ++ | taint.cpp:703:8:703:8 | p | TAINT | +| taint.cpp:702:10:702:11 | * ... | taint.cpp:702:3:702:11 | ... = ... | | +| taint.cpp:702:11:702:11 | s | taint.cpp:702:10:702:11 | * ... | TAINT | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 9806ddb395e..fa6074e44f6 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -693,4 +693,13 @@ void test_argument_source_field_to_obj() { sink(s); // $ SPURIOUS: ast,ir sink(s.x); // $ ast,ir sink(s.y); // clean +} + +namespace strings { + void test_write_to_read_then_incr_then_deref() { + char* s = source(); + char* p; + *p++ = *s; + sink(p); // $ ast ir + } } \ No newline at end of file From afb1129f2790447bd5eec24e2bf24025ddfeca17 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 8 Jun 2023 12:50:05 +0100 Subject: [PATCH 191/219] C++: Ensure that postfix crement operations are handled properly in dataflow SSA. --- .../cpp/ir/dataflow/internal/SsaInternals.qll | 20 ++++++++- .../dataflow/internal/ssa0/SsaInternals.qll | 41 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll index 551653c3aca..0cd152e2473 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll @@ -364,7 +364,25 @@ abstract private class OperandBasedUse extends UseImpl { OperandBasedUse() { any() } final override predicate hasIndexInBlock(IRBlock block, int index) { - operand.getUse() = block.getInstruction(index) + // See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this + // predicate's implementation. + exists(BaseSourceVariableInstruction base | base = this.getBase() | + if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand() + then + exists(Operand op, int indirectionIndex, int indirection | + indirectionIndex = this.getIndirectionIndex() and + indirection = this.getIndirection() and + op = + min(Operand cand, int i | + isUse(_, cand, base, indirection, indirectionIndex) and + block.getInstruction(i) = cand.getUse() + | + cand order by i + ) and + block.getInstruction(index) = op.getUse() + ) + else operand.getUse() = block.getInstruction(index) + ) } final Operand getOperand() { result = operand } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll index aa6a43a2580..38f9bbeec8e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ssa0/SsaInternals.qll @@ -122,7 +122,46 @@ abstract private class OperandBasedUse extends UseImpl { override string toString() { result = operand.toString() } final override predicate hasIndexInBlock(IRBlock block, int index) { - operand.getUse() = block.getInstruction(index) + // Ideally, this would just be implemented as: + // ``` + // operand.getUse() = block.getInstruction(index) + // ``` + // but because the IR generated for a snippet such as + // ``` + // int x = *p++; + // ``` + // looks like + // ``` + // r1(glval<int>) = VariableAddress[x] : + // r2(glval<int *>) = VariableAddress[p] : + // r3(int *) = Load[p] : &:r2, m1 + // r4(int) = Constant[1] : + // r5(int *) = PointerAdd[4] : r3, r4 + // m3(int *) = Store[p] : &:r2, r5 + // r6(int *) = CopyValue : r3 + // r7(int) = Load[?] : &:r6, ~m2 + // m2(int) = Store[x] : &:r1, r7 + // ``` + // we need to ensure that the `r3` operand of the `CopyValue` instruction isn't seen as a fresh use + // of `p` that happens after the increment. So if the base instruction of this use comes from a + // post-fix crement operation we set the index of the SSA use that wraps the `r3` operand at the + // `CopyValue` instruction to be the same index as the `r3` operand at the `PointerAdd` instruction. + // This ensures that the SSA library doesn't create flow from the `PointerAdd` to `r6`. + exists(BaseSourceVariableInstruction base | base = this.getBase() | + if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand() + then + exists(Operand op | + op = + min(Operand cand, int i | + isUse(_, cand, base, _, _) and + block.getInstruction(i) = cand.getUse() + | + cand order by i + ) and + block.getInstruction(index) = op.getUse() + ) + else operand.getUse() = block.getInstruction(index) + ) } final override Cpp::Location getLocation() { result = operand.getLocation() } From a357eeedacabac1fe3ac5b2895c61e500e158c42 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 8 Jun 2023 12:50:16 +0100 Subject: [PATCH 192/219] C++: Accept test changes. --- .../CWE-193/pointer-deref/InvalidPointerDeref.expected | 10 ---------- .../Security/CWE/CWE-193/pointer-deref/test.cpp | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 1bff2ec77f7..0d92ae6db5a 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -664,11 +664,6 @@ edges | test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... | | test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... | | test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs | -| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | -| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ | -| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:15:350:19 | Load: * ... | -| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ | -| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ | | test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:16 | xs | | test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... | | test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... | @@ -1057,10 +1052,6 @@ nodes | test.cpp:342:8:342:17 | * ... | semmle.label | * ... | | test.cpp:347:14:347:27 | new[] | semmle.label | new[] | | test.cpp:348:15:348:16 | xs | semmle.label | xs | -| test.cpp:350:15:350:19 | Load: * ... | semmle.label | Load: * ... | -| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ | -| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ | -| test.cpp:350:16:350:19 | ... ++ | semmle.label | ... ++ | | test.cpp:355:14:355:27 | new[] | semmle.label | new[] | | test.cpp:356:15:356:16 | xs | semmle.label | xs | | test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... | @@ -1118,7 +1109,6 @@ subpaths | test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len | | test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len | | test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... | -| test.cpp:350:15:350:19 | Load: * ... | test.cpp:347:14:347:27 | new[] | test.cpp:350:15:350:19 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:347:14:347:27 | new[] | new[] | test.cpp:348:20:348:23 | size | size | | test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 7269af0153f..05b0f1c07ca 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -347,7 +347,7 @@ void test24(unsigned size) { char *xs = new char[size]; char *end = xs + size; if (xs < end) { - int val = *xs++; // GOOD [FALSE POSITIVE] + int val = *xs++; // GOOD } } From d6741f655d085175262da40b041b78a90969f788 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Thu, 8 Jun 2023 14:01:47 +0200 Subject: [PATCH 193/219] Ruby: restrict ORM tracking to calls --- ruby/ql/lib/codeql/ruby/security/XSS.qll | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/security/XSS.qll b/ruby/ql/lib/codeql/ruby/security/XSS.qll index 8196f508b55..f84ae0a52c0 100644 --- a/ruby/ql/lib/codeql/ruby/security/XSS.qll +++ b/ruby/ql/lib/codeql/ruby/security/XSS.qll @@ -285,7 +285,13 @@ private module OrmTracking { * A data flow configuration to track flow from finder calls to field accesses. */ private module Config implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof OrmInstantiation } + predicate isSource(DataFlow::Node source) { + // We currently only use ORM instances that come from a call site, so restrict the sources + // to calls. This works around a performance issue that would arise from using 'self' as a source + // in ActiveRecord models. Over time, library models should stop relying on OrmInstantiation and instead + // use API graphs or type-tracking the same way we track other types. + source instanceof OrmInstantiation and source instanceof DataFlow::CallNode + } // Select any call receiver and narrow down later predicate isSink(DataFlow::Node sink) { sink = any(DataFlow::CallNode c).getReceiver() } @@ -293,6 +299,8 @@ private module OrmTracking { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { Shared::isAdditionalXssFlowStep(node1, node2) } + + predicate isBarrierIn(DataFlow::Node node) { node instanceof DataFlow::SelfParameterNode } } import DataFlow::Global<Config> From 5a2ac1b5ca9999d2865080f4dff8c35273b00cbe Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 8 Jun 2023 14:04:57 +0200 Subject: [PATCH 194/219] Java: Add more negation context to reduce string ops and improve perf. --- .../code/java/security/LogInjection.qll | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/java/ql/lib/semmle/code/java/security/LogInjection.qll b/java/ql/lib/semmle/code/java/security/LogInjection.qll index 2314d807a60..7fb85f6d8f1 100644 --- a/java/ql/lib/semmle/code/java/security/LogInjection.qll +++ b/java/ql/lib/semmle/code/java/security/LogInjection.qll @@ -46,16 +46,33 @@ private class LineBreaksLogInjectionSanitizer extends LogInjectionSanitizer { } } +private predicate stringMethodAccess( + MethodAccess ma, CompileTimeConstantExpr arg0, CompileTimeConstantExpr arg1 +) { + ma.getMethod().getDeclaringType() instanceof TypeString and + arg0 = ma.getArgument(0) and + arg1 = ma.getArgument(1) +} + +private predicate stringMethodArgument(CompileTimeConstantExpr arg) { + stringMethodAccess(_, arg, _) or stringMethodAccess(_, _, arg) +} + +bindingset[match] +pragma[inline_late] +private predicate stringMethodArgumentValueMatches(CompileTimeConstantExpr const, string match) { + stringMethodArgument(const) and + const.getStringValue().matches(match) +} + /** * Holds if the return value of `ma` is sanitized against log injection attacks * by removing line breaks from it. */ private predicate logInjectionSanitizer(MethodAccess ma) { exists(CompileTimeConstantExpr target, CompileTimeConstantExpr replacement | - ma.getMethod().getDeclaringType() instanceof TypeString and - target = ma.getArgument(0) and - replacement = ma.getArgument(1) and - not replacement.getStringValue().matches(["%\n%", "%\r%"]) + stringMethodAccess(ma, target, replacement) and + not stringMethodArgumentValueMatches(replacement, ["%\n%", "%\r%"]) | ma.getMethod().hasName("replace") and not replacement.getIntValue() = [10, 13] and @@ -68,7 +85,7 @@ private predicate logInjectionSanitizer(MethodAccess ma) { ( // Replace anything not in an allow list target.getStringValue().matches("[^%]") and - not target.getStringValue().matches("%" + ["\n", "\r", "\\n", "\\r", "\\R"] + "%") + not stringMethodArgumentValueMatches(target, "%" + ["\n", "\r", "\\n", "\\r", "\\R"] + "%") or // Replace line breaks target.getStringValue() = ["\n", "\r", "\\n", "\\r", "\\R"] From 4608481d7b9e0f819a4e04675f9a9e5347209aa1 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Thu, 8 Jun 2023 14:53:09 +0200 Subject: [PATCH 195/219] Java: Fix more problems in the Gson models Found during type strengthening work by @aschackmull --- java/ql/lib/ext/com.google.gson.model.yml | 4 ++-- .../library-tests/frameworks/gson/Test.java | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/java/ql/lib/ext/com.google.gson.model.yml b/java/ql/lib/ext/com.google.gson.model.yml index 7b41b57083a..abc3693ae00 100644 --- a/java/ql/lib/ext/com.google.gson.model.yml +++ b/java/ql/lib/ext/com.google.gson.model.yml @@ -38,11 +38,11 @@ extensions: - ["com.google.gson", "JsonObject", True, "add", "", "", "Argument[0]", "Argument[this].MapKey", "value", "manual"] - ["com.google.gson", "JsonObject", True, "add", "", "", "Argument[1]", "Argument[this].MapValue", "value", "manual"] - ["com.google.gson", "JsonObject", True, "addProperty", "(String,String)", "", "Argument[0]", "Argument[this].MapKey", "value", "manual"] - - ["com.google.gson", "JsonObject", True, "addProperty", "(String,String)", "", "Argument[1]", "Argument[this].MapValue", "value", "manual"] + - ["com.google.gson", "JsonObject", True, "addProperty", "(String,String)", "", "Argument[1]", "Argument[this].MapValue", "taint", "manual"] - ["com.google.gson", "JsonObject", True, "asMap", "", "", "Argument[this].MapKey", "ReturnValue.MapKey", "value", "manual"] - ["com.google.gson", "JsonObject", True, "asMap", "", "", "Argument[this].MapValue", "ReturnValue.MapValue", "value", "manual"] - ["com.google.gson", "JsonObject", True, "entrySet", "", "", "Argument[this].MapKey", "ReturnValue.Element.MapKey", "value", "manual"] - - ["com.google.gson", "JsonObject", True, "entrySet", "", "", "Argument[this].MapKey", "ReturnValue.Element.MapValue", "value", "manual"] + - ["com.google.gson", "JsonObject", True, "entrySet", "", "", "Argument[this].MapValue", "ReturnValue.Element.MapValue", "value", "manual"] - ["com.google.gson", "JsonObject", True, "get", "", "", "Argument[this].MapValue", "ReturnValue", "value", "manual"] - ["com.google.gson", "JsonObject", True, "keySet", "", "", "Argument[this].MapKey", "ReturnValue.Element", "value", "manual"] - ["com.google.gson", "JsonPrimitive", True, "JsonPrimitive", "(Character)", "", "Argument[0]", "Argument[this]", "taint", "manual"] diff --git a/java/ql/test/library-tests/frameworks/gson/Test.java b/java/ql/test/library-tests/frameworks/gson/Test.java index 6fa1fd2a1e5..b1dc845f091 100644 --- a/java/ql/test/library-tests/frameworks/gson/Test.java +++ b/java/ql/test/library-tests/frameworks/gson/Test.java @@ -407,51 +407,51 @@ public class Test { sink(getMapKeyDefault(out)); // $ hasValueFlow } { - // "com.google.gson;JsonObject;true;addProperty;(String,String);;Argument[1];Argument[this].MapValue;value;manual" + // "com.google.gson;JsonObject;true;addProperty;(String,String);;Argument[1];Argument[this].MapValue;taint;manual" JsonObject out = null; String in = (String)source(); out.addProperty((String)null, in); - sink(getMapValueDefault(out)); // $ hasValueFlow + sink(getMapValueDefault(out)); // $ hasTaintFlow } { // "com.google.gson;JsonObject;true;asMap;;;Argument[this].MapKey;ReturnValue.MapKey;value;manual" Map out = null; - JsonObject in = (JsonObject)newWithMapKeyDefault((String) source()); + JsonObject in = newWithMapKeyDefault((String) source()); out = in.asMap(); sink(getMapKey(out)); // $ hasValueFlow } { // "com.google.gson;JsonObject;true;asMap;;;Argument[this].MapValue;ReturnValue.MapValue;value;manual" Map out = null; - JsonObject in = (JsonObject)newWithMapValueDefault((JsonElement) source()); + JsonObject in = newWithMapValueDefault((JsonElement) source()); out = in.asMap(); sink(getMapValue(out)); // $ hasValueFlow } { // "com.google.gson;JsonObject;true;entrySet;;;Argument[this].MapKey;ReturnValue.Element.MapKey;value;manual" Set<Map.Entry<String,JsonElement>> out = null; - JsonObject in = (JsonObject)newWithMapKeyDefault((String) source()); + JsonObject in = newWithMapKeyDefault((String) source()); out = in.entrySet(); sink(getMapKeyDefault(getElement(out))); // $ hasValueFlow } { - // "com.google.gson;JsonObject;true;entrySet;;;Argument[this].MapKey;ReturnValue.Element.MapValue;value;manual" + // "com.google.gson;JsonObject;true;entrySet;;;Argument[this].MapValue;ReturnValue.Element.MapValue;value;manual" Set<Map.Entry<String,JsonElement>> out = null; - JsonObject in = (JsonObject) newWithMapKeyDefault((String) source()); + JsonObject in = newWithMapValueDefault((JsonElement) source()); out = in.entrySet(); sink(getMapValueDefault(getElement(out))); // $ hasValueFlow } { // "com.google.gson;JsonObject;true;get;;;Argument[this].MapValue;ReturnValue;value;manual" JsonElement out = null; - JsonObject in = (JsonObject)newWithMapValueDefault((JsonElement) source()); + JsonObject in = newWithMapValueDefault((JsonElement) source()); out = in.get(null); sink(out); // $ hasValueFlow } { // "com.google.gson;JsonObject;true;keySet;;;Argument[this].MapKey;ReturnValue.Element;value;manual" Set out = null; - JsonObject in = (JsonObject)newWithMapKeyDefault((String) source()); + JsonObject in = newWithMapKeyDefault((String) source()); out = in.keySet(); sink(getElement(out)); // $ hasValueFlow } From 74a9d9fa3746210cb90b01c70eb9bc20d4acb8b8 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Thu, 8 Jun 2023 15:29:36 +0200 Subject: [PATCH 196/219] Revert "Ruby: update tree-sitter-ruby" --- ruby/extractor/Cargo.lock | Bin 31065 -> 31065 bytes ruby/extractor/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/extractor/Cargo.lock b/ruby/extractor/Cargo.lock index f048f2d7725d8d6e8b86e41a63b538afe657ba31..85c546b9b96e189aae02de3062127274df104d7b 100644 GIT binary patch delta 100 zcmccliSgzq#tkc?0*wsJlFbdw%?-^=jLnUbO)bsR(h@CF6BARCEKQ6}lZ`AaO$?3A SOq7XLIQgQe*k=A{FF61&_#I6E delta 99 zcmccliSgzq#tkc?0?bX)Qc_J*P1BN$l9Eg<%`FlWQ&Y_?EKLn9EK-vUEiKc`(-M=@ S43vpfIQgJ}_-6iSFF63U^dL9@ diff --git a/ruby/extractor/Cargo.toml b/ruby/extractor/Cargo.toml index 6857162af5e..133233f2f14 100644 --- a/ruby/extractor/Cargo.toml +++ b/ruby/extractor/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" [dependencies] tree-sitter = "0.20" tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "203f7bd3c1bbfbd98fc19add4b8fcb213c059205" } -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "74fde5e5fb2bb5978aaee7895188eb199f7facf0" } +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "206c7077164372c596ffa8eaadb9435c28941364" } clap = { version = "4.2", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } From 8401793755d6a6bfcb14958ee5c51ff27dab5088 Mon Sep 17 00:00:00 2001 From: Tony Torralba <atorralba@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:57:38 +0200 Subject: [PATCH 197/219] Run "Check framework coverage changes" workflow when models-as-data files change --- .github/workflows/csv-coverage-pr-artifacts.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/csv-coverage-pr-artifacts.yml b/.github/workflows/csv-coverage-pr-artifacts.yml index 19ad488a3ab..b560d98a79d 100644 --- a/.github/workflows/csv-coverage-pr-artifacts.yml +++ b/.github/workflows/csv-coverage-pr-artifacts.yml @@ -10,6 +10,7 @@ on: - "*/ql/src/**/*.qll" - "*/ql/lib/**/*.ql" - "*/ql/lib/**/*.qll" + - "*/ql/lib/ext/**/*.yml" - "misc/scripts/library-coverage/*.py" # input data files - "*/documentation/library-coverage/cwe-sink.csv" From a961fffda8ade49400406ee645c2641a36a95062 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" <mbg@github.com> Date: Thu, 8 Jun 2023 16:24:16 +0100 Subject: [PATCH 198/219] Pass architecture to dotnet test --- .../integration-tests/posix-only/dotnet_test_mstest/test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py index 345d26a1516..ff14366807d 100644 --- a/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py +++ b/csharp/ql/integration-tests/posix-only/dotnet_test_mstest/test.py @@ -1,3 +1,4 @@ +import platform from create_database_utils import * from diagnostics_test_utils import * @@ -5,6 +6,9 @@ from diagnostics_test_utils import * run_codeql_database_create(['dotnet test'], test_db="test-db", lang="csharp") check_diagnostics() +# Fix `dotnet test` picking `x64` on arm-based macOS +architecture = '-a arm64' if platform.machine() == 'arm64' else '' + # Explicitly build and then run tests. -run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout --os win', 'dotnet test myout/dotnet_test_mstest.exe'], test_db="test2-db", lang="csharp") +run_codeql_database_create(['dotnet clean', 'rm -rf test-db', 'dotnet build -o myout --os win', 'dotnet test myout/dotnet_test_mstest.exe ' + architecture], test_db="test2-db", lang="csharp") check_diagnostics(test_db="test2-db") From 81b08b4399a5175bf530374fd71bf4e71cd14e20 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Jun 2023 00:18:12 +0000 Subject: [PATCH 199/219] Add changed framework coverage reports --- java/documentation/library-coverage/coverage.csv | 2 +- java/documentation/library-coverage/coverage.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 93c93f8ef46..acfd9b9224c 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -22,7 +22,7 @@ com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 com.google.common.flogger,29,,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,, com.google.common.io,8,,73,,1,,,,,,,,,,,,,,7,,,,,,,,,,,,,,,,,,,72,1 -com.google.gson,,,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,14 +com.google.gson,,,44,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30,14 com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, com.jcraft.jsch,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,1, com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index ffd3ce0ed91..3e2043369dc 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -22,6 +22,6 @@ Java framework & library support Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,115,4,,28,14,,35 - Others,"``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,894,528,66,,18,18,,195 - Totals,,255,9194,1997,263,10,122,33,1,385 + Others,"``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,899,528,66,,18,18,,195 + Totals,,255,9199,1997,263,10,122,33,1,385 From 7aede5034d1f12347d9f72d17dc15bb17e6a3730 Mon Sep 17 00:00:00 2001 From: Jami <57204504+jcogs33@users.noreply.github.com> Date: Thu, 8 Jun 2023 22:52:34 -0400 Subject: [PATCH 200/219] Docs: fix typo --- docs/codeql/ql-language-reference/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/ql-language-reference/modules.rst b/docs/codeql/ql-language-reference/modules.rst index ee0d1f7966b..42344c72e3d 100644 --- a/docs/codeql/ql-language-reference/modules.rst +++ b/docs/codeql/ql-language-reference/modules.rst @@ -139,7 +139,7 @@ Parameterized modules ===================== Parameterized modules are QL's approach to generic programming. -Similar to explicit modules, parameterized modules are defined within other modules using the keywork ``module``. +Similar to explicit modules, parameterized modules are defined within other modules using the keyword ``module``. In addition to the module name, parameterized modules declare one or more parameters between the name and the module body. For example, consider the module ``M``, which takes two predicate parameters and defines a new predicate From 1d87f0793b613b25ed78694ce0c84bc60ce60d2d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 11:40:35 +0200 Subject: [PATCH 201/219] Dataflow: Minor refactor. --- .../java/dataflow/internal/DataFlowImpl.qll | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..77110c0db0d 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1204,14 +1204,6 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t, ap) } - pragma[inline] - additional predicate fwdFlow( - NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap - ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) - } - pragma[assume_small_delta] pragma[nomagic] private predicate fwdFlow0( @@ -1359,7 +1351,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1512,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1772,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -2197,8 +2189,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2274,8 +2266,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2365,7 +2357,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2571,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2632,7 +2624,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2641,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } From ad461a87b45113fb29a63dd1ebf2274021b4a5e1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 8 May 2023 13:56:26 +0200 Subject: [PATCH 202/219] Dataflow: Strengthen tracked types. --- .../java/dataflow/internal/DataFlowImpl.qll | 92 +++++++++++++++---- .../dataflow/internal/DataFlowPrivate.qll | 13 ++- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 77110c0db0d..8520f308f55 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,9 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) + } + + private predicate fwdFlow1( + NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa + ) { + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1331,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1955,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2210,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2325,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2601,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2812,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3332,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 22f84241c96..4782e65b7e7 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -176,7 +176,7 @@ predicate expectsContent(Node n, ContentSet c) { * possible flow. A single type is used for all numeric types to account for * numeric conversions, and otherwise the erasure is used. */ -DataFlowType getErasedRepr(Type t) { +RefType getErasedRepr(Type t) { exists(Type e | e = t.getErasure() | if e instanceof NumericOrCharType then result.(BoxedType).getPrimitiveType().getName() = "double" @@ -189,6 +189,15 @@ DataFlowType getErasedRepr(Type t) { t instanceof NullType and result instanceof TypeObject } +class DataFlowType extends SrcRefType { + DataFlowType() { this = getErasedRepr(_) } +} + +pragma[nomagic] +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { + t1.getASourceSupertype+() = t2 +} + pragma[noinline] DataFlowType getNodeType(Node n) { result = getErasedRepr(n.getTypeBound()) @@ -259,8 +268,6 @@ class DataFlowCallable extends TDataFlowCallable { class DataFlowExpr = Expr; -class DataFlowType = RefType; - private newtype TDataFlowCall = TCall(Call c) or TSummaryCall(SummarizedCallable c, Node receiver) { From e8cea79f1d4f4ee71329cfbdf364f1cb2a596fd3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 11:45:00 +0200 Subject: [PATCH 203/219] Dataflow: Sync. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../csharp/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../go/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../dataflow/new/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../ruby/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ .../swift/dataflow/internal/DataFlowImpl.qll | 124 ++++++++++++------ 7 files changed, 588 insertions(+), 280 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index ddf98ac0f2f..8520f308f55 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> { DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow ); - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t); bindingset[typ, contentType] predicate typecheckStore(Typ typ, DataFlowType contentType); @@ -1199,17 +1199,20 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa ) { - fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and - PrevStage::revFlow(node, state, apa) and - filter(node, state, t, ap) + fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa) } - pragma[inline] - additional predicate fwdFlow( + private predicate fwdFlow1( NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap + ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa ) { - fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) + fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and + PrevStage::revFlow(node, state, apa) and + filter(node, state, t0, ap, t) + } + + private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { + fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } pragma[assume_small_delta] @@ -1339,6 +1342,11 @@ module Impl<FullStateConfigSig Config> { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and cons = apCons(c, t1, tail) + or + exists(Typ t0 | + typeStrengthen(t0, cons, t2) and + fwdFlowConsCand(t0, cons, c, t1, tail) + ) } pragma[nomagic] @@ -1359,7 +1367,7 @@ module Impl<FullStateConfigSig Config> { ParamNodeOption summaryCtx, TypOption argT, ApOption argAp ) { exists(ApHeadContent apc | - fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and + fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and apc = getHeadContent(ap) and readStepCand0(node1, apc, c, node2) ) @@ -1520,14 +1528,14 @@ module Impl<FullStateConfigSig Config> { NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { revFlow0(node, state, returnCtx, returnAp, ap) and - fwdFlow(node, state, _, _, _, _, _, ap) + fwdFlow(node, state, _, _, _, _, _, ap, _) } pragma[nomagic] private predicate revFlow0( NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap ) { - fwdFlow(node, state, _, _, _, _, _, ap) and + fwdFlow(node, state, _, _, _, _, _, ap, _) and sinkNode(node, state) and ( if hasSinkCallCtx() @@ -1780,13 +1788,13 @@ module Impl<FullStateConfigSig Config> { boolean fwd, int nodes, int fields, int conscand, int states, int tuples ) { fwd = true and - nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and + nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and fields = count(Content f0 | fwdConsCand(f0, _, _)) and conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and - states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and + states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and tuples = count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, - ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap)) + ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _)) or fwd = false and nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and @@ -1963,10 +1971,10 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { PrevStage::revFlowState(state) and - exists(t) and + t0 = t and exists(ap) and not stateBarrier(node, state) and ( @@ -2197,8 +2205,8 @@ module Impl<FullStateConfigSig Config> { import BooleanCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and exists(lcc) @@ -2218,10 +2226,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + // We can get away with not using type strengthening here, since we aren't + // going to use the tracked types in the construction of Stage 4 access + // paths. For Stage 4 and onwards, the tracked types must be consistent as + // the cons candidates including types are used to construct subsequent + // access path approximations. + t0 = t and + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and ( notExpectsContent(node) or @@ -2274,8 +2288,8 @@ module Impl<FullStateConfigSig Config> { pragma[nomagic] predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2333,11 +2347,18 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and ( notExpectsContent(node) or @@ -2365,7 +2386,7 @@ module Impl<FullStateConfigSig Config> { exists(AccessPathFront apf | Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _, - apf) + apf, _) ) } @@ -2579,8 +2600,8 @@ module Impl<FullStateConfigSig Config> { import LocalCallContext predicate localStep( - NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, - DataFlowType t, LocalCc lcc + NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t, + LocalCc lcc ) { localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and @@ -2609,9 +2630,16 @@ module Impl<FullStateConfigSig Config> { ) } - bindingset[node, state, t, ap] - predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and + bindingset[node, state, t0, ap] + predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { + ( + if castingNodeEx(node) + then + exists(Typ nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) and exists(state) and exists(ap) } @@ -2632,7 +2660,7 @@ module Impl<FullStateConfigSig Config> { Stage5::parameterMayFlowThrough(p, _) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _, - TAccessPathApproxSome(apa), _, apa0) + TAccessPathApproxSome(apa), _, apa0, _) ) } @@ -2649,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and + Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -2820,9 +2848,7 @@ module Impl<FullStateConfigSig Config> { ap = TAccessPathNil() or // ... or a step from an existing PathNode to another node. - pathStep(_, node, state, cc, sc, t, ap) and - Stage5::revFlow(node, state, ap.getApprox()) and - (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) + pathStep(_, node, state, cc, sc, t, ap) } or TPathNodeSink(NodeEx node, FlowState state) { exists(PathNodeMid sink | @@ -3340,13 +3366,31 @@ module Impl<FullStateConfigSig Config> { ap = mid.getAp() } + private predicate pathStep( + PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, + AccessPath ap + ) { + exists(DataFlowType t0 | + pathStep0(mid, node, state, cc, sc, t0, ap) and + Stage5::revFlow(node, state, ap.getApprox()) and + ( + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + ) + ) + } + /** * Holds if data may flow from `mid` to `node`. The last step in or out of * a callable is recorded by `cc`. */ pragma[assume_small_delta] pragma[nomagic] - private predicate pathStep( + private predicate pathStep0( PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap ) { From 96c1b5b0a9f640008555c230ba3ca9ec15986031 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 12:10:03 +0200 Subject: [PATCH 204/219] C#: Enable type strengthening. --- .../csharp/dataflow/internal/DataFlowPrivate.qll | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index d683e03dc2d..578c8fb8ed5 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1984,6 +1984,21 @@ private class DataFlowUnknownType extends DataFlowType { DataFlowUnknownType() { this = Gvn::getGlobalValueNumber(any(UnknownType ut)) } } +private predicate uselessTypebound(DataFlowType t) { + t instanceof DataFlowUnknownType or + t instanceof Gvn::TypeParameterGvnType +} + +pragma[nomagic] +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { + t1 != t2 and + t1 = getANonTypeParameterSubTypeRestricted(t2) + or + t1 instanceof RelevantDataFlowType and + not uselessTypebound(t1) and + uselessTypebound(t2) +} + /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. From fd832416d8ec214edf28cdeffbdc58c6c13c98c7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 12:10:31 +0200 Subject: [PATCH 205/219] Dataflow: Add empty type strengthening predicate for languages without type pruning. --- .../lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 2 ++ .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 2 ++ .../lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 2 ++ ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 2 ++ swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll | 2 ++ 6 files changed, 12 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 9b4e0e6a4f9..115989e3dea 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -205,6 +205,8 @@ predicate clearsContent(Node n, Content c) { */ predicate expectsContent(Node n, ContentSet c) { none() } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** Gets the type of `n` used for type pruning. */ Type getNodeType(Node n) { suppressUnusedNode(n) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index cc8d0cdbe94..33ff6f74775 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -753,6 +753,8 @@ predicate clearsContent(Node n, Content c) { */ predicate expectsContent(Node n, ContentSet c) { none() } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** Gets the type of `n` used for type pruning. */ DataFlowType getNodeType(Node n) { suppressUnusedNode(n) and diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index d45587aa3d4..e0adc9f5790 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -200,6 +200,8 @@ predicate expectsContent(Node n, ContentSet c) { FlowSummaryImpl::Private::Steps::summaryExpectsContent(n, c) } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** Gets the type of `n` used for type pruning. */ DataFlowType getNodeType(Node n) { result = TTodoDataFlowType() and exists(n) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 693a2f13fc4..de493e5bb53 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -502,6 +502,8 @@ class CastNode extends Node { pragma[inline] predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** * Gets the type of `node`. */ diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 6a7d87e9bd5..7708eff235a 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -1231,6 +1231,8 @@ class DataFlowType extends TDataFlowType { string toString() { result = "" } } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** Gets the type of `n` used for type pruning. */ DataFlowType getNodeType(NodeImpl n) { result = TTodoDataFlowType() and exists(n) } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index 7b2bc359c9a..ab2bbc050a4 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -793,6 +793,8 @@ class DataFlowType extends TDataFlowType { string toString() { result = "" } } +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } + /** Gets the type of `n` used for type pruning. */ DataFlowType getNodeType(NodeImpl n) { any() // return the singleton DataFlowType until we support type pruning for Swift From 4633abe19e95503362526406b249154167718421 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 13:26:38 +0200 Subject: [PATCH 206/219] Java: Autoformat --- .../semmle/code/java/dataflow/internal/DataFlowPrivate.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 4782e65b7e7..01bf90cb7ba 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -194,9 +194,7 @@ class DataFlowType extends SrcRefType { } pragma[nomagic] -predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { - t1.getASourceSupertype+() = t2 -} +predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { t1.getASourceSupertype+() = t2 } pragma[noinline] DataFlowType getNodeType(Node n) { From 21dea62e99754629e978d32bee8e88204561df1e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 9 May 2023 14:42:50 +0200 Subject: [PATCH 207/219] C#: Fix qltests. --- .../collections/CollectionFlow.expected | 12 ++--- .../dataflow/external-models/ExternalFlow.cs | 6 +-- .../external-models/ExternalFlow.expected | 14 +++--- .../external-models/ExternalFlow.ext.yml | 4 +- .../dataflow/global/DataFlowPath.expected | 10 ++-- .../global/TaintTrackingPath.expected | 10 ++-- .../EntityFramework/Dataflow.expected | 48 +++++++++---------- .../CWE-338/InsecureRandomness.expected | 14 +++--- 8 files changed, 58 insertions(+), 60 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index d5bbeef765a..1aabed1e806 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -214,8 +214,8 @@ edges | CollectionFlow.cs:385:58:385:61 | dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:385:67:385:70 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | | CollectionFlow.cs:385:67:385:70 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:385:67:385:73 | access to indexer : A | | CollectionFlow.cs:387:59:387:62 | dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:387:68:387:71 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | -| CollectionFlow.cs:387:68:387:71 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : Object [property Value] : A | -| CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : Object [property Value] : A | CollectionFlow.cs:387:68:387:85 | access to property Value : A | +| CollectionFlow.cs:387:68:387:71 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : KeyValuePair<Int32,T> [property Value] : A | +| CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : KeyValuePair<Int32,T> [property Value] : A | CollectionFlow.cs:387:68:387:85 | access to property Value : A | | CollectionFlow.cs:389:60:389:63 | dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:389:69:389:72 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | | CollectionFlow.cs:389:69:389:72 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | CollectionFlow.cs:389:69:389:79 | access to property Values : ICollection<T> [element] : A | | CollectionFlow.cs:389:69:389:79 | access to property Values : ICollection<T> [element] : A | CollectionFlow.cs:389:69:389:87 | call to method First<T> : A | @@ -223,8 +223,8 @@ edges | CollectionFlow.cs:391:67:391:70 | access to parameter dict : Dictionary<T,T> [element, property Key] : A | CollectionFlow.cs:391:67:391:75 | access to property Keys : ICollection<T> [element] : A | | CollectionFlow.cs:391:67:391:75 | access to property Keys : ICollection<T> [element] : A | CollectionFlow.cs:391:67:391:83 | call to method First<T> : A | | CollectionFlow.cs:393:57:393:60 | dict : Dictionary<T,T> [element, property Key] : A | CollectionFlow.cs:393:66:393:69 | access to parameter dict : Dictionary<T,T> [element, property Key] : A | -| CollectionFlow.cs:393:66:393:69 | access to parameter dict : Dictionary<T,T> [element, property Key] : A | CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : Object [property Key] : A | -| CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : Object [property Key] : A | CollectionFlow.cs:393:66:393:81 | access to property Key : A | +| CollectionFlow.cs:393:66:393:69 | access to parameter dict : Dictionary<T,T> [element, property Key] : A | CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : KeyValuePair<T,Int32> [property Key] : A | +| CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : KeyValuePair<T,Int32> [property Key] : A | CollectionFlow.cs:393:66:393:81 | access to property Key : A | | CollectionFlow.cs:395:49:395:52 | args : A[] [element] : A | CollectionFlow.cs:395:63:395:66 | access to parameter args : A[] [element] : A | | CollectionFlow.cs:395:49:395:52 | args : null [element] : A | CollectionFlow.cs:395:63:395:66 | access to parameter args : null [element] : A | | CollectionFlow.cs:395:63:395:66 | access to parameter args : A[] [element] : A | CollectionFlow.cs:395:63:395:69 | access to array element | @@ -440,7 +440,7 @@ nodes | CollectionFlow.cs:385:67:385:73 | access to indexer : A | semmle.label | access to indexer : A | | CollectionFlow.cs:387:59:387:62 | dict : Dictionary<T,T> [element, property Value] : A | semmle.label | dict : Dictionary<T,T> [element, property Value] : A | | CollectionFlow.cs:387:68:387:71 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | semmle.label | access to parameter dict : Dictionary<T,T> [element, property Value] : A | -| CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : Object [property Value] : A | semmle.label | call to method First<KeyValuePair<Int32,T>> : Object [property Value] : A | +| CollectionFlow.cs:387:68:387:79 | call to method First<KeyValuePair<Int32,T>> : KeyValuePair<Int32,T> [property Value] : A | semmle.label | call to method First<KeyValuePair<Int32,T>> : KeyValuePair<Int32,T> [property Value] : A | | CollectionFlow.cs:387:68:387:85 | access to property Value : A | semmle.label | access to property Value : A | | CollectionFlow.cs:389:60:389:63 | dict : Dictionary<T,T> [element, property Value] : A | semmle.label | dict : Dictionary<T,T> [element, property Value] : A | | CollectionFlow.cs:389:69:389:72 | access to parameter dict : Dictionary<T,T> [element, property Value] : A | semmle.label | access to parameter dict : Dictionary<T,T> [element, property Value] : A | @@ -452,7 +452,7 @@ nodes | CollectionFlow.cs:391:67:391:83 | call to method First<T> : A | semmle.label | call to method First<T> : A | | CollectionFlow.cs:393:57:393:60 | dict : Dictionary<T,T> [element, property Key] : A | semmle.label | dict : Dictionary<T,T> [element, property Key] : A | | CollectionFlow.cs:393:66:393:69 | access to parameter dict : Dictionary<T,T> [element, property Key] : A | semmle.label | access to parameter dict : Dictionary<T,T> [element, property Key] : A | -| CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : Object [property Key] : A | semmle.label | call to method First<KeyValuePair<T,Int32>> : Object [property Key] : A | +| CollectionFlow.cs:393:66:393:77 | call to method First<KeyValuePair<T,Int32>> : KeyValuePair<T,Int32> [property Key] : A | semmle.label | call to method First<KeyValuePair<T,Int32>> : KeyValuePair<T,Int32> [property Key] : A | | CollectionFlow.cs:393:66:393:81 | access to property Key : A | semmle.label | access to property Key : A | | CollectionFlow.cs:395:49:395:52 | args : A[] [element] : A | semmle.label | args : A[] [element] : A | | CollectionFlow.cs:395:49:395:52 | args : null [element] : A | semmle.label | args : null [element] : A | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs index 05772dfb29a..7a0e896e54d 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs @@ -149,9 +149,9 @@ namespace My.Qltest static T Apply<S, T>(Func<S, T> f, S s) => throw null; - static S[] Map<S, T>(S[] elements, Func<S, T> f) => throw null; + static T[] Map<S, T>(S[] elements, Func<S, T> f) => throw null; - static void Apply2<S>(Action<S> f, S s1, S s2) => throw null; + static void Apply2(Action<object> f, D d1, D d2) => throw null; static void Parse(string s, out int i) => throw null; @@ -235,4 +235,4 @@ namespace My.Qltest static void Sink(object o) { } } -} \ No newline at end of file +} diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected index 09ce9945cdf..c69a86a5cb3 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected @@ -12,10 +12,10 @@ edges | ExternalFlow.cs:30:13:30:16 | [post] this access : D [field Field] : Object | ExternalFlow.cs:31:18:31:21 | this access : D [field Field] : Object | | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | ExternalFlow.cs:30:13:30:16 | [post] this access : D [field Field] : Object | | ExternalFlow.cs:31:18:31:21 | this access : D [field Field] : Object | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | -| ExternalFlow.cs:36:19:36:62 | (...) ... : Object [field Field] : Object | ExternalFlow.cs:36:18:36:69 | access to field Field | +| ExternalFlow.cs:36:19:36:62 | (...) ... : D [field Field] : Object | ExternalFlow.cs:36:18:36:69 | access to field Field | | ExternalFlow.cs:36:22:36:25 | [post] this access : D [field Field] : Object | ExternalFlow.cs:37:18:37:21 | this access : D [field Field] : Object | | ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter : D [field Field2, field Field] : Object | ExternalFlow.cs:36:22:36:62 | access to field Field2 : Object [field Field] : Object | -| ExternalFlow.cs:36:22:36:62 | access to field Field2 : Object [field Field] : Object | ExternalFlow.cs:36:19:36:62 | (...) ... : Object [field Field] : Object | +| ExternalFlow.cs:36:22:36:62 | access to field Field2 : Object [field Field] : Object | ExternalFlow.cs:36:19:36:62 | (...) ... : D [field Field] : Object | | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:36:22:36:25 | [post] this access : D [field Field] : Object | | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter : D [field Field2, field Field] : Object | | ExternalFlow.cs:37:18:37:21 | this access : D [field Field] : Object | ExternalFlow.cs:37:18:37:27 | access to field Field | @@ -38,8 +38,7 @@ edges | ExternalFlow.cs:72:23:72:23 | o : Object | ExternalFlow.cs:72:35:72:35 | access to parameter o | | ExternalFlow.cs:77:24:77:58 | call to method Map<Int32,Object> : T[] [element] : Object | ExternalFlow.cs:78:18:78:21 | access to local variable objs : T[] [element] : Object | | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | ExternalFlow.cs:77:24:77:58 | call to method Map<Int32,Object> : T[] [element] : Object | -| ExternalFlow.cs:78:18:78:21 | access to local variable objs : T[] [element] : Object | ExternalFlow.cs:78:18:78:24 | access to array element : Object | -| ExternalFlow.cs:78:18:78:24 | access to array element : Object | ExternalFlow.cs:78:18:78:24 | (...) ... | +| ExternalFlow.cs:78:18:78:21 | access to local variable objs : T[] [element] : Object | ExternalFlow.cs:78:18:78:24 | access to array element | | ExternalFlow.cs:83:30:83:45 | { ..., ... } : null [element] : Object | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | ExternalFlow.cs:83:30:83:45 | { ..., ... } : null [element] : Object | | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object | ExternalFlow.cs:85:18:85:22 | access to local variable objs2 : T[] [element] : Object | @@ -91,7 +90,7 @@ nodes | ExternalFlow.cs:31:18:31:21 | this access : D [field Field] : Object | semmle.label | this access : D [field Field] : Object | | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | semmle.label | call to method StepFieldGetter | | ExternalFlow.cs:36:18:36:69 | access to field Field | semmle.label | access to field Field | -| ExternalFlow.cs:36:19:36:62 | (...) ... : Object [field Field] : Object | semmle.label | (...) ... : Object [field Field] : Object | +| ExternalFlow.cs:36:19:36:62 | (...) ... : D [field Field] : Object | semmle.label | (...) ... : D [field Field] : Object | | ExternalFlow.cs:36:22:36:25 | [post] this access : D [field Field] : Object | semmle.label | [post] this access : D [field Field] : Object | | ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter : D [field Field2, field Field] : Object | semmle.label | call to method StepFieldSetter : D [field Field2, field Field] : Object | | ExternalFlow.cs:36:22:36:62 | access to field Field2 : Object [field Field] : Object | semmle.label | access to field Field2 : Object [field Field] : Object | @@ -124,8 +123,7 @@ nodes | ExternalFlow.cs:77:24:77:58 | call to method Map<Int32,Object> : T[] [element] : Object | semmle.label | call to method Map<Int32,Object> : T[] [element] : Object | | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:78:18:78:21 | access to local variable objs : T[] [element] : Object | semmle.label | access to local variable objs : T[] [element] : Object | -| ExternalFlow.cs:78:18:78:24 | (...) ... | semmle.label | (...) ... | -| ExternalFlow.cs:78:18:78:24 | access to array element : Object | semmle.label | access to array element : Object | +| ExternalFlow.cs:78:18:78:24 | access to array element | semmle.label | access to array element | | ExternalFlow.cs:83:30:83:45 | { ..., ... } : null [element] : Object | semmle.label | { ..., ... } : null [element] : Object | | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object | semmle.label | call to method Map<Object,Object> : T[] [element] : Object | @@ -184,7 +182,7 @@ subpaths | ExternalFlow.cs:60:47:60:47 | access to parameter o | ExternalFlow.cs:60:64:60:75 | object creation of type Object : Object | ExternalFlow.cs:60:47:60:47 | access to parameter o | $@ | ExternalFlow.cs:60:64:60:75 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:66:18:66:18 | access to local variable o | ExternalFlow.cs:65:45:65:56 | object creation of type Object : Object | ExternalFlow.cs:66:18:66:18 | access to local variable o | $@ | ExternalFlow.cs:65:45:65:56 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:72:35:72:35 | access to parameter o | ExternalFlow.cs:71:32:71:43 | object creation of type Object : Object | ExternalFlow.cs:72:35:72:35 | access to parameter o | $@ | ExternalFlow.cs:71:32:71:43 | object creation of type Object : Object | object creation of type Object : Object | -| ExternalFlow.cs:78:18:78:24 | (...) ... | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | ExternalFlow.cs:78:18:78:24 | (...) ... | $@ | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:78:18:78:24 | access to array element | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | ExternalFlow.cs:78:18:78:24 | access to array element | $@ | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:85:18:85:25 | access to array element | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | ExternalFlow.cs:85:18:85:25 | access to array element | $@ | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:92:18:92:18 | (...) ... | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | ExternalFlow.cs:92:18:92:18 | (...) ... | $@ | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | object creation of type String : String | | ExternalFlow.cs:102:22:102:22 | access to parameter d | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml index f626949e6f4..a2bf0d8b525 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml @@ -16,8 +16,8 @@ extensions: - ["My.Qltest", "D", false, "StepElementSetter", "(System.Object)", "", "Argument[0]", "Argument[this].Element", "value", "manual"] - ["My.Qltest", "D", false, "Apply<,>", "(System.Func<S,T>,S)", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"] - ["My.Qltest", "D", false, "Apply<,>", "(System.Func<S,T>,S)", "", "Argument[0].ReturnValue", "ReturnValue", "value", "manual"] - - ["My.Qltest", "D", false, "Apply2<>", "(System.Action<S>,S,S)", "", "Argument[1].Field[My.Qltest.D.Field]", "Argument[0].Parameter[0]", "value", "manual"] - - ["My.Qltest", "D", false, "Apply2<>", "(System.Action<S>,S,S)", "", "Argument[2].Field[My.Qltest.D.Field2]", "Argument[0].Parameter[0]", "value", "manual"] + - ["My.Qltest", "D", false, "Apply2", "(System.Action<System.Object>,My.Qltest.D,My.Qltest.D)", "", "Argument[1].Field[My.Qltest.D.Field]", "Argument[0].Parameter[0]", "value", "manual"] + - ["My.Qltest", "D", false, "Apply2", "(System.Action<System.Object>,My.Qltest.D,My.Qltest.D)", "", "Argument[2].Field[My.Qltest.D.Field2]", "Argument[0].Parameter[0]", "value", "manual"] - ["My.Qltest", "D", false, "Map<,>", "(S[],System.Func<S,T>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"] - ["My.Qltest", "D", false, "Map<,>", "(S[],System.Func<S,T>)", "", "Argument[1].ReturnValue", "ReturnValue.Element", "value", "manual"] - ["My.Qltest", "D", false, "Parse", "(System.String,System.Int32)", "", "Argument[0]", "Argument[1]", "taint", "manual"] diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index bce1914e42b..767e66301ce 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -267,7 +267,7 @@ edges | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:31:514:32 | [post] access to local variable y1 : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:36:514:37 | [post] access to local variable y2 : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:42:514:43 | [post] access to local variable y3 : SimpleClass [field field] : String | -| GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | +| GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:544:20:544:20 | [post] access to local variable x : SimpleClass [field field] : String | @@ -286,8 +286,8 @@ edges | GlobalDataFlow.cs:515:15:515:16 | access to local variable y1 : SimpleClass [field field] : String | GlobalDataFlow.cs:515:15:515:22 | access to field field | | GlobalDataFlow.cs:516:15:516:16 | access to local variable y2 : SimpleClass [field field] : String | GlobalDataFlow.cs:516:15:516:22 | access to field field | | GlobalDataFlow.cs:517:15:517:16 | access to local variable y3 : SimpleClass [field field] : String | GlobalDataFlow.cs:517:15:517:22 | access to field field | -| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | -| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:21 | access to field field | +| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | +| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:21 | access to field field | | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | GlobalDataFlow.cs:533:15:533:15 | access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | GlobalDataFlow.cs:534:15:534:15 | access to local variable y : SimpleClass [field field] : String | | GlobalDataFlow.cs:533:15:533:15 | access to parameter x : SimpleClass [field field] : String | GlobalDataFlow.cs:533:15:533:21 | access to field field | @@ -579,8 +579,8 @@ nodes | GlobalDataFlow.cs:516:15:516:22 | access to field field | semmle.label | access to field field | | GlobalDataFlow.cs:517:15:517:16 | access to local variable y3 : SimpleClass [field field] : String | semmle.label | access to local variable y3 : SimpleClass [field field] : String | | GlobalDataFlow.cs:517:15:517:22 | access to field field | semmle.label | access to field field | -| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | semmle.label | [post] access to local variable x : SimpleClass [field field] : String | -| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | semmle.label | access to local variable x : SimpleClass [field field] : String | +| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | semmle.label | [post] access to local variable x : SubSimpleClass [field field] : String | +| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | semmle.label | access to local variable x : SubSimpleClass [field field] : String | | GlobalDataFlow.cs:526:15:526:21 | access to field field | semmle.label | access to field field | | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | semmle.label | [post] access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | semmle.label | [post] access to local variable y : SimpleClass [field field] : String | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 5dae90d82a6..dec8a134712 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -293,7 +293,7 @@ edges | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:31:514:32 | [post] access to local variable y1 : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:36:514:37 | [post] access to local variable y2 : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:514:42:514:43 | [post] access to local variable y3 : SimpleClass [field field] : String | -| GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | +| GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | | GlobalDataFlow.cs:500:9:500:10 | [post] access to parameter sc : SimpleClass [field field] : String | GlobalDataFlow.cs:544:20:544:20 | [post] access to local variable x : SimpleClass [field field] : String | @@ -312,8 +312,8 @@ edges | GlobalDataFlow.cs:515:15:515:16 | access to local variable y1 : SimpleClass [field field] : String | GlobalDataFlow.cs:515:15:515:22 | access to field field | | GlobalDataFlow.cs:516:15:516:16 | access to local variable y2 : SimpleClass [field field] : String | GlobalDataFlow.cs:516:15:516:22 | access to field field | | GlobalDataFlow.cs:517:15:517:16 | access to local variable y3 : SimpleClass [field field] : String | GlobalDataFlow.cs:517:15:517:22 | access to field field | -| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | -| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:21 | access to field field | +| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | +| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | GlobalDataFlow.cs:526:15:526:21 | access to field field | | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | GlobalDataFlow.cs:533:15:533:15 | access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | GlobalDataFlow.cs:534:15:534:15 | access to local variable y : SimpleClass [field field] : String | | GlobalDataFlow.cs:533:15:533:15 | access to parameter x : SimpleClass [field field] : String | GlobalDataFlow.cs:533:15:533:21 | access to field field | @@ -633,8 +633,8 @@ nodes | GlobalDataFlow.cs:516:15:516:22 | access to field field | semmle.label | access to field field | | GlobalDataFlow.cs:517:15:517:16 | access to local variable y3 : SimpleClass [field field] : String | semmle.label | access to local variable y3 : SimpleClass [field field] : String | | GlobalDataFlow.cs:517:15:517:22 | access to field field | semmle.label | access to field field | -| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SimpleClass [field field] : String | semmle.label | [post] access to local variable x : SimpleClass [field field] : String | -| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SimpleClass [field field] : String | semmle.label | access to local variable x : SimpleClass [field field] : String | +| GlobalDataFlow.cs:525:33:525:33 | [post] access to local variable x : SubSimpleClass [field field] : String | semmle.label | [post] access to local variable x : SubSimpleClass [field field] : String | +| GlobalDataFlow.cs:526:15:526:15 | access to local variable x : SubSimpleClass [field field] : String | semmle.label | access to local variable x : SubSimpleClass [field field] : String | | GlobalDataFlow.cs:526:15:526:21 | access to field field | semmle.label | access to field field | | GlobalDataFlow.cs:532:20:532:20 | [post] access to parameter x : SimpleClass [field field] : String | semmle.label | [post] access to parameter x : SimpleClass [field field] : String | | GlobalDataFlow.cs:532:25:532:25 | [post] access to local variable y : SimpleClass [field field] : String | semmle.label | [post] access to local variable y : SimpleClass [field field] : String | diff --git a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected index 811f1a04d8b..a9d4895fb46 100644 --- a/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected +++ b/csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.expected @@ -74,14 +74,14 @@ edges | EntityFramework.cs:196:13:196:23 | [post] access to property Persons : DbSet<T> [element, property Name] : String | EntityFramework.cs:196:13:196:15 | [post] access to local variable ctx : MyContext [property Persons, element, property Name] : String | | EntityFramework.cs:196:29:196:29 | access to parameter p : Person [property Name] : String | EntityFramework.cs:196:13:196:23 | [post] access to property Persons : DbSet<T> [element, property Name] : String | | EntityFramework.cs:197:13:197:15 | access to local variable ctx : MyContext [property Persons, element, property Name] : String | EntityFramework.cs:204:18:204:28 | access to property Persons : DbSet<Person> [element, property Name] : String | -| EntityFramework.cs:204:18:204:28 | access to property Persons : DbSet<Person> [element, property Name] : String | EntityFramework.cs:204:18:204:36 | call to method First<Person> : Object [property Name] : String | -| EntityFramework.cs:204:18:204:36 | call to method First<Person> : Object [property Name] : String | EntityFramework.cs:204:18:204:41 | access to property Name | -| EntityFramework.cs:212:18:212:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | EntityFramework.cs:212:18:212:38 | call to method First<Address> : Object [property Street] : String | -| EntityFramework.cs:212:18:212:38 | call to method First<Address> : Object [property Street] : String | EntityFramework.cs:212:18:212:45 | access to property Street | -| EntityFramework.cs:219:18:219:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | EntityFramework.cs:219:18:219:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | -| EntityFramework.cs:219:18:219:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | EntityFramework.cs:219:18:219:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | -| EntityFramework.cs:219:18:219:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | EntityFramework.cs:219:18:219:54 | call to method First<Address> : Object [property Street] : String | -| EntityFramework.cs:219:18:219:54 | call to method First<Address> : Object [property Street] : String | EntityFramework.cs:219:18:219:61 | access to property Street | +| EntityFramework.cs:204:18:204:28 | access to property Persons : DbSet<Person> [element, property Name] : String | EntityFramework.cs:204:18:204:36 | call to method First<Person> : Person [property Name] : String | +| EntityFramework.cs:204:18:204:36 | call to method First<Person> : Person [property Name] : String | EntityFramework.cs:204:18:204:41 | access to property Name | +| EntityFramework.cs:212:18:212:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | EntityFramework.cs:212:18:212:38 | call to method First<Address> : Address [property Street] : String | +| EntityFramework.cs:212:18:212:38 | call to method First<Address> : Address [property Street] : String | EntityFramework.cs:212:18:212:45 | access to property Street | +| EntityFramework.cs:219:18:219:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | EntityFramework.cs:219:18:219:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | +| EntityFramework.cs:219:18:219:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | EntityFramework.cs:219:18:219:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | +| EntityFramework.cs:219:18:219:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | EntityFramework.cs:219:18:219:54 | call to method First<Address> : Address [property Street] : String | +| EntityFramework.cs:219:18:219:54 | call to method First<Address> : Address [property Street] : String | EntityFramework.cs:219:18:219:61 | access to property Street | | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:84:35:84:45 | access to local variable taintSource : String | | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | EntityFrameworkCore.cs:85:18:85:42 | (...) ... | @@ -165,14 +165,14 @@ edges | EntityFrameworkCore.cs:229:13:229:23 | [post] access to property Persons : DbSet<T> [element, property Name] : String | EntityFrameworkCore.cs:229:13:229:15 | [post] access to local variable ctx : MyContext [property Persons, element, property Name] : String | | EntityFrameworkCore.cs:229:29:229:29 | access to parameter p : Person [property Name] : String | EntityFrameworkCore.cs:229:13:229:23 | [post] access to property Persons : DbSet<T> [element, property Name] : String | | EntityFrameworkCore.cs:230:13:230:15 | access to local variable ctx : MyContext [property Persons, element, property Name] : String | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons : DbSet<Person> [element, property Name] : String | -| EntityFrameworkCore.cs:237:18:237:28 | access to property Persons : DbSet<Person> [element, property Name] : String | EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Object [property Name] : String | -| EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Object [property Name] : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | -| EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Object [property Street] : String | -| EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Object [property Street] : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | -| EntityFrameworkCore.cs:252:18:252:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | -| EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Object [property Street] : String | -| EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Object [property Street] : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | +| EntityFrameworkCore.cs:237:18:237:28 | access to property Persons : DbSet<Person> [element, property Name] : String | EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Person [property Name] : String | +| EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Person [property Name] : String | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | +| EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Address [property Street] : String | +| EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Address [property Street] : String | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | +| EntityFrameworkCore.cs:252:18:252:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Address [property Street] : String | +| EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Address [property Street] : String | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | nodes | EntityFramework.cs:59:13:62:13 | { ..., ... } : Person [property Name] : String | semmle.label | { ..., ... } : Person [property Name] : String | | EntityFramework.cs:61:24:61:32 | "tainted" : String | semmle.label | "tainted" : String | @@ -237,15 +237,15 @@ nodes | EntityFramework.cs:196:29:196:29 | access to parameter p : Person [property Name] : String | semmle.label | access to parameter p : Person [property Name] : String | | EntityFramework.cs:197:13:197:15 | access to local variable ctx : MyContext [property Persons, element, property Name] : String | semmle.label | access to local variable ctx : MyContext [property Persons, element, property Name] : String | | EntityFramework.cs:204:18:204:28 | access to property Persons : DbSet<Person> [element, property Name] : String | semmle.label | access to property Persons : DbSet<Person> [element, property Name] : String | -| EntityFramework.cs:204:18:204:36 | call to method First<Person> : Object [property Name] : String | semmle.label | call to method First<Person> : Object [property Name] : String | +| EntityFramework.cs:204:18:204:36 | call to method First<Person> : Person [property Name] : String | semmle.label | call to method First<Person> : Person [property Name] : String | | EntityFramework.cs:204:18:204:41 | access to property Name | semmle.label | access to property Name | | EntityFramework.cs:212:18:212:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | semmle.label | access to property Addresses : DbSet<Address> [element, property Street] : String | -| EntityFramework.cs:212:18:212:38 | call to method First<Address> : Object [property Street] : String | semmle.label | call to method First<Address> : Object [property Street] : String | +| EntityFramework.cs:212:18:212:38 | call to method First<Address> : Address [property Street] : String | semmle.label | call to method First<Address> : Address [property Street] : String | | EntityFramework.cs:212:18:212:45 | access to property Street | semmle.label | access to property Street | | EntityFramework.cs:219:18:219:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | -| EntityFramework.cs:219:18:219:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | semmle.label | call to method First<Person> : Object [property Addresses, element, property Street] : String | +| EntityFramework.cs:219:18:219:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | semmle.label | call to method First<Person> : Person [property Addresses, element, property Street] : String | | EntityFramework.cs:219:18:219:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | semmle.label | access to property Addresses : ICollection<Address> [element, property Street] : String | -| EntityFramework.cs:219:18:219:54 | call to method First<Address> : Object [property Street] : String | semmle.label | call to method First<Address> : Object [property Street] : String | +| EntityFramework.cs:219:18:219:54 | call to method First<Address> : Address [property Street] : String | semmle.label | call to method First<Address> : Address [property Street] : String | | EntityFramework.cs:219:18:219:61 | access to property Street | semmle.label | access to property Street | | EntityFrameworkCore.cs:82:31:82:39 | "tainted" : String | semmle.label | "tainted" : String | | EntityFrameworkCore.cs:83:18:83:28 | access to local variable taintSource | semmle.label | access to local variable taintSource | @@ -318,15 +318,15 @@ nodes | EntityFrameworkCore.cs:229:29:229:29 | access to parameter p : Person [property Name] : String | semmle.label | access to parameter p : Person [property Name] : String | | EntityFrameworkCore.cs:230:13:230:15 | access to local variable ctx : MyContext [property Persons, element, property Name] : String | semmle.label | access to local variable ctx : MyContext [property Persons, element, property Name] : String | | EntityFrameworkCore.cs:237:18:237:28 | access to property Persons : DbSet<Person> [element, property Name] : String | semmle.label | access to property Persons : DbSet<Person> [element, property Name] : String | -| EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Object [property Name] : String | semmle.label | call to method First<Person> : Object [property Name] : String | +| EntityFrameworkCore.cs:237:18:237:36 | call to method First<Person> : Person [property Name] : String | semmle.label | call to method First<Person> : Person [property Name] : String | | EntityFrameworkCore.cs:237:18:237:41 | access to property Name | semmle.label | access to property Name | | EntityFrameworkCore.cs:245:18:245:30 | access to property Addresses : DbSet<Address> [element, property Street] : String | semmle.label | access to property Addresses : DbSet<Address> [element, property Street] : String | -| EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Object [property Street] : String | semmle.label | call to method First<Address> : Object [property Street] : String | +| EntityFrameworkCore.cs:245:18:245:38 | call to method First<Address> : Address [property Street] : String | semmle.label | call to method First<Address> : Address [property Street] : String | | EntityFrameworkCore.cs:245:18:245:45 | access to property Street | semmle.label | access to property Street | | EntityFrameworkCore.cs:252:18:252:28 | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | semmle.label | access to property Persons : DbSet<Person> [element, property Addresses, element, property Street] : String | -| EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Object [property Addresses, element, property Street] : String | semmle.label | call to method First<Person> : Object [property Addresses, element, property Street] : String | +| EntityFrameworkCore.cs:252:18:252:36 | call to method First<Person> : Person [property Addresses, element, property Street] : String | semmle.label | call to method First<Person> : Person [property Addresses, element, property Street] : String | | EntityFrameworkCore.cs:252:18:252:46 | access to property Addresses : ICollection<Address> [element, property Street] : String | semmle.label | access to property Addresses : ICollection<Address> [element, property Street] : String | -| EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Object [property Street] : String | semmle.label | call to method First<Address> : Object [property Street] : String | +| EntityFrameworkCore.cs:252:18:252:54 | call to method First<Address> : Address [property Street] : String | semmle.label | call to method First<Address> : Address [property Street] : String | | EntityFrameworkCore.cs:252:18:252:61 | access to property Street | semmle.label | access to property Street | subpaths #select diff --git a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected index 4cc2e788074..011ec3faee0 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected @@ -1,10 +1,10 @@ edges -| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Int32 | InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Int32 | -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Int32 | -| InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Byte | InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Byte | +| InsecureRandomness.cs:28:23:28:43 | (...) ... : Byte | InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Byte | +| InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | InsecureRandomness.cs:28:23:28:43 | (...) ... : Byte | | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result : StringBuilder [element] : String | InsecureRandomness.cs:31:16:31:21 | access to local variable result : StringBuilder [element] : String | | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result : StringBuilder [element] : String | -| InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Byte | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | | InsecureRandomness.cs:31:16:31:21 | access to local variable result : StringBuilder [element] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | @@ -16,12 +16,12 @@ nodes | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | semmle.label | call to method InsecureRandomString | | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | semmle.label | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | semmle.label | call to method InsecureRandomStringFromIndexer | -| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Int32 | semmle.label | [post] access to local variable data : Byte[] [element] : Int32 | -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | semmle.label | (...) ... : Int32 | +| InsecureRandomness.cs:28:13:28:16 | [post] access to local variable data : Byte[] [element] : Byte | semmle.label | [post] access to local variable data : Byte[] [element] : Byte | +| InsecureRandomness.cs:28:23:28:43 | (...) ... : Byte | semmle.label | (...) ... : Byte | | InsecureRandomness.cs:28:29:28:43 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | | InsecureRandomness.cs:29:13:29:18 | [post] access to local variable result : StringBuilder [element] : String | semmle.label | [post] access to local variable result : StringBuilder [element] : String | | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | semmle.label | call to method GetString : String | -| InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Int32 | semmle.label | access to local variable data : Byte[] [element] : Int32 | +| InsecureRandomness.cs:29:57:29:60 | access to local variable data : Byte[] [element] : Byte | semmle.label | access to local variable data : Byte[] [element] : Byte | | InsecureRandomness.cs:31:16:31:21 | access to local variable result : StringBuilder [element] : String | semmle.label | access to local variable result : StringBuilder [element] : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | From a0a9d30286d5607e6ae6e0ab45e676a589ec1bb4 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 10 May 2023 09:46:27 +0200 Subject: [PATCH 208/219] Java: Fix qltests. --- java/ql/lib/ext/java.sql.model.yml | 6 +- .../CWE-200/AndroidWebResourceResponse.qll | 8 +- .../CWE-020/Log4jInjectionTest.expected | 46 ++-- .../InsecureWebResourceResponse.expected | 246 +++++++++--------- .../CWE-200/SensitiveAndroidFileLeak.expected | 48 ++-- .../CWE-470/UnsafeReflection.expected | 14 +- .../CWE-552/UnsafeUrlForward.expected | 12 +- .../CWE-598/SensitiveGetQuery.expected | 16 +- .../security/CWE-755/NFEAndroidDoS.expected | 26 +- java/ql/test/ext/TestModels/Test.java | 2 +- .../CWE-078/ExecTaintedLocal.expected | 6 +- 11 files changed, 217 insertions(+), 213 deletions(-) diff --git a/java/ql/lib/ext/java.sql.model.yml b/java/ql/lib/ext/java.sql.model.yml index c93a89cfd2c..58985c886b5 100644 --- a/java/ql/lib/ext/java.sql.model.yml +++ b/java/ql/lib/ext/java.sql.model.yml @@ -21,7 +21,6 @@ extensions: extensible: summaryModel data: - ["java.sql", "Connection", True, "nativeSQL", "(String)", "", "Argument[0]", "ReturnValue", "taint", "hq-manual"] - - ["java.sql", "PreparedStatement", True, "setString", "(int,String)", "", "Argument[1]", "Argument[this]", "value", "manual"] - ["java.sql", "ResultSet", True, "getString", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"] - addsTo: @@ -31,13 +30,14 @@ extensions: - ["java.sql", "Connection", "createStatement", "()", "summary", "manual"] - ["java.sql", "PreparedStatement", "executeUpdate", "()", "summary", "manual"] - ["java.sql", "PreparedStatement", "executeQuery", "()", "summary", "manual"] + - ["java.sql", "PreparedStatement", "setInt", "(int,int)", "summary", "manual"] + - ["java.sql", "PreparedStatement", "setLong", "(int,long)", "summary", "manual"] + - ["java.sql", "PreparedStatement", "setString", "(int,String)", "summary", "manual"] - ["java.sql", "ResultSet", "next", "()", "summary", "manual"] - ["java.sql", "Statement", "close", "()", "summary", "manual"] # The below APIs have numeric flow and are currently being stored as neutral models. # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future. - - ["java.sql", "PreparedStatement", "setInt", "(int,int)", "summary", "manual"] # value-numeric - - ["java.sql", "PreparedStatement", "setLong", "(int,long)", "summary", "manual"] # value-numeric - ["java.sql", "ResultSet", "getInt", "(int)", "summary", "manual"] # taint-numeric - ["java.sql", "ResultSet", "getInt", "(String)", "summary", "manual"] # taint-numeric - ["java.sql", "ResultSet", "getLong", "(String)", "summary", "manual"] # taint-numeric diff --git a/java/ql/src/experimental/Security/CWE/CWE-200/AndroidWebResourceResponse.qll b/java/ql/src/experimental/Security/CWE/CWE-200/AndroidWebResourceResponse.qll index bd177b30213..05055bdfa84 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-200/AndroidWebResourceResponse.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-200/AndroidWebResourceResponse.qll @@ -55,10 +55,14 @@ class WebResourceResponseSink extends DataFlow::Node { } /** - * A value step from the URL argument of `WebView::loadUrl` to the URL parameter of + * A taint step from the URL argument of `WebView::loadUrl` to the URL/WebResourceRequest parameter of * `WebViewClient::shouldInterceptRequest`. + * + * TODO: This ought to be a value step when it is targeting the URL parameter, + * and it ought to check the parameter type in both cases to ensure that we only + * hit the overloads we intend to. */ -private class FetchUrlStep extends AdditionalValueStep { +private class FetchUrlStep extends AdditionalTaintStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists( // webview.loadUrl(url) -> webview.setWebViewClient(new WebViewClient() { shouldInterceptRequest(view, url) }); diff --git a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.expected b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.expected index f3d88d25805..93b2b060685 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.expected @@ -2075,28 +2075,28 @@ edges | Log4jJndiInjectionTest.java:1085:39:1085:46 | source(...) : String | Log4jJndiInjectionTest.java:1085:25:1085:46 | (...)... | | Log4jJndiInjectionTest.java:1088:47:1088:54 | source(...) : String | Log4jJndiInjectionTest.java:1088:38:1088:54 | (...)... | | Log4jJndiInjectionTest.java:1089:53:1089:60 | source(...) : String | Log4jJndiInjectionTest.java:1089:44:1089:60 | (...)... | -| Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : Map [<map.value>] : String | Log4jJndiInjectionTest.java:1092:34:1092:36 | map | -| Log4jJndiInjectionTest.java:1091:28:1091:44 | (...)... : String | Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : HashMap [<map.value>] : String | Log4jJndiInjectionTest.java:1092:34:1092:36 | map | +| Log4jJndiInjectionTest.java:1091:28:1091:44 | (...)... : String | Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1091:37:1091:44 | source(...) : String | Log4jJndiInjectionTest.java:1091:28:1091:44 | (...)... : String | -| Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : MapMessage | Log4jJndiInjectionTest.java:1096:26:1096:29 | mmsg | -| Log4jJndiInjectionTest.java:1095:71:1095:87 | (...)... : String | Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : MapMessage | +| Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : StringMapMessage | Log4jJndiInjectionTest.java:1096:26:1096:29 | mmsg | +| Log4jJndiInjectionTest.java:1095:71:1095:87 | (...)... : String | Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : StringMapMessage | | Log4jJndiInjectionTest.java:1095:80:1095:87 | source(...) : String | Log4jJndiInjectionTest.java:1095:71:1095:87 | (...)... : String | -| Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : MapMessage | Log4jJndiInjectionTest.java:1101:26:1101:29 | mmsg | -| Log4jJndiInjectionTest.java:1100:35:1100:51 | (...)... : String | Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : MapMessage | +| Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : StringMapMessage | Log4jJndiInjectionTest.java:1101:26:1101:29 | mmsg | +| Log4jJndiInjectionTest.java:1100:35:1100:51 | (...)... : String | Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : StringMapMessage | | Log4jJndiInjectionTest.java:1100:44:1100:51 | source(...) : String | Log4jJndiInjectionTest.java:1100:35:1100:51 | (...)... : String | -| Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : MapMessage | Log4jJndiInjectionTest.java:1106:26:1106:29 | mmsg | -| Log4jJndiInjectionTest.java:1105:34:1105:50 | (...)... : String | Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : MapMessage | +| Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : StringMapMessage | Log4jJndiInjectionTest.java:1106:26:1106:29 | mmsg | +| Log4jJndiInjectionTest.java:1105:34:1105:50 | (...)... : String | Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : StringMapMessage | | Log4jJndiInjectionTest.java:1105:43:1105:50 | source(...) : String | Log4jJndiInjectionTest.java:1105:34:1105:50 | (...)... : String | -| Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : Map [<map.value>] : String | Log4jJndiInjectionTest.java:1112:25:1112:27 | map : Map [<map.value>] : String | -| Log4jJndiInjectionTest.java:1111:33:1111:49 | (...)... : String | Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : HashMap [<map.value>] : String | Log4jJndiInjectionTest.java:1112:25:1112:27 | map : HashMap [<map.value>] : String | +| Log4jJndiInjectionTest.java:1111:33:1111:49 | (...)... : String | Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1111:42:1111:49 | source(...) : String | Log4jJndiInjectionTest.java:1111:33:1111:49 | (...)... : String | -| Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : MapMessage | Log4jJndiInjectionTest.java:1113:26:1113:29 | mmsg | -| Log4jJndiInjectionTest.java:1112:25:1112:27 | map : Map [<map.value>] : String | Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : MapMessage | +| Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : StringMapMessage | Log4jJndiInjectionTest.java:1113:26:1113:29 | mmsg | +| Log4jJndiInjectionTest.java:1112:25:1112:27 | map : HashMap [<map.value>] : String | Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : StringMapMessage | | Log4jJndiInjectionTest.java:1116:61:1116:68 | source(...) : String | Log4jJndiInjectionTest.java:1116:52:1116:68 | (...)... | | Log4jJndiInjectionTest.java:1117:81:1117:88 | source(...) : String | Log4jJndiInjectionTest.java:1117:72:1117:88 | (...)... | -| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : Map [<map.value>] : String | Log4jJndiInjectionTest.java:1120:43:1120:45 | map | -| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : Map [<map.value>] : String | Log4jJndiInjectionTest.java:1121:63:1121:65 | map | -| Log4jJndiInjectionTest.java:1119:33:1119:49 | (...)... : String | Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : HashMap [<map.value>] : String | Log4jJndiInjectionTest.java:1120:43:1120:45 | map | +| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : HashMap [<map.value>] : String | Log4jJndiInjectionTest.java:1121:63:1121:65 | map | +| Log4jJndiInjectionTest.java:1119:33:1119:49 | (...)... : String | Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1119:42:1119:49 | source(...) : String | Log4jJndiInjectionTest.java:1119:33:1119:49 | (...)... : String | nodes | Log4jJndiInjectionTest.java:24:16:24:45 | getParameter(...) : String | semmle.label | getParameter(...) : String | @@ -4168,33 +4168,33 @@ nodes | Log4jJndiInjectionTest.java:1088:47:1088:54 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1089:44:1089:60 | (...)... | semmle.label | (...)... | | Log4jJndiInjectionTest.java:1089:53:1089:60 | source(...) : String | semmle.label | source(...) : String | -| Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : Map [<map.value>] : String | semmle.label | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1091:13:1091:15 | map [post update] : HashMap [<map.value>] : String | semmle.label | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1091:28:1091:44 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1091:37:1091:44 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1092:34:1092:36 | map | semmle.label | map | -| Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : MapMessage | semmle.label | with(...) : MapMessage | +| Log4jJndiInjectionTest.java:1095:31:1095:88 | with(...) : StringMapMessage | semmle.label | with(...) : StringMapMessage | | Log4jJndiInjectionTest.java:1095:71:1095:87 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1095:80:1095:87 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1096:26:1096:29 | mmsg | semmle.label | mmsg | -| Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : MapMessage | semmle.label | mmsg [post update] : MapMessage | +| Log4jJndiInjectionTest.java:1100:13:1100:16 | mmsg [post update] : StringMapMessage | semmle.label | mmsg [post update] : StringMapMessage | | Log4jJndiInjectionTest.java:1100:35:1100:51 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1100:44:1100:51 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1101:26:1101:29 | mmsg | semmle.label | mmsg | -| Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : MapMessage | semmle.label | mmsg [post update] : MapMessage | +| Log4jJndiInjectionTest.java:1105:13:1105:16 | mmsg [post update] : StringMapMessage | semmle.label | mmsg [post update] : StringMapMessage | | Log4jJndiInjectionTest.java:1105:34:1105:50 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1105:43:1105:50 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1106:26:1106:29 | mmsg | semmle.label | mmsg | -| Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : Map [<map.value>] : String | semmle.label | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1111:13:1111:15 | map [post update] : HashMap [<map.value>] : String | semmle.label | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1111:33:1111:49 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1111:42:1111:49 | source(...) : String | semmle.label | source(...) : String | -| Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : MapMessage | semmle.label | mmsg [post update] : MapMessage | -| Log4jJndiInjectionTest.java:1112:25:1112:27 | map : Map [<map.value>] : String | semmle.label | map : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1112:13:1112:16 | mmsg [post update] : StringMapMessage | semmle.label | mmsg [post update] : StringMapMessage | +| Log4jJndiInjectionTest.java:1112:25:1112:27 | map : HashMap [<map.value>] : String | semmle.label | map : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1113:26:1113:29 | mmsg | semmle.label | mmsg | | Log4jJndiInjectionTest.java:1116:52:1116:68 | (...)... | semmle.label | (...)... | | Log4jJndiInjectionTest.java:1116:61:1116:68 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1117:72:1117:88 | (...)... | semmle.label | (...)... | | Log4jJndiInjectionTest.java:1117:81:1117:88 | source(...) : String | semmle.label | source(...) : String | -| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : Map [<map.value>] : String | semmle.label | map [post update] : Map [<map.value>] : String | +| Log4jJndiInjectionTest.java:1119:13:1119:15 | map [post update] : HashMap [<map.value>] : String | semmle.label | map [post update] : HashMap [<map.value>] : String | | Log4jJndiInjectionTest.java:1119:33:1119:49 | (...)... : String | semmle.label | (...)... : String | | Log4jJndiInjectionTest.java:1119:42:1119:49 | source(...) : String | semmle.label | source(...) : String | | Log4jJndiInjectionTest.java:1120:43:1120:45 | map | semmle.label | map | diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.expected b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.expected index 37741e5f605..07ce59763ad 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.expected @@ -1,152 +1,152 @@ edges -| InsecureWebResourceResponse.java:28:27:28:37 | getIntent(...) : Intent | InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : Object | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : Object | -| InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : Object | InsecureWebResourceResponse.java:59:34:59:43 | url : Object | -| InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : Object | InsecureWebResourceResponse.java:80:34:80:43 | url : Object | -| InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : Object | InsecureWebResourceResponse.java:106:34:106:43 | url : Object | -| InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : Object | InsecureWebResourceResponse.java:131:36:131:45 | url : Object | -| InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : Object | InsecureWebResourceResponse.java:156:35:156:44 | url : Object | -| InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : Object | InsecureWebResourceResponse.java:181:34:181:43 | url : Object | -| InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : Object | InsecureWebResourceResponse.java:188:34:188:43 | url : Object | -| InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : Object | InsecureWebResourceResponse.java:217:35:217:44 | url : Object | -| InsecureWebResourceResponse.java:59:34:59:43 | url : Object | InsecureWebResourceResponse.java:75:20:75:22 | url : Object | -| InsecureWebResourceResponse.java:63:77:63:86 | url : Object | InsecureWebResourceResponse.java:65:41:65:43 | url : Object | +| InsecureWebResourceResponse.java:28:27:28:37 | getIntent(...) : Intent | InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : String | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : String | +| InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : String | InsecureWebResourceResponse.java:59:34:59:43 | url : String | +| InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : String | InsecureWebResourceResponse.java:80:34:80:43 | url : String | +| InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : String | InsecureWebResourceResponse.java:106:34:106:43 | url : String | +| InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : String | InsecureWebResourceResponse.java:131:36:131:45 | url : String | +| InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : String | InsecureWebResourceResponse.java:156:35:156:44 | url : String | +| InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : String | InsecureWebResourceResponse.java:181:34:181:43 | url : String | +| InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : String | InsecureWebResourceResponse.java:188:34:188:43 | url : String | +| InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : String | InsecureWebResourceResponse.java:217:35:217:44 | url : String | +| InsecureWebResourceResponse.java:59:34:59:43 | url : String | InsecureWebResourceResponse.java:75:20:75:22 | url : String | +| InsecureWebResourceResponse.java:63:77:63:86 | url : String | InsecureWebResourceResponse.java:65:41:65:43 | url : String | | InsecureWebResourceResponse.java:65:31:65:44 | parse(...) : Uri | InsecureWebResourceResponse.java:66:71:66:73 | uri : Uri | -| InsecureWebResourceResponse.java:65:41:65:43 | url : Object | InsecureWebResourceResponse.java:65:31:65:44 | parse(...) : Uri | +| InsecureWebResourceResponse.java:65:41:65:43 | url : String | InsecureWebResourceResponse.java:65:31:65:44 | parse(...) : Uri | | InsecureWebResourceResponse.java:66:51:66:84 | new FileInputStream(...) : FileInputStream | InsecureWebResourceResponse.java:68:71:68:81 | inputStream | | InsecureWebResourceResponse.java:66:71:66:73 | uri : Uri | InsecureWebResourceResponse.java:66:71:66:83 | getPath(...) : String | | InsecureWebResourceResponse.java:66:71:66:83 | getPath(...) : String | InsecureWebResourceResponse.java:66:51:66:84 | new FileInputStream(...) : FileInputStream | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:80:34:80:43 | url : Object | InsecureWebResourceResponse.java:101:20:101:22 | url : Object | -| InsecureWebResourceResponse.java:84:77:84:86 | url : Object | InsecureWebResourceResponse.java:86:41:86:43 | url : Object | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:80:34:80:43 | url : String | InsecureWebResourceResponse.java:101:20:101:22 | url : String | +| InsecureWebResourceResponse.java:84:77:84:86 | url : String | InsecureWebResourceResponse.java:86:41:86:43 | url : String | | InsecureWebResourceResponse.java:86:31:86:44 | parse(...) : Uri | InsecureWebResourceResponse.java:88:66:88:68 | uri : Uri | -| InsecureWebResourceResponse.java:86:41:86:43 | url : Object | InsecureWebResourceResponse.java:86:31:86:44 | parse(...) : Uri | +| InsecureWebResourceResponse.java:86:41:86:43 | url : String | InsecureWebResourceResponse.java:86:31:86:44 | parse(...) : Uri | | InsecureWebResourceResponse.java:88:42:88:90 | new File(...) : File | InsecureWebResourceResponse.java:89:75:89:83 | cacheFile : File | | InsecureWebResourceResponse.java:88:66:88:68 | uri : Uri | InsecureWebResourceResponse.java:88:66:88:89 | getLastPathSegment(...) : String | | InsecureWebResourceResponse.java:88:66:88:89 | getLastPathSegment(...) : String | InsecureWebResourceResponse.java:88:42:88:90 | new File(...) : File | | InsecureWebResourceResponse.java:89:55:89:84 | new FileInputStream(...) : FileInputStream | InsecureWebResourceResponse.java:91:75:91:85 | inputStream | | InsecureWebResourceResponse.java:89:75:89:83 | cacheFile : File | InsecureWebResourceResponse.java:89:55:89:84 | new FileInputStream(...) : FileInputStream | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:106:34:106:43 | url : Object | InsecureWebResourceResponse.java:127:20:127:22 | url : Object | -| InsecureWebResourceResponse.java:110:77:110:86 | url : Object | InsecureWebResourceResponse.java:112:41:112:43 | url : Object | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:106:34:106:43 | url : String | InsecureWebResourceResponse.java:127:20:127:22 | url : String | +| InsecureWebResourceResponse.java:110:77:110:86 | url : String | InsecureWebResourceResponse.java:112:41:112:43 | url : String | | InsecureWebResourceResponse.java:112:31:112:44 | parse(...) : Uri | InsecureWebResourceResponse.java:113:35:113:37 | uri : Uri | -| InsecureWebResourceResponse.java:112:41:112:43 | url : Object | InsecureWebResourceResponse.java:112:31:112:44 | parse(...) : Uri | +| InsecureWebResourceResponse.java:112:41:112:43 | url : String | InsecureWebResourceResponse.java:112:31:112:44 | parse(...) : Uri | | InsecureWebResourceResponse.java:113:35:113:37 | uri : Uri | InsecureWebResourceResponse.java:113:35:113:47 | getPath(...) : String | | InsecureWebResourceResponse.java:113:35:113:47 | getPath(...) : String | InsecureWebResourceResponse.java:113:35:113:60 | substring(...) : String | | InsecureWebResourceResponse.java:113:35:113:60 | substring(...) : String | InsecureWebResourceResponse.java:115:75:115:78 | path : String | | InsecureWebResourceResponse.java:115:55:115:108 | new FileInputStream(...) : FileInputStream | InsecureWebResourceResponse.java:117:75:117:85 | inputStream | | InsecureWebResourceResponse.java:115:75:115:78 | path : String | InsecureWebResourceResponse.java:115:75:115:107 | substring(...) : String | | InsecureWebResourceResponse.java:115:75:115:107 | substring(...) : String | InsecureWebResourceResponse.java:115:55:115:108 | new FileInputStream(...) : FileInputStream | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:131:36:131:45 | url : Object | InsecureWebResourceResponse.java:152:20:152:22 | url : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:156:35:156:44 | url : Object | InsecureWebResourceResponse.java:177:20:177:22 | url : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:181:34:181:43 | url : Object | InsecureWebResourceResponse.java:184:20:184:22 | url : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:188:34:188:43 | url : Object | InsecureWebResourceResponse.java:209:20:209:22 | url : Object | -| InsecureWebResourceResponse.java:192:77:192:102 | request : Object | InsecureWebResourceResponse.java:194:31:194:37 | request : Object | -| InsecureWebResourceResponse.java:194:31:194:37 | request : Object | InsecureWebResourceResponse.java:194:31:194:46 | getUrl(...) : Uri | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:131:36:131:45 | url : String | InsecureWebResourceResponse.java:152:20:152:22 | url : String | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:156:35:156:44 | url : String | InsecureWebResourceResponse.java:177:20:177:22 | url : String | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:181:34:181:43 | url : String | InsecureWebResourceResponse.java:184:20:184:22 | url : String | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:188:34:188:43 | url : String | InsecureWebResourceResponse.java:209:20:209:22 | url : String | +| InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | InsecureWebResourceResponse.java:194:31:194:37 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:194:31:194:37 | request : WebResourceRequest | InsecureWebResourceResponse.java:194:31:194:46 | getUrl(...) : Uri | | InsecureWebResourceResponse.java:194:31:194:46 | getUrl(...) : Uri | InsecureWebResourceResponse.java:196:66:196:68 | uri : Uri | | InsecureWebResourceResponse.java:196:42:196:90 | new File(...) : File | InsecureWebResourceResponse.java:197:75:197:83 | cacheFile : File | | InsecureWebResourceResponse.java:196:66:196:68 | uri : Uri | InsecureWebResourceResponse.java:196:66:196:89 | getLastPathSegment(...) : String | | InsecureWebResourceResponse.java:196:66:196:89 | getLastPathSegment(...) : String | InsecureWebResourceResponse.java:196:42:196:90 | new File(...) : File | | InsecureWebResourceResponse.java:197:55:197:84 | new FileInputStream(...) : FileInputStream | InsecureWebResourceResponse.java:199:75:199:85 | inputStream | | InsecureWebResourceResponse.java:197:75:197:83 | cacheFile : File | InsecureWebResourceResponse.java:197:55:197:84 | new FileInputStream(...) : FileInputStream | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:217:35:217:44 | url : Object | InsecureWebResourceResponse.java:226:20:226:22 | url : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | InsecureWebResourceResponse.java:63:77:63:86 | url : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | InsecureWebResourceResponse.java:84:77:84:86 | url : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | InsecureWebResourceResponse.java:110:77:110:86 | url : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | InsecureWebResourceResponse.java:192:77:192:102 | request : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | InsecureWebResourceResponse.java:232:69:232:78 | url : Object | -| InsecureWebResourceResponse.java:232:69:232:78 | url : Object | InsecureWebResourceResponse.java:234:33:234:35 | url : Object | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:217:35:217:44 | url : String | InsecureWebResourceResponse.java:226:20:226:22 | url : String | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | InsecureWebResourceResponse.java:63:77:63:86 | url : String | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | InsecureWebResourceResponse.java:84:77:84:86 | url : String | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | InsecureWebResourceResponse.java:110:77:110:86 | url : String | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | InsecureWebResourceResponse.java:232:69:232:78 | url : String | +| InsecureWebResourceResponse.java:232:69:232:78 | url : String | InsecureWebResourceResponse.java:234:33:234:35 | url : String | | InsecureWebResourceResponse.java:234:23:234:36 | parse(...) : Uri | InsecureWebResourceResponse.java:235:63:235:65 | uri : Uri | -| InsecureWebResourceResponse.java:234:33:234:35 | url : Object | InsecureWebResourceResponse.java:234:23:234:36 | parse(...) : Uri | +| InsecureWebResourceResponse.java:234:33:234:35 | url : String | InsecureWebResourceResponse.java:234:23:234:36 | parse(...) : Uri | | InsecureWebResourceResponse.java:235:43:235:76 | new FileInputStream(...) : FileInputStream | InsecureWebResourceResponse.java:237:63:237:73 | inputStream | | InsecureWebResourceResponse.java:235:63:235:65 | uri : Uri | InsecureWebResourceResponse.java:235:63:235:75 | getPath(...) : String | | InsecureWebResourceResponse.java:235:63:235:75 | getPath(...) : String | InsecureWebResourceResponse.java:235:43:235:76 | new FileInputStream(...) : FileInputStream | -| InsecureWebViewActivity.java:27:27:27:37 | getIntent(...) : Intent | InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : Object | -| InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : Object | InsecureWebViewActivity.java:28:20:28:27 | inputUrl : Object | -| InsecureWebViewActivity.java:28:20:28:27 | inputUrl : Object | InsecureWebViewActivity.java:42:28:42:37 | url : Object | -| InsecureWebViewActivity.java:42:28:42:37 | url : Object | InsecureWebViewActivity.java:43:25:43:27 | url : Object | -| InsecureWebViewActivity.java:43:25:43:27 | url : Object | InsecureWebViewActivity.java:53:77:53:86 | url : Object | -| InsecureWebViewActivity.java:53:77:53:86 | url : Object | InsecureWebViewActivity.java:55:41:55:43 | url : Object | +| InsecureWebViewActivity.java:27:27:27:37 | getIntent(...) : Intent | InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : String | +| InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : String | InsecureWebViewActivity.java:28:20:28:27 | inputUrl : String | +| InsecureWebViewActivity.java:28:20:28:27 | inputUrl : String | InsecureWebViewActivity.java:42:28:42:37 | url : String | +| InsecureWebViewActivity.java:42:28:42:37 | url : String | InsecureWebViewActivity.java:43:25:43:27 | url : String | +| InsecureWebViewActivity.java:43:25:43:27 | url : String | InsecureWebViewActivity.java:53:77:53:86 | url : String | +| InsecureWebViewActivity.java:53:77:53:86 | url : String | InsecureWebViewActivity.java:55:41:55:43 | url : String | | InsecureWebViewActivity.java:55:31:55:44 | parse(...) : Uri | InsecureWebViewActivity.java:56:71:56:73 | uri : Uri | -| InsecureWebViewActivity.java:55:41:55:43 | url : Object | InsecureWebViewActivity.java:55:31:55:44 | parse(...) : Uri | +| InsecureWebViewActivity.java:55:41:55:43 | url : String | InsecureWebViewActivity.java:55:31:55:44 | parse(...) : Uri | | InsecureWebViewActivity.java:56:51:56:84 | new FileInputStream(...) : FileInputStream | InsecureWebViewActivity.java:58:71:58:81 | inputStream | | InsecureWebViewActivity.java:56:71:56:73 | uri : Uri | InsecureWebViewActivity.java:56:71:56:83 | getPath(...) : String | | InsecureWebViewActivity.java:56:71:56:83 | getPath(...) : String | InsecureWebViewActivity.java:56:51:56:84 | new FileInputStream(...) : FileInputStream | nodes | InsecureWebResourceResponse.java:28:27:28:37 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | -| InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebResourceResponse.java:59:34:59:43 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:63:77:63:86 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:28:27:28:64 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | +| InsecureWebResourceResponse.java:30:25:30:32 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:32:25:32:32 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:34:25:34:32 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:36:26:36:33 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:38:26:38:33 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:40:25:40:32 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:42:25:42:32 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:44:26:44:33 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebResourceResponse.java:59:34:59:43 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:63:77:63:86 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:65:31:65:44 | parse(...) : Uri | semmle.label | parse(...) : Uri | -| InsecureWebResourceResponse.java:65:41:65:43 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:65:41:65:43 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:66:51:66:84 | new FileInputStream(...) : FileInputStream | semmle.label | new FileInputStream(...) : FileInputStream | | InsecureWebResourceResponse.java:66:71:66:73 | uri : Uri | semmle.label | uri : Uri | | InsecureWebResourceResponse.java:66:71:66:83 | getPath(...) : String | semmle.label | getPath(...) : String | | InsecureWebResourceResponse.java:68:71:68:81 | inputStream | semmle.label | inputStream | -| InsecureWebResourceResponse.java:75:20:75:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:80:34:80:43 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:84:77:84:86 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:75:20:75:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:80:34:80:43 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:84:77:84:86 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:86:31:86:44 | parse(...) : Uri | semmle.label | parse(...) : Uri | -| InsecureWebResourceResponse.java:86:41:86:43 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:86:41:86:43 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:88:42:88:90 | new File(...) : File | semmle.label | new File(...) : File | | InsecureWebResourceResponse.java:88:66:88:68 | uri : Uri | semmle.label | uri : Uri | | InsecureWebResourceResponse.java:88:66:88:89 | getLastPathSegment(...) : String | semmle.label | getLastPathSegment(...) : String | | InsecureWebResourceResponse.java:89:55:89:84 | new FileInputStream(...) : FileInputStream | semmle.label | new FileInputStream(...) : FileInputStream | | InsecureWebResourceResponse.java:89:75:89:83 | cacheFile : File | semmle.label | cacheFile : File | | InsecureWebResourceResponse.java:91:75:91:85 | inputStream | semmle.label | inputStream | -| InsecureWebResourceResponse.java:101:20:101:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:106:34:106:43 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:110:77:110:86 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:101:20:101:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:106:34:106:43 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:110:77:110:86 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:112:31:112:44 | parse(...) : Uri | semmle.label | parse(...) : Uri | -| InsecureWebResourceResponse.java:112:41:112:43 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:112:41:112:43 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:113:35:113:37 | uri : Uri | semmle.label | uri : Uri | | InsecureWebResourceResponse.java:113:35:113:47 | getPath(...) : String | semmle.label | getPath(...) : String | | InsecureWebResourceResponse.java:113:35:113:60 | substring(...) : String | semmle.label | substring(...) : String | @@ -154,16 +154,16 @@ nodes | InsecureWebResourceResponse.java:115:75:115:78 | path : String | semmle.label | path : String | | InsecureWebResourceResponse.java:115:75:115:107 | substring(...) : String | semmle.label | substring(...) : String | | InsecureWebResourceResponse.java:117:75:117:85 | inputStream | semmle.label | inputStream | -| InsecureWebResourceResponse.java:127:20:127:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:131:36:131:45 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:152:20:152:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:156:35:156:44 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:177:20:177:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:181:34:181:43 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:184:20:184:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:188:34:188:43 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:192:77:192:102 | request : Object | semmle.label | request : Object | -| InsecureWebResourceResponse.java:194:31:194:37 | request : Object | semmle.label | request : Object | +| InsecureWebResourceResponse.java:127:20:127:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:131:36:131:45 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:152:20:152:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:156:35:156:44 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:177:20:177:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:181:34:181:43 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:184:20:184:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:188:34:188:43 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:192:77:192:102 | request : WebResourceRequest | semmle.label | request : WebResourceRequest | +| InsecureWebResourceResponse.java:194:31:194:37 | request : WebResourceRequest | semmle.label | request : WebResourceRequest | | InsecureWebResourceResponse.java:194:31:194:46 | getUrl(...) : Uri | semmle.label | getUrl(...) : Uri | | InsecureWebResourceResponse.java:196:42:196:90 | new File(...) : File | semmle.label | new File(...) : File | | InsecureWebResourceResponse.java:196:66:196:68 | uri : Uri | semmle.label | uri : Uri | @@ -171,24 +171,24 @@ nodes | InsecureWebResourceResponse.java:197:55:197:84 | new FileInputStream(...) : FileInputStream | semmle.label | new FileInputStream(...) : FileInputStream | | InsecureWebResourceResponse.java:197:75:197:83 | cacheFile : File | semmle.label | cacheFile : File | | InsecureWebResourceResponse.java:199:75:199:85 | inputStream | semmle.label | inputStream | -| InsecureWebResourceResponse.java:209:20:209:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:217:35:217:44 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:226:20:226:22 | url : Object | semmle.label | url : Object | -| InsecureWebResourceResponse.java:232:69:232:78 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:209:20:209:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:217:35:217:44 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:226:20:226:22 | url : String | semmle.label | url : String | +| InsecureWebResourceResponse.java:232:69:232:78 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:234:23:234:36 | parse(...) : Uri | semmle.label | parse(...) : Uri | -| InsecureWebResourceResponse.java:234:33:234:35 | url : Object | semmle.label | url : Object | +| InsecureWebResourceResponse.java:234:33:234:35 | url : String | semmle.label | url : String | | InsecureWebResourceResponse.java:235:43:235:76 | new FileInputStream(...) : FileInputStream | semmle.label | new FileInputStream(...) : FileInputStream | | InsecureWebResourceResponse.java:235:63:235:65 | uri : Uri | semmle.label | uri : Uri | | InsecureWebResourceResponse.java:235:63:235:75 | getPath(...) : String | semmle.label | getPath(...) : String | | InsecureWebResourceResponse.java:237:63:237:73 | inputStream | semmle.label | inputStream | | InsecureWebViewActivity.java:27:27:27:37 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | -| InsecureWebViewActivity.java:28:20:28:27 | inputUrl : Object | semmle.label | inputUrl : Object | -| InsecureWebViewActivity.java:42:28:42:37 | url : Object | semmle.label | url : Object | -| InsecureWebViewActivity.java:43:25:43:27 | url : Object | semmle.label | url : Object | -| InsecureWebViewActivity.java:53:77:53:86 | url : Object | semmle.label | url : Object | +| InsecureWebViewActivity.java:27:27:27:64 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | +| InsecureWebViewActivity.java:28:20:28:27 | inputUrl : String | semmle.label | inputUrl : String | +| InsecureWebViewActivity.java:42:28:42:37 | url : String | semmle.label | url : String | +| InsecureWebViewActivity.java:43:25:43:27 | url : String | semmle.label | url : String | +| InsecureWebViewActivity.java:53:77:53:86 | url : String | semmle.label | url : String | | InsecureWebViewActivity.java:55:31:55:44 | parse(...) : Uri | semmle.label | parse(...) : Uri | -| InsecureWebViewActivity.java:55:41:55:43 | url : Object | semmle.label | url : Object | +| InsecureWebViewActivity.java:55:41:55:43 | url : String | semmle.label | url : String | | InsecureWebViewActivity.java:56:51:56:84 | new FileInputStream(...) : FileInputStream | semmle.label | new FileInputStream(...) : FileInputStream | | InsecureWebViewActivity.java:56:71:56:73 | uri : Uri | semmle.label | uri : Uri | | InsecureWebViewActivity.java:56:71:56:83 | getPath(...) : String | semmle.label | getPath(...) : String | diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.expected b/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.expected index 43a64e4226a..9c5b6ce8b69 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.expected @@ -1,47 +1,47 @@ edges | FileService.java:20:31:20:43 | intent : Intent | FileService.java:21:28:21:33 | intent : Intent | -| FileService.java:21:28:21:33 | intent : Intent | FileService.java:21:28:21:64 | getStringExtra(...) : Object | -| FileService.java:21:28:21:64 | getStringExtra(...) : Object | FileService.java:25:42:25:50 | localPath : Object | +| FileService.java:21:28:21:33 | intent : Intent | FileService.java:21:28:21:64 | getStringExtra(...) : String | +| FileService.java:21:28:21:64 | getStringExtra(...) : String | FileService.java:25:42:25:50 | localPath : String | | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | FileService.java:40:41:40:55 | params : Object[] | -| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : Object | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | -| FileService.java:25:42:25:50 | localPath : Object | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : Object | -| FileService.java:25:42:25:50 | localPath : Object | FileService.java:32:13:32:28 | sourceUri : Object | -| FileService.java:32:13:32:28 | sourceUri : Object | FileService.java:35:17:35:25 | sourceUri : Object | -| FileService.java:34:20:36:13 | {...} : Object[] [[]] : Object | FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : Object | -| FileService.java:35:17:35:25 | sourceUri : Object | FileService.java:34:20:36:13 | {...} : Object[] [[]] : Object | -| FileService.java:40:41:40:55 | params : Object[] | FileService.java:44:33:44:52 | (...)... : Object | -| FileService.java:44:33:44:52 | (...)... : Object | FileService.java:45:53:45:59 | ...[...] | +| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : String | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | +| FileService.java:25:42:25:50 | localPath : String | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : String | +| FileService.java:25:42:25:50 | localPath : String | FileService.java:32:13:32:28 | sourceUri : String | +| FileService.java:32:13:32:28 | sourceUri : String | FileService.java:35:17:35:25 | sourceUri : String | +| FileService.java:34:20:36:13 | {...} : Object[] [[]] : String | FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : String | +| FileService.java:35:17:35:25 | sourceUri : String | FileService.java:34:20:36:13 | {...} : Object[] [[]] : String | +| FileService.java:40:41:40:55 | params : Object[] | FileService.java:44:33:44:52 | (...)... : String[] | +| FileService.java:44:33:44:52 | (...)... : String[] | FileService.java:45:53:45:59 | ...[...] | | LeakFileActivity2.java:15:13:15:18 | intent : Intent | LeakFileActivity2.java:16:26:16:31 | intent : Intent | | LeakFileActivity2.java:16:26:16:31 | intent : Intent | FileService.java:20:31:20:43 | intent : Intent | | LeakFileActivity.java:14:35:14:38 | data : Intent | LeakFileActivity.java:18:40:18:59 | contentIntent : Intent | | LeakFileActivity.java:18:40:18:59 | contentIntent : Intent | LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | -| LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | LeakFileActivity.java:19:31:19:53 | getData(...) : Object | -| LeakFileActivity.java:19:31:19:53 | getData(...) : Object | LeakFileActivity.java:21:58:21:72 | streamsToUpload : Object | -| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Object | LeakFileActivity.java:21:58:21:82 | getPath(...) | +| LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | LeakFileActivity.java:19:31:19:53 | getData(...) : Uri | +| LeakFileActivity.java:19:31:19:53 | getData(...) : Uri | LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri | +| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri | LeakFileActivity.java:21:58:21:82 | getPath(...) | nodes | FileService.java:20:31:20:43 | intent : Intent | semmle.label | intent : Intent | | FileService.java:21:28:21:33 | intent : Intent | semmle.label | intent : Intent | -| FileService.java:21:28:21:64 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | +| FileService.java:21:28:21:64 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | semmle.label | makeParamsToExecute(...) : Object[] | -| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : Object | semmle.label | makeParamsToExecute(...) : Object[] [[]] : Object | -| FileService.java:25:42:25:50 | localPath : Object | semmle.label | localPath : Object | -| FileService.java:32:13:32:28 | sourceUri : Object | semmle.label | sourceUri : Object | -| FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : Object | semmle.label | new Object[] : Object[] [[]] : Object | -| FileService.java:34:20:36:13 | {...} : Object[] [[]] : Object | semmle.label | {...} : Object[] [[]] : Object | -| FileService.java:35:17:35:25 | sourceUri : Object | semmle.label | sourceUri : Object | +| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : String | semmle.label | makeParamsToExecute(...) : Object[] [[]] : String | +| FileService.java:25:42:25:50 | localPath : String | semmle.label | localPath : String | +| FileService.java:32:13:32:28 | sourceUri : String | semmle.label | sourceUri : String | +| FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : String | semmle.label | new Object[] : Object[] [[]] : String | +| FileService.java:34:20:36:13 | {...} : Object[] [[]] : String | semmle.label | {...} : Object[] [[]] : String | +| FileService.java:35:17:35:25 | sourceUri : String | semmle.label | sourceUri : String | | FileService.java:40:41:40:55 | params : Object[] | semmle.label | params : Object[] | -| FileService.java:44:33:44:52 | (...)... : Object | semmle.label | (...)... : Object | +| FileService.java:44:33:44:52 | (...)... : String[] | semmle.label | (...)... : String[] | | FileService.java:45:53:45:59 | ...[...] | semmle.label | ...[...] | | LeakFileActivity2.java:15:13:15:18 | intent : Intent | semmle.label | intent : Intent | | LeakFileActivity2.java:16:26:16:31 | intent : Intent | semmle.label | intent : Intent | | LeakFileActivity.java:14:35:14:38 | data : Intent | semmle.label | data : Intent | | LeakFileActivity.java:18:40:18:59 | contentIntent : Intent | semmle.label | contentIntent : Intent | | LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | semmle.label | contentIntent : Intent | -| LeakFileActivity.java:19:31:19:53 | getData(...) : Object | semmle.label | getData(...) : Object | -| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Object | semmle.label | streamsToUpload : Object | +| LeakFileActivity.java:19:31:19:53 | getData(...) : Uri | semmle.label | getData(...) : Uri | +| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri | semmle.label | streamsToUpload : Uri | | LeakFileActivity.java:21:58:21:82 | getPath(...) | semmle.label | getPath(...) | subpaths -| FileService.java:25:42:25:50 | localPath : Object | FileService.java:32:13:32:28 | sourceUri : Object | FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : Object | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : Object | +| FileService.java:25:42:25:50 | localPath : String | FileService.java:32:13:32:28 | sourceUri : String | FileService.java:34:20:36:13 | new Object[] : Object[] [[]] : String | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] [[]] : String | #select | FileService.java:45:53:45:59 | ...[...] | LeakFileActivity2.java:15:13:15:18 | intent : Intent | FileService.java:45:53:45:59 | ...[...] | Leaking arbitrary Android file from $@. | LeakFileActivity2.java:15:13:15:18 | intent | this user input | | FileService.java:45:53:45:59 | ...[...] | LeakFileActivity2.java:16:26:16:31 | intent : Intent | FileService.java:45:53:45:59 | ...[...] | Leaking arbitrary Android file from $@. | LeakFileActivity2.java:16:26:16:31 | intent | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.expected b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.expected index b6f894c3e5f..606cf994976 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.expected @@ -6,17 +6,17 @@ edges | UnsafeReflection.java:34:33:34:70 | getParameter(...) : String | UnsafeReflection.java:39:58:39:71 | parameterValue | | UnsafeReflection.java:46:24:46:82 | beanIdOrClassName : String | UnsafeReflection.java:53:30:53:46 | beanIdOrClassName : String | | UnsafeReflection.java:46:132:46:168 | body : Map | UnsafeReflection.java:49:37:49:40 | body : Map | -| UnsafeReflection.java:49:23:49:59 | (...)... : Object | UnsafeReflection.java:53:67:53:73 | rawData : Object | +| UnsafeReflection.java:49:23:49:59 | (...)... : List | UnsafeReflection.java:53:67:53:73 | rawData : List | | UnsafeReflection.java:49:37:49:40 | body : Map | UnsafeReflection.java:49:37:49:59 | get(...) : Object | -| UnsafeReflection.java:49:37:49:59 | get(...) : Object | UnsafeReflection.java:49:23:49:59 | (...)... : Object | +| UnsafeReflection.java:49:37:49:59 | get(...) : Object | UnsafeReflection.java:49:23:49:59 | (...)... : List | | UnsafeReflection.java:53:30:53:46 | beanIdOrClassName : String | UnsafeReflection.java:104:34:104:57 | beanIdOrClassName : String | -| UnsafeReflection.java:53:67:53:73 | rawData : Object | UnsafeReflection.java:104:102:104:118 | data : Object | +| UnsafeReflection.java:53:67:53:73 | rawData : List | UnsafeReflection.java:104:102:104:118 | data : List | | UnsafeReflection.java:62:33:62:70 | getParameter(...) : String | UnsafeReflection.java:68:76:68:89 | parameterValue | | UnsafeReflection.java:77:33:77:70 | getParameter(...) : String | UnsafeReflection.java:83:76:83:89 | parameterValue | | UnsafeReflection.java:92:33:92:70 | getParameter(...) : String | UnsafeReflection.java:98:76:98:89 | parameterValue | | UnsafeReflection.java:104:34:104:57 | beanIdOrClassName : String | UnsafeReflection.java:119:21:119:26 | method | | UnsafeReflection.java:104:34:104:57 | beanIdOrClassName : String | UnsafeReflection.java:119:35:119:38 | bean | -| UnsafeReflection.java:104:102:104:118 | data : Object | UnsafeReflection.java:119:41:119:44 | data | +| UnsafeReflection.java:104:102:104:118 | data : List | UnsafeReflection.java:119:41:119:44 | data | nodes | UnsafeReflection.java:21:28:21:60 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UnsafeReflection.java:22:33:22:70 | getParameter(...) : String | semmle.label | getParameter(...) : String | @@ -29,11 +29,11 @@ nodes | UnsafeReflection.java:39:58:39:71 | parameterValue | semmle.label | parameterValue | | UnsafeReflection.java:46:24:46:82 | beanIdOrClassName : String | semmle.label | beanIdOrClassName : String | | UnsafeReflection.java:46:132:46:168 | body : Map | semmle.label | body : Map | -| UnsafeReflection.java:49:23:49:59 | (...)... : Object | semmle.label | (...)... : Object | +| UnsafeReflection.java:49:23:49:59 | (...)... : List | semmle.label | (...)... : List | | UnsafeReflection.java:49:37:49:40 | body : Map | semmle.label | body : Map | | UnsafeReflection.java:49:37:49:59 | get(...) : Object | semmle.label | get(...) : Object | | UnsafeReflection.java:53:30:53:46 | beanIdOrClassName : String | semmle.label | beanIdOrClassName : String | -| UnsafeReflection.java:53:67:53:73 | rawData : Object | semmle.label | rawData : Object | +| UnsafeReflection.java:53:67:53:73 | rawData : List | semmle.label | rawData : List | | UnsafeReflection.java:62:33:62:70 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UnsafeReflection.java:68:76:68:89 | parameterValue | semmle.label | parameterValue | | UnsafeReflection.java:77:33:77:70 | getParameter(...) : String | semmle.label | getParameter(...) : String | @@ -41,7 +41,7 @@ nodes | UnsafeReflection.java:92:33:92:70 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UnsafeReflection.java:98:76:98:89 | parameterValue | semmle.label | parameterValue | | UnsafeReflection.java:104:34:104:57 | beanIdOrClassName : String | semmle.label | beanIdOrClassName : String | -| UnsafeReflection.java:104:102:104:118 | data : Object | semmle.label | data : Object | +| UnsafeReflection.java:104:102:104:118 | data : List | semmle.label | data : List | | UnsafeReflection.java:119:21:119:26 | method | semmle.label | method | | UnsafeReflection.java:119:35:119:38 | bean | semmle.label | bean | | UnsafeReflection.java:119:41:119:44 | data | semmle.label | data | diff --git a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected index a39906b4115..57874f96e18 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-552/UnsafeUrlForward.expected @@ -6,11 +6,11 @@ edges | UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName | | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:17:20:17:25 | params : Map | -| UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | -| UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | +| UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | +| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:33:20:33:25 | params : Map | -| UnsafeResourceGet2.java:33:20:33:25 | params : Map | UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | -| UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | UnsafeResourceGet2.java:37:20:37:22 | url | +| UnsafeResourceGet2.java:33:20:33:25 | params : Map | UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | +| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | UnsafeResourceGet2.java:37:20:37:22 | url | | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:41:20:41:22 | url | | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath | | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:150:20:150:22 | url | @@ -42,11 +42,11 @@ nodes | UnsafeRequestPath.java:23:33:23:36 | path | semmle.label | path | | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map | | UnsafeResourceGet2.java:17:20:17:25 | params : Map | semmle.label | params : Map | -| UnsafeResourceGet2.java:17:20:17:40 | get(...) : Object | semmle.label | get(...) : Object | +| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | semmle.label | get(...) : String | | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | semmle.label | loadUrl | | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map | | UnsafeResourceGet2.java:33:20:33:25 | params : Map | semmle.label | params : Map | -| UnsafeResourceGet2.java:33:20:33:40 | get(...) : Object | semmle.label | get(...) : Object | +| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | semmle.label | get(...) : String | | UnsafeResourceGet2.java:37:20:37:22 | url | semmle.label | url | | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UnsafeResourceGet.java:41:20:41:22 | url | semmle.label | url | diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.expected b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.expected index 0c641999e27..28471144374 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.expected @@ -1,11 +1,11 @@ edges | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | SensitiveGetQuery2.java:14:30:14:32 | map : Map | -| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | SensitiveGetQuery2.java:15:29:15:36 | password | -| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | SensitiveGetQuery2.java:15:29:15:36 | password : Object | +| SensitiveGetQuery2.java:14:21:14:48 | (...)... : String | SensitiveGetQuery2.java:15:29:15:36 | password | +| SensitiveGetQuery2.java:14:21:14:48 | (...)... : String | SensitiveGetQuery2.java:15:29:15:36 | password : String | | SensitiveGetQuery2.java:14:30:14:32 | map : Map | SensitiveGetQuery2.java:14:30:14:48 | get(...) : Object | -| SensitiveGetQuery2.java:14:30:14:48 | get(...) : Object | SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | -| SensitiveGetQuery2.java:15:29:15:36 | password : Object | SensitiveGetQuery2.java:18:40:18:54 | password : Object | -| SensitiveGetQuery2.java:18:40:18:54 | password : Object | SensitiveGetQuery2.java:19:61:19:68 | password | +| SensitiveGetQuery2.java:14:30:14:48 | get(...) : Object | SensitiveGetQuery2.java:14:21:14:48 | (...)... : String | +| SensitiveGetQuery2.java:15:29:15:36 | password : String | SensitiveGetQuery2.java:18:40:18:54 | password : String | +| SensitiveGetQuery2.java:18:40:18:54 | password : String | SensitiveGetQuery2.java:19:61:19:68 | password | | SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String | SensitiveGetQuery3.java:13:57:13:64 | password | | SensitiveGetQuery3.java:17:10:17:40 | getParameter(...) : String | SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String | | SensitiveGetQuery4.java:14:24:14:66 | getRequestParameter(...) : String | SensitiveGetQuery4.java:16:37:16:47 | accessToken | @@ -16,12 +16,12 @@ edges | SensitiveGetQuery.java:17:40:17:54 | password : String | SensitiveGetQuery.java:18:61:18:68 | password | nodes | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | semmle.label | getParameterMap(...) : Map | -| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | semmle.label | (...)... : Object | +| SensitiveGetQuery2.java:14:21:14:48 | (...)... : String | semmle.label | (...)... : String | | SensitiveGetQuery2.java:14:30:14:32 | map : Map | semmle.label | map : Map | | SensitiveGetQuery2.java:14:30:14:48 | get(...) : Object | semmle.label | get(...) : Object | | SensitiveGetQuery2.java:15:29:15:36 | password | semmle.label | password | -| SensitiveGetQuery2.java:15:29:15:36 | password : Object | semmle.label | password : Object | -| SensitiveGetQuery2.java:18:40:18:54 | password : Object | semmle.label | password : Object | +| SensitiveGetQuery2.java:15:29:15:36 | password : String | semmle.label | password : String | +| SensitiveGetQuery2.java:18:40:18:54 | password : String | semmle.label | password : String | | SensitiveGetQuery2.java:19:61:19:68 | password | semmle.label | password | | SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String | semmle.label | getRequestParameter(...) : String | | SensitiveGetQuery3.java:13:57:13:64 | password | semmle.label | password | diff --git a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected index 73657a38158..5f0e5b028f9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected @@ -1,25 +1,25 @@ edges -| NFEAndroidDoS.java:13:24:13:34 | getIntent(...) : Intent | NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : Object | -| NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:14:21:14:51 | parseDouble(...) | -| NFEAndroidDoS.java:22:21:22:31 | getIntent(...) : Intent | NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | -| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | NFEAndroidDoS.java:23:15:23:40 | parseInt(...) | -| NFEAndroidDoS.java:25:22:25:32 | getIntent(...) : Intent | NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | -| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | NFEAndroidDoS.java:26:16:26:42 | parseInt(...) | -| NFEAndroidDoS.java:43:24:43:34 | getIntent(...) : Intent | NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | -| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:44:21:44:43 | new Double(...) | -| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:47:21:47:47 | valueOf(...) | +| NFEAndroidDoS.java:13:24:13:34 | getIntent(...) : Intent | NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : String | +| NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : String | NFEAndroidDoS.java:14:21:14:51 | parseDouble(...) | +| NFEAndroidDoS.java:22:21:22:31 | getIntent(...) : Intent | NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : String | +| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : String | NFEAndroidDoS.java:23:15:23:40 | parseInt(...) | +| NFEAndroidDoS.java:25:22:25:32 | getIntent(...) : Intent | NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : String | +| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : String | NFEAndroidDoS.java:26:16:26:42 | parseInt(...) | +| NFEAndroidDoS.java:43:24:43:34 | getIntent(...) : Intent | NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : String | +| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : String | NFEAndroidDoS.java:44:21:44:43 | new Double(...) | +| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : String | NFEAndroidDoS.java:47:21:47:47 | valueOf(...) | nodes | NFEAndroidDoS.java:13:24:13:34 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | +| NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | | NFEAndroidDoS.java:14:21:14:51 | parseDouble(...) | semmle.label | parseDouble(...) | | NFEAndroidDoS.java:22:21:22:31 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | +| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | | NFEAndroidDoS.java:23:15:23:40 | parseInt(...) | semmle.label | parseInt(...) | | NFEAndroidDoS.java:25:22:25:32 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | +| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | | NFEAndroidDoS.java:26:16:26:42 | parseInt(...) | semmle.label | parseInt(...) | | NFEAndroidDoS.java:43:24:43:34 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent | -| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object | +| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String | | NFEAndroidDoS.java:44:21:44:43 | new Double(...) | semmle.label | new Double(...) | | NFEAndroidDoS.java:47:21:47:47 | valueOf(...) | semmle.label | valueOf(...) | subpaths diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java index 83efd12e967..6bbc7a07879 100644 --- a/java/ql/test/ext/TestModels/Test.java +++ b/java/ql/test/ext/TestModels/Test.java @@ -82,7 +82,7 @@ public class Test { Connection con = DriverManager.getConnection(""); PreparedStatement ps1 = con.prepareStatement("UPDATE EMPLOYEES SET NAME = ? WHERE ID = ?"); ps1.setString(1, (String)source()); - sink(ps1); // $hasValueFlow + sink(ps1); // safe // java.util.concurrent.atomic AtomicReference ar = new AtomicReference(source()); diff --git a/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected index 2ae893b5d1d..05dd12f9a5b 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected @@ -5,8 +5,8 @@ edges | Test.java:6:35:6:44 | arg : String | Test.java:22:15:22:27 | ... + ... : String | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | Test.java:10:29:10:74 | new String[] | | Test.java:10:61:10:73 | ... + ... : String | Test.java:10:29:10:74 | {...} : String[] [[]] : String | -| Test.java:16:5:16:7 | cmd [post update] : List [<element>] : String | Test.java:18:29:18:31 | cmd | -| Test.java:16:13:16:25 | ... + ... : String | Test.java:16:5:16:7 | cmd [post update] : List [<element>] : String | +| Test.java:16:5:16:7 | cmd [post update] : ArrayList [<element>] : String | Test.java:18:29:18:31 | cmd | +| Test.java:16:13:16:25 | ... + ... : String | Test.java:16:5:16:7 | cmd [post update] : ArrayList [<element>] : String | | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | Test.java:24:29:24:32 | cmd1 | | Test.java:22:15:22:27 | ... + ... : String | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | | Test.java:28:38:28:47 | arg : String | Test.java:29:44:29:64 | ... + ... | @@ -20,7 +20,7 @@ nodes | Test.java:10:29:10:74 | new String[] | semmle.label | new String[] | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | semmle.label | {...} : String[] [[]] : String | | Test.java:10:61:10:73 | ... + ... : String | semmle.label | ... + ... : String | -| Test.java:16:5:16:7 | cmd [post update] : List [<element>] : String | semmle.label | cmd [post update] : List [<element>] : String | +| Test.java:16:5:16:7 | cmd [post update] : ArrayList [<element>] : String | semmle.label | cmd [post update] : ArrayList [<element>] : String | | Test.java:16:13:16:25 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:18:29:18:31 | cmd | semmle.label | cmd | | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | semmle.label | cmd1 [post update] : String[] [[]] : String | From 441ccef6c44e897997f243c89b31f1ca74b596b7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 May 2023 10:24:22 +0200 Subject: [PATCH 209/219] Dataflow: Bugfix, use arg type rather than strengthened param type. --- java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 8520f308f55..869866584ec 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } From 8a584b78ac28ede24b7867fe96516c91c6082acf Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 May 2023 10:25:12 +0200 Subject: [PATCH 210/219] Dataflow: Enable type strengthening in partial flow. --- .../java/dataflow/internal/DataFlowImpl.qll | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 869866584ec..d83adf3d39e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] From 53f2b8aab0bbf4124eded8755171e0e29761738d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 May 2023 10:28:02 +0200 Subject: [PATCH 211/219] Dataflow: Sync. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../csharp/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../go/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../dataflow/new/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../ruby/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- .../swift/dataflow/internal/DataFlowImpl.qll | 44 ++++++++++++++----- 7 files changed, 238 insertions(+), 70 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index 8520f308f55..d83adf3d39e 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -2677,7 +2677,7 @@ module Impl<FullStateConfigSig Config> { TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) { exists(AccessPathApprox apa | ap.getApprox() = apa | Stage5::parameterMayFlowThrough(p, apa) and - Stage5::fwdFlow(p, state, _, _, _, _, t, apa, _) and + Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and Stage5::revFlow(p, state, _) ) } @@ -4008,7 +4008,7 @@ module Impl<FullStateConfigSig Config> { ap = TPartialNil() and exists(explorationLimit()) or - partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and distSrc(node.getEnclosingCallable()) <= explorationLimit() } or TPartialPathNodeRev( @@ -4034,11 +4034,20 @@ module Impl<FullStateConfigSig Config> { } pragma[nomagic] - private predicate partialPathNodeMk0( - NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, - TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap + private predicate partialPathStep( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { - partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and + partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap) + } + + pragma[nomagic] + private predicate partialPathStep1( + PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, + TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t, + PartialAccessPath ap + ) { + partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and not fullBarrier(node) and not stateBarrier(node, state) and not clearsContentEx(node, ap.getHead()) and @@ -4046,9 +4055,19 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if node.asNode() instanceof CastingNode - then compatibleTypes(node.getDataFlowType(), t) - else any() + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + + pragma[nomagic] + private predicate partialPathTypeStrengthen( + DataFlowType t0, PartialAccessPath ap, DataFlowType t + ) { + partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t } /** @@ -4227,7 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } - private predicate partialPathStep( + private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap ) { @@ -4353,6 +4372,11 @@ module Impl<FullStateConfigSig Config> { DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2 ) { partialPathStoreStep(_, t1, ap1, c, _, t2, ap2) + or + exists(DataFlowType t0 | + partialPathTypeStrengthen(t0, ap2, t2) and + apConsFwd(t1, ap1, c, t0, ap2) + ) } pragma[nomagic] From 4399138c829bf9b55f161ffe0874351174e21ca9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 May 2023 10:42:15 +0200 Subject: [PATCH 212/219] Dataflow: Fix QL4QL alert. --- cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 1 + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 1 + .../ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 1 + go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll | 1 + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 1 + .../ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll | 1 + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll | 1 + swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll | 1 + 8 files changed, 8 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index d83adf3d39e..ffb42d453d0 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -4246,6 +4246,7 @@ module Impl<FullStateConfigSig Config> { } } + pragma[nomagic] private predicate partialPathStep0( PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap From 95afd551ff743183ffcab867a2b9afebcb78e1dd Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 May 2023 13:36:41 +0200 Subject: [PATCH 213/219] Java: Fix qltest --- .../library-tests/frameworks/apache-collections/Test.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/test/library-tests/frameworks/apache-collections/Test.java b/java/ql/test/library-tests/frameworks/apache-collections/Test.java index 188849457ac..09906405d75 100644 --- a/java/ql/test/library-tests/frameworks/apache-collections/Test.java +++ b/java/ql/test/library-tests/frameworks/apache-collections/Test.java @@ -721,14 +721,14 @@ public class Test { { // "org.apache.commons.collections4;MapUtils;true;getMap;;;MapValue of Argument[0];ReturnValue;value;manual" Map out = null; - Map in = newTreeMapWithMapValue((String)source()); + Map in = newTreeMapWithMapValue((Map)source()); out = MapUtils.getMap(in, null, null); sink(out); // $ hasValueFlow } { // "org.apache.commons.collections4;MapUtils;true;getMap;;;MapValue of Argument[0];ReturnValue;value;manual" Map out = null; - Map in = newTreeMapWithMapValue((String)source()); + Map in = newTreeMapWithMapValue((Map)source()); out = MapUtils.getMap(in, null); sink(out); // $ hasValueFlow } @@ -7257,4 +7257,4 @@ public class Test { } } -} \ No newline at end of file +} From d230509905a1867555bef82ce30e051722235676 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 15 May 2023 13:09:35 +0200 Subject: [PATCH 214/219] Dataflow: Address review comments. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../csharp/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../go/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../java/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../dataflow/new/internal/DataFlowImpl.qll | 45 +++++++------------ .../ruby/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ .../swift/dataflow/internal/DataFlowImpl.qll | 45 +++++++------------ 8 files changed, 120 insertions(+), 240 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index ffb42d453d0..984c5ae2018 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -1211,6 +1211,7 @@ module Impl<FullStateConfigSig Config> { filter(node, state, t0, ap, t) } + pragma[nomagic] private predicate typeStrengthen(Typ t0, Ap ap, Typ t) { fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t } @@ -2255,6 +2256,16 @@ module Impl<FullStateConfigSig Config> { import MkStage<Stage2>::Stage<Stage3Param> } + bindingset[node, t0] + private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) { + if castingNodeEx(node) + then + exists(DataFlowType nt | nt = node.getDataFlowType() | + if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) + ) + else t = t0 + } + private module Stage4Param implements MkStage<Stage3>::StageParam { private module PrevStage = Stage3; @@ -2351,14 +2362,7 @@ module Impl<FullStateConfigSig Config> { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { exists(state) and not clear(node, ap) and - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and ( notExpectsContent(node) or @@ -2632,14 +2636,7 @@ module Impl<FullStateConfigSig Config> { bindingset[node, state, t0, ap] predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) { - ( - if castingNodeEx(node) - then - exists(Typ nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) and + strengthenType(node, t0, t) and exists(state) and exists(ap) } @@ -3373,14 +3370,7 @@ module Impl<FullStateConfigSig Config> { exists(DataFlowType t0 | pathStep0(mid, node, state, cc, sc, t0, ap) and Stage5::revFlow(node, state, ap.getApprox()) and - ( - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 - ) + strengthenType(node, t0, t) ) } @@ -4055,12 +4045,7 @@ module Impl<FullStateConfigSig Config> { notExpectsContent(node) or expectsContentEx(node, ap.getHead()) ) and - if castingNodeEx(node) - then - exists(DataFlowType nt | nt = node.getDataFlowType() | - if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0) - ) - else t = t0 + strengthenType(node, t0, t) } pragma[nomagic] From 85d6b44d9288169a3886641f6d82d3fe381a9b77 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 7 Jun 2023 11:30:33 +0200 Subject: [PATCH 215/219] Java: Fix test output. --- .../TopJdkApisTest/TopJdkApisTest.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/test/query-tests/Metrics/GeneratedVsManualCoverage/TopJdkApisTest/TopJdkApisTest.expected b/java/ql/test/query-tests/Metrics/GeneratedVsManualCoverage/TopJdkApisTest/TopJdkApisTest.expected index b362ef171f5..4fee1c07e06 100644 --- a/java/ql/test/query-tests/Metrics/GeneratedVsManualCoverage/TopJdkApisTest/TopJdkApisTest.expected +++ b/java/ql/test/query-tests/Metrics/GeneratedVsManualCoverage/TopJdkApisTest/TopJdkApisTest.expected @@ -8,7 +8,7 @@ | java.nio | 0 | 0 | 2 | 3 | 5 | 0.4 | 0.0 | 0.4 | 0.0 | NaN | 0.6 | | java.nio.charset | 0 | 0 | 0 | 1 | 1 | 0.0 | 0.0 | 0.0 | NaN | NaN | 1.0 | | java.nio.file | 0 | 0 | 7 | 1 | 8 | 0.875 | 0.0 | 0.875 | 0.0 | NaN | 0.125 | -| java.sql | 0 | 0 | 2 | 14 | 16 | 0.125 | 0.0 | 0.125 | 0.0 | NaN | 0.875 | +| java.sql | 0 | 0 | 1 | 15 | 16 | 0.0625 | 0.0 | 0.0625 | 0.0 | NaN | 0.9375 | | java.text | 0 | 0 | 0 | 5 | 5 | 0.0 | 0.0 | 0.0 | NaN | NaN | 1.0 | | java.time | 0 | 0 | 0 | 17 | 17 | 0.0 | 0.0 | 0.0 | NaN | NaN | 1.0 | | java.time.chrono | 0 | 0 | 0 | 1 | 1 | 0.0 | 0.0 | 0.0 | NaN | NaN | 1.0 | From 68f1e40370bbebd4001b8e6f6771bb2295746bad Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 8 Jun 2023 14:35:28 +0200 Subject: [PATCH 216/219] Java/C#: Add change notes. --- csharp/ql/lib/change-notes/2023-06-08-type-strengthening.md | 4 ++++ java/ql/lib/change-notes/2023-06-08-type-strengthening.md | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-06-08-type-strengthening.md create mode 100644 java/ql/lib/change-notes/2023-06-08-type-strengthening.md diff --git a/csharp/ql/lib/change-notes/2023-06-08-type-strengthening.md b/csharp/ql/lib/change-notes/2023-06-08-type-strengthening.md new file mode 100644 index 00000000000..60daaa53058 --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-06-08-type-strengthening.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* The data flow library now performs type strengthening. This increases precision for all data flow queries by excluding paths that can be inferred to be impossible due to incompatible types. diff --git a/java/ql/lib/change-notes/2023-06-08-type-strengthening.md b/java/ql/lib/change-notes/2023-06-08-type-strengthening.md new file mode 100644 index 00000000000..60daaa53058 --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-08-type-strengthening.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* The data flow library now performs type strengthening. This increases precision for all data flow queries by excluding paths that can be inferred to be impossible due to incompatible types. From 6dfeb2536bd274a3068e17c63d50f872150dd56e Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Thu, 1 Jun 2023 09:44:30 +0200 Subject: [PATCH 217/219] delete old deprecations --- python/ql/lib/semmle/python/Files.qll | 6 - .../python/dataflow/old/TaintTracking.qll | 8 - .../lib/semmle/python/frameworks/Django.qll | 33 ----- .../lib/semmle/python/frameworks/FastApi.qll | 3 - .../python/frameworks/RestFramework.qll | 3 - .../semmle/python/frameworks/SqlAlchemy.qll | 3 - .../lib/semmle/python/frameworks/Stdlib.qll | 39 ----- .../lib/semmle/python/frameworks/Tornado.qll | 3 - .../lib/semmle/python/pointsto/PointsTo.qll | 48 ------ .../lib/semmle/python/security/ClearText.qll | 54 ------- .../ql/lib/semmle/python/security/Crypto.qll | 139 ------------------ .../semmle/python/security/SensitiveData.qll | 118 --------------- .../security/dataflow/ChainedConfigs12.qll | 95 ------------ .../security/dataflow/CleartextLogging.qll | 14 -- .../security/dataflow/CleartextStorage.qll | 14 -- .../security/dataflow/CodeInjection.qll | 13 -- .../security/dataflow/CommandInjection.qll | 13 -- .../security/dataflow/LdapInjection.qll | 12 -- .../python/security/dataflow/LogInjection.qll | 10 -- .../security/dataflow/PathInjection.qll | 133 ----------------- .../security/dataflow/PolynomialReDoS.qll | 10 -- .../python/security/dataflow/ReflectedXSS.qll | 16 -- .../dataflow/ReflectedXSSCustomizations.qll | 3 - .../security/dataflow/RegexInjection.qll | 10 -- .../dataflow/ServerSideRequestForgery.qll | 25 ---- .../python/security/dataflow/SqlInjection.qll | 16 -- .../security/dataflow/StackTraceExposure.qll | 13 -- .../dataflow/UnsafeDeserialization.qll | 13 -- .../python/security/dataflow/UrlRedirect.qll | 13 -- .../dataflow/WeakSensitiveDataHashing.qll | 19 --- .../security/dataflow/XpathInjection.qll | 10 -- .../semmle/python/security/flow/AnyCall.qll | 9 -- .../security/injection/Deserialization.qll | 8 - .../semmle/python/security/injection/Exec.qll | 29 ---- .../python/security/injection/Marshal.qll | 33 ----- .../semmle/python/security/injection/Path.qll | 81 ---------- .../python/security/injection/Pickle.qll | 36 ----- .../security/injection/RegexInjection.qll | 6 - .../RegexInjectionCustomizations.qll | 6 - .../semmle/python/security/injection/Xml.qll | 70 --------- .../semmle/python/security/injection/Yaml.qll | 28 ---- .../ql/lib/semmle/python/types/Extensions.qll | 25 ---- .../CWE-020-ExternalAPIs/ExternalAPIs.qll | 15 -- .../experimental/semmle/python/Concepts.qll | 48 ------ .../python/security/LDAPInsecureAuth.qll | 24 --- .../security/injection/NoSQLInjection.qll | 3 - .../security/sensitive/Sources.expected | 6 - .../security/sensitive/Sources.ql | 5 - .../library-tests/security/sensitive/test.py | 21 --- .../web/bottle/HttpResponseSinks.expected | 5 - .../web/bottle/HttpResponseSinks.ql | 7 - .../web/bottle/HttpSources.expected | 9 -- .../library-tests/web/bottle/HttpSources.ql | 7 - .../library-tests/web/bottle/Routing.expected | 8 - .../test/library-tests/web/bottle/Routing.ql | 5 - .../library-tests/web/bottle/Taint.expected | 23 --- .../ql/test/library-tests/web/bottle/Taint.ql | 7 - .../ql/test/library-tests/web/bottle/options | 1 - .../ql/test/library-tests/web/bottle/test.py | 36 ----- .../web/cherrypy/HttpResponseSinks.expected | 4 - .../web/cherrypy/HttpResponseSinks.ql | 7 - .../web/cherrypy/HttpSources.expected | 4 - .../library-tests/web/cherrypy/HttpSources.ql | 7 - .../test/library-tests/web/cherrypy/options | 1 - .../ql/test/library-tests/web/cherrypy/red.py | 11 -- .../test/library-tests/web/cherrypy/test.py | 23 --- .../requests/ClientHttpRequests.expected | 3 - .../web/client/requests/ClientHttpRequests.ql | 7 - .../library-tests/web/client/requests/options | 1 - .../library-tests/web/client/requests/test.py | 4 - .../client/six/ClientHttpRequests.expected | 11 -- .../web/client/six/ClientHttpRequests.ql | 7 - .../test/library-tests/web/client/six/options | 2 - .../test/library-tests/web/client/six/test.py | 37 ----- .../client/stdlib/ClientHttpRequests.expected | 11 -- .../web/client/stdlib/ClientHttpRequests.ql | 7 - .../library-tests/web/client/stdlib/options | 1 - .../library-tests/web/client/stdlib/test.py | 44 ------ .../web/django/HttpRedirectSinks.expected | 5 - .../web/django/HttpRedirectSinks.ql | 7 - .../web/django/HttpResponseSinks.expected | 32 ---- .../web/django/HttpResponseSinks.ql | 7 - .../web/django/HttpSources.expected | 53 ------- .../library-tests/web/django/HttpSources.ql | 7 - .../web/django/SqlInjectionSinks.expected | 9 -- .../web/django/SqlInjectionSinks.ql | 8 - .../ql/test/library-tests/web/django/options | 1 - .../ql/test/library-tests/web/django/sql.py | 53 ------- .../test/library-tests/web/django/test_1x.py | 19 --- .../library-tests/web/django/test_2x_3x.py | 19 --- .../test/library-tests/web/django/views_1x.py | 107 -------------- .../library-tests/web/django/views_2x_3x.py | 128 ---------------- .../web/falcon/HttpResponseSinks.expected | 1 - .../web/falcon/HttpResponseSinks.ql | 8 - .../web/falcon/HttpSources.expected | 4 - .../library-tests/web/falcon/HttpSources.ql | 7 - .../library-tests/web/falcon/Routing.expected | 4 - .../test/library-tests/web/falcon/Routing.ql | 5 - .../library-tests/web/falcon/Sinks.expected | 0 .../ql/test/library-tests/web/falcon/Sinks.ql | 8 - .../library-tests/web/falcon/Taint.expected | 20 --- .../ql/test/library-tests/web/falcon/Taint.ql | 8 - .../ql/test/library-tests/web/falcon/options | 1 - .../ql/test/library-tests/web/falcon/test.py | 28 ---- .../web/flask/HttpResponseSinks.expected | 17 --- .../web/flask/HttpResponseSinks.ql | 7 - .../web/flask/HttpSources.expected | 10 -- .../library-tests/web/flask/HttpSources.ql | 7 - .../library-tests/web/flask/Routing.expected | 11 -- .../test/library-tests/web/flask/Routing.ql | 6 - .../library-tests/web/flask/Taint.expected | 33 ----- .../ql/test/library-tests/web/flask/Taint.ql | 8 - .../ql/test/library-tests/web/flask/options | 1 - .../ql/test/library-tests/web/flask/test.py | 67 --------- .../web/pyramid/HttpResponseSinks.expected | 4 - .../web/pyramid/HttpResponseSinks.ql | 7 - .../web/pyramid/HttpSources.expected | 4 - .../library-tests/web/pyramid/HttpSources.ql | 7 - .../web/pyramid/Routing.expected | 4 - .../test/library-tests/web/pyramid/Routing.ql | 6 - .../library-tests/web/pyramid/Taint.expected | 11 -- .../test/library-tests/web/pyramid/Taint.ql | 8 - .../ql/test/library-tests/web/pyramid/options | 1 - .../ql/test/library-tests/web/pyramid/test.py | 25 ---- .../web/stdlib/HttpResponseSinks.expected | 3 - .../web/stdlib/HttpResponseSinks.ql | 7 - .../web/stdlib/HttpSources.expected | 35 ----- .../library-tests/web/stdlib/HttpSources.ql | 9 -- .../web/stdlib/TestTaint.expected | 32 ---- .../library-tests/web/stdlib/TestTaint.ql | 32 ---- .../ql/test/library-tests/web/stdlib/test.py | 108 -------------- .../web/tornado/Classes.expected | 5 - .../test/library-tests/web/tornado/Classes.ql | 7 - .../web/tornado/HttpRedirectSinks.expected | 2 - .../web/tornado/HttpRedirectSinks.ql | 7 - .../web/tornado/HttpResponseSinks.expected | 4 - .../web/tornado/HttpResponseSinks.ql | 7 - .../web/tornado/HttpSources.expected | 5 - .../library-tests/web/tornado/HttpSources.ql | 7 - .../library-tests/web/tornado/Taint.expected | 12 -- .../test/library-tests/web/tornado/Taint.ql | 10 -- .../ql/test/library-tests/web/tornado/options | 1 - .../ql/test/library-tests/web/tornado/test.py | 26 ---- .../web/turbogears/Controller.expected | 6 - .../web/turbogears/Controller.ql | 5 - .../web/turbogears/HttpResponseSinks.expected | 6 - .../web/turbogears/HttpResponseSinks.ql | 7 - .../web/turbogears/HttpSources.expected | 4 - .../web/turbogears/HttpSources.ql | 7 - .../web/turbogears/Taint.expected | 12 -- .../library-tests/web/turbogears/Taint.ql | 7 - .../test/library-tests/web/turbogears/options | 1 - .../test/library-tests/web/turbogears/test.py | 27 ---- .../web/twisted/Classes.expected | 6 - .../test/library-tests/web/twisted/Classes.ql | 7 - .../web/twisted/HttpResponseSinks.expected | 11 -- .../web/twisted/HttpResponseSinks.ql | 7 - .../web/twisted/HttpSources.expected | 9 -- .../library-tests/web/twisted/HttpSources.ql | 7 - .../web/twisted/Methods.expected | 9 -- .../test/library-tests/web/twisted/Methods.ql | 7 - .../library-tests/web/twisted/Taint.expected | 41 ------ .../test/library-tests/web/twisted/Taint.ql | 8 - .../ql/test/library-tests/web/twisted/options | 1 - .../ql/test/library-tests/web/twisted/test.py | 51 ------- .../ql/lib/BytecodeExpr.qll | 33 ----- .../ql/lib/RecordedCalls.qll | 15 -- 167 files changed, 3068 deletions(-) delete mode 100644 python/ql/lib/semmle/python/security/ClearText.qll delete mode 100644 python/ql/lib/semmle/python/security/Crypto.qll delete mode 100644 python/ql/lib/semmle/python/security/SensitiveData.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/ChainedConfigs12.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/CleartextLogging.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/CleartextStorage.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/CodeInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/CommandInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/LdapInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/LogInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/PathInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/PolynomialReDoS.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/ReflectedXSS.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/RegexInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgery.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/SqlInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/StackTraceExposure.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/UnsafeDeserialization.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/UrlRedirect.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashing.qll delete mode 100644 python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/flow/AnyCall.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Deserialization.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Exec.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Marshal.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Path.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Pickle.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/RegexInjection.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Xml.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Yaml.qll delete mode 100644 python/ql/test/library-tests/security/sensitive/Sources.expected delete mode 100644 python/ql/test/library-tests/security/sensitive/Sources.ql delete mode 100644 python/ql/test/library-tests/security/sensitive/test.py delete mode 100644 python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/bottle/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/bottle/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/bottle/Routing.expected delete mode 100644 python/ql/test/library-tests/web/bottle/Routing.ql delete mode 100644 python/ql/test/library-tests/web/bottle/Taint.expected delete mode 100644 python/ql/test/library-tests/web/bottle/Taint.ql delete mode 100644 python/ql/test/library-tests/web/bottle/options delete mode 100644 python/ql/test/library-tests/web/bottle/test.py delete mode 100644 python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/cherrypy/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/cherrypy/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/cherrypy/options delete mode 100644 python/ql/test/library-tests/web/cherrypy/red.py delete mode 100644 python/ql/test/library-tests/web/cherrypy/test.py delete mode 100644 python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected delete mode 100644 python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql delete mode 100644 python/ql/test/library-tests/web/client/requests/options delete mode 100644 python/ql/test/library-tests/web/client/requests/test.py delete mode 100644 python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected delete mode 100644 python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql delete mode 100644 python/ql/test/library-tests/web/client/six/options delete mode 100644 python/ql/test/library-tests/web/client/six/test.py delete mode 100644 python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected delete mode 100644 python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql delete mode 100644 python/ql/test/library-tests/web/client/stdlib/options delete mode 100644 python/ql/test/library-tests/web/client/stdlib/test.py delete mode 100644 python/ql/test/library-tests/web/django/HttpRedirectSinks.expected delete mode 100644 python/ql/test/library-tests/web/django/HttpRedirectSinks.ql delete mode 100644 python/ql/test/library-tests/web/django/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/django/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/django/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/django/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/django/SqlInjectionSinks.expected delete mode 100644 python/ql/test/library-tests/web/django/SqlInjectionSinks.ql delete mode 100644 python/ql/test/library-tests/web/django/options delete mode 100644 python/ql/test/library-tests/web/django/sql.py delete mode 100644 python/ql/test/library-tests/web/django/test_1x.py delete mode 100644 python/ql/test/library-tests/web/django/test_2x_3x.py delete mode 100644 python/ql/test/library-tests/web/django/views_1x.py delete mode 100644 python/ql/test/library-tests/web/django/views_2x_3x.py delete mode 100644 python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/falcon/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/falcon/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/falcon/Routing.expected delete mode 100644 python/ql/test/library-tests/web/falcon/Routing.ql delete mode 100644 python/ql/test/library-tests/web/falcon/Sinks.expected delete mode 100644 python/ql/test/library-tests/web/falcon/Sinks.ql delete mode 100644 python/ql/test/library-tests/web/falcon/Taint.expected delete mode 100644 python/ql/test/library-tests/web/falcon/Taint.ql delete mode 100644 python/ql/test/library-tests/web/falcon/options delete mode 100644 python/ql/test/library-tests/web/falcon/test.py delete mode 100644 python/ql/test/library-tests/web/flask/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/flask/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/flask/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/flask/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/flask/Routing.expected delete mode 100644 python/ql/test/library-tests/web/flask/Routing.ql delete mode 100644 python/ql/test/library-tests/web/flask/Taint.expected delete mode 100644 python/ql/test/library-tests/web/flask/Taint.ql delete mode 100644 python/ql/test/library-tests/web/flask/options delete mode 100644 python/ql/test/library-tests/web/flask/test.py delete mode 100644 python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/pyramid/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/pyramid/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/pyramid/Routing.expected delete mode 100644 python/ql/test/library-tests/web/pyramid/Routing.ql delete mode 100644 python/ql/test/library-tests/web/pyramid/Taint.expected delete mode 100644 python/ql/test/library-tests/web/pyramid/Taint.ql delete mode 100644 python/ql/test/library-tests/web/pyramid/options delete mode 100644 python/ql/test/library-tests/web/pyramid/test.py delete mode 100644 python/ql/test/library-tests/web/stdlib/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/stdlib/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/stdlib/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/stdlib/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/stdlib/TestTaint.expected delete mode 100644 python/ql/test/library-tests/web/stdlib/TestTaint.ql delete mode 100644 python/ql/test/library-tests/web/stdlib/test.py delete mode 100644 python/ql/test/library-tests/web/tornado/Classes.expected delete mode 100644 python/ql/test/library-tests/web/tornado/Classes.ql delete mode 100644 python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected delete mode 100644 python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql delete mode 100644 python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/tornado/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/tornado/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/tornado/Taint.expected delete mode 100644 python/ql/test/library-tests/web/tornado/Taint.ql delete mode 100644 python/ql/test/library-tests/web/tornado/options delete mode 100644 python/ql/test/library-tests/web/tornado/test.py delete mode 100644 python/ql/test/library-tests/web/turbogears/Controller.expected delete mode 100644 python/ql/test/library-tests/web/turbogears/Controller.ql delete mode 100644 python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/turbogears/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/turbogears/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/turbogears/Taint.expected delete mode 100644 python/ql/test/library-tests/web/turbogears/Taint.ql delete mode 100644 python/ql/test/library-tests/web/turbogears/options delete mode 100644 python/ql/test/library-tests/web/turbogears/test.py delete mode 100644 python/ql/test/library-tests/web/twisted/Classes.expected delete mode 100644 python/ql/test/library-tests/web/twisted/Classes.ql delete mode 100644 python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected delete mode 100644 python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql delete mode 100644 python/ql/test/library-tests/web/twisted/HttpSources.expected delete mode 100644 python/ql/test/library-tests/web/twisted/HttpSources.ql delete mode 100644 python/ql/test/library-tests/web/twisted/Methods.expected delete mode 100644 python/ql/test/library-tests/web/twisted/Methods.ql delete mode 100644 python/ql/test/library-tests/web/twisted/Taint.expected delete mode 100644 python/ql/test/library-tests/web/twisted/Taint.ql delete mode 100644 python/ql/test/library-tests/web/twisted/options delete mode 100644 python/ql/test/library-tests/web/twisted/test.py diff --git a/python/ql/lib/semmle/python/Files.qll b/python/ql/lib/semmle/python/Files.qll index 4d331a26308..059a0d72b28 100644 --- a/python/ql/lib/semmle/python/Files.qll +++ b/python/ql/lib/semmle/python/Files.qll @@ -154,12 +154,6 @@ abstract class Container extends @container { */ string toString() { result = this.getAbsolutePath() } - /** - * Gets the name of this container. - * DEPRECATED: Use `getAbsolutePath` instead. - */ - deprecated string getName() { result = this.getAbsolutePath() } - /** * Gets the relative path of this file or folder from the root folder of the * analyzed source location. The relative path of the root folder itself is diff --git a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll index d0293522404..0ce4bc27790 100644 --- a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll +++ b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll @@ -664,14 +664,6 @@ module DataFlow { } } -deprecated private class DataFlowType extends TaintKind { - // this only exists to avoid an empty recursion error in the type checker - DataFlowType() { - this = "Data flow" and - 1 = 2 - } -} - pragma[noinline] private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) { dictnode.(DictNode).getAValue() = itemnode diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index 2240894a3f4..7fcc64f181e 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -534,9 +534,6 @@ module PrivateDjango { /** Gets a reference to the `django` module. */ API::Node django() { result = API::moduleImport("django") } - /** DEPRECATED: Alias for `DjangoImpl` */ - deprecated module django = DjangoImpl; - /** Provides models for the `django` module. */ module DjangoImpl { // ------------------------------------------------------------------------- @@ -552,9 +549,6 @@ module PrivateDjango { DjangoDb() { this = API::moduleImport("django").getMember("db") } } - /** DEPRECATED: Alias for `DB` */ - deprecated module db = DB; - /** Provides models for the `django.db` module. */ module DB { /** Gets a reference to the `django.db.connection` object. */ @@ -571,9 +565,6 @@ module PrivateDjango { /** Gets a reference to the `django.db.models` module. */ API::Node models() { result = db().getMember("models") } - /** DEPRECATED: Alias for `Models` */ - deprecated module models = Models; - /** Provides models for the `django.db.models` module. */ module Models { /** @@ -819,9 +810,6 @@ module PrivateDjango { /** Gets a reference to the `django.db.models.expressions` module. */ API::Node expressions() { result = models().getMember("expressions") } - /** DEPRECATED: Alias for `Expressions` */ - deprecated module expressions = Expressions; - /** Provides models for the `django.db.models.expressions` module. */ module Expressions { /** Provides models for the `django.db.models.expressions.RawSql` class. */ @@ -858,9 +846,6 @@ module PrivateDjango { instance(DataFlow::TypeTracker::end(), sql).flowsTo(result) } } - - /** DEPRECATED: Alias for RawSql */ - deprecated module RawSQL = RawSql; } /** This internal module provides data-flow modeling of Django ORM. */ @@ -1099,9 +1084,6 @@ module PrivateDjango { /** Gets a reference to the `django.urls` module. */ API::Node urls() { result = django().getMember("urls") } - /** DEPRECATED: Alias for `Urls` */ - deprecated module urls = Urls; - /** Provides models for the `django.urls` module */ module Urls { /** @@ -1123,14 +1105,8 @@ module PrivateDjango { /** Gets a reference to the `django.conf` module. */ API::Node conf() { result = django().getMember("conf") } - /** DEPRECATED: Alias for `Conf` */ - deprecated module conf = Conf; - /** Provides models for the `django.conf` module */ module Conf { - /** DEPRECATED: Alias for `ConfUrls` */ - deprecated module conf_urls = ConfUrls; - /** Provides models for the `django.conf.urls` module */ module ConfUrls { // ------------------------------------------------------------------------- @@ -1166,9 +1142,6 @@ module PrivateDjango { /** Gets a reference to the `django.http.request` module. */ API::Node request() { result = http().getMember("request") } - /** DEPRECATED: Alias for `Request` */ - deprecated module request = Request; - /** Provides models for the `django.http.request` module. */ module Request { /** @@ -1331,9 +1304,6 @@ module PrivateDjango { /** Gets a reference to the `django.http.response` module. */ API::Node response() { result = http().getMember("response") } - /** DEPRECATED: Alias for `Response` */ - deprecated module response = Response; - /** Provides models for the `django.http.response` module */ module Response { /** @@ -2189,9 +2159,6 @@ module PrivateDjango { /** Gets a reference to the `django.shortcuts` module. */ API::Node shortcuts() { result = django().getMember("shortcuts") } - /** DEPRECATED: Alias for `Shortcuts` */ - deprecated module shortcuts = Shortcuts; - /** Provides models for the `django.shortcuts` module */ module Shortcuts { /** diff --git a/python/ql/lib/semmle/python/frameworks/FastApi.qll b/python/ql/lib/semmle/python/frameworks/FastApi.qll index d6f5bba6d9f..07dbd982653 100644 --- a/python/ql/lib/semmle/python/frameworks/FastApi.qll +++ b/python/ql/lib/semmle/python/frameworks/FastApi.qll @@ -37,9 +37,6 @@ private module FastApi { } } - /** DEPRECATED: Alias for ApiRouter */ - deprecated module APIRouter = ApiRouter; - // --------------------------------------------------------------------------- // routing modeling // --------------------------------------------------------------------------- diff --git a/python/ql/lib/semmle/python/frameworks/RestFramework.qll b/python/ql/lib/semmle/python/frameworks/RestFramework.qll index dcbd247a1c5..23b32946e31 100644 --- a/python/ql/lib/semmle/python/frameworks/RestFramework.qll +++ b/python/ql/lib/semmle/python/frameworks/RestFramework.qll @@ -359,7 +359,4 @@ private module RestFramework { override string getMimetypeDefault() { none() } } } - - /** DEPRECATED: Alias for ApiException */ - deprecated module APIException = ApiException; } diff --git a/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll b/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll index c1712e7e7eb..0bb0125cf5c 100644 --- a/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll +++ b/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll @@ -169,9 +169,6 @@ module SqlAlchemy { DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } } - /** DEPRECATED: Alias for DBApiConnection */ - deprecated module DBAPIConnection = DBApiConnection; - /** * Provides models for the `sqlalchemy.orm.Session` class * diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index cd5ec31945e..8af918f4bb4 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -130,9 +130,6 @@ module Stdlib { } } - /** DEPRECATED: Alias for HttpMessage */ - deprecated module HTTPMessage = HttpMessage; - /** * Provides models for the `http.cookies.Morsel` class * @@ -1821,9 +1818,6 @@ private module StdlibPrivate { /** Gets a reference to the `BaseHttpServer` module. */ API::Node baseHttpServer() { result = API::moduleImport("BaseHTTPServer") } - /** DEPRECATED: Alias for baseHttpServer */ - deprecated API::Node baseHTTPServer() { result = baseHttpServer() } - /** Provides models for the `BaseHttpServer` module. */ module BaseHttpServer { /** @@ -1833,23 +1827,14 @@ private module StdlibPrivate { /** Gets a reference to the `BaseHttpServer.BaseHttpRequestHandler` class. */ API::Node classRef() { result = baseHttpServer().getMember("BaseHTTPRequestHandler") } } - - /** DEPRECATED: Alias for BaseHttpRequestHandler */ - deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler; } - /** DEPRECATED: Alias for BaseHttpServer */ - deprecated module BaseHTTPServer = BaseHttpServer; - // --------------------------------------------------------------------------- // SimpleHTTPServer (Python 2 only) // --------------------------------------------------------------------------- /** Gets a reference to the `SimpleHttpServer` module. */ API::Node simpleHttpServer() { result = API::moduleImport("SimpleHTTPServer") } - /** DEPRECATED: Alias for simpleHttpServer */ - deprecated API::Node simpleHTTPServer() { result = simpleHttpServer() } - /** Provides models for the `SimpleHttpServer` module. */ module SimpleHttpServer { /** @@ -1859,23 +1844,14 @@ private module StdlibPrivate { /** Gets a reference to the `SimpleHttpServer.SimpleHttpRequestHandler` class. */ API::Node classRef() { result = simpleHttpServer().getMember("SimpleHTTPRequestHandler") } } - - /** DEPRECATED: Alias for SimpleHttpRequestHandler */ - deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler; } - /** DEPRECATED: Alias for SimpleHttpServer */ - deprecated module SimpleHTTPServer = SimpleHttpServer; - // --------------------------------------------------------------------------- // CGIHTTPServer (Python 2 only) // --------------------------------------------------------------------------- /** Gets a reference to the `CGIHTTPServer` module. */ API::Node cgiHttpServer() { result = API::moduleImport("CGIHTTPServer") } - /** DEPRECATED: Alias for cgiHttpServer */ - deprecated API::Node cgiHTTPServer() { result = cgiHttpServer() } - /** Provides models for the `CGIHTTPServer` module. */ module CgiHttpServer { /** @@ -1919,9 +1895,6 @@ private module StdlibPrivate { API::Node classRef() { result = server().getMember("BaseHTTPRequestHandler") } } - /** DEPRECATED: Alias for BaseHttpRequestHandler */ - deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler; - /** * Provides models for the `http.server.SimpleHTTPRequestHandler` class (Python 3 only). * @@ -1932,9 +1905,6 @@ private module StdlibPrivate { API::Node classRef() { result = server().getMember("SimpleHTTPRequestHandler") } } - /** DEPRECATED: Alias for SimpleHttpRequestHandler */ - deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler; - /** * Provides models for the `http.server.CGIHTTPRequestHandler` class (Python 3 only). * @@ -1978,9 +1948,6 @@ private module StdlibPrivate { HttpRequestHandlerClassDef() { this.getParent() = subclassRef().asSource().asExpr() } } - /** DEPRECATED: Alias for HttpRequestHandlerClassDef */ - deprecated class HTTPRequestHandlerClassDef = HttpRequestHandlerClassDef; - /** * A source of instances of the `BaseHTTPRequestHandler` class or any subclass, extend this class to model new instances. * @@ -2352,9 +2319,6 @@ private module StdlibPrivate { } } - /** DEPRECATED: Alias for HttpConnection */ - deprecated module HTTPConnection = HttpConnection; - /** * Provides models for the `http.client.HTTPResponse` class * @@ -2424,9 +2388,6 @@ private module StdlibPrivate { } } - /** DEPRECATED: Alias for HttpResponse */ - deprecated module HTTPResponse = HttpResponse; - // --------------------------------------------------------------------------- // sqlite3 // --------------------------------------------------------------------------- diff --git a/python/ql/lib/semmle/python/frameworks/Tornado.qll b/python/ql/lib/semmle/python/frameworks/Tornado.qll index 12a69908f80..73c016ed927 100644 --- a/python/ql/lib/semmle/python/frameworks/Tornado.qll +++ b/python/ql/lib/semmle/python/frameworks/Tornado.qll @@ -64,9 +64,6 @@ module Tornado { } } - /** DEPRECATED: Alias for HttpHeaders */ - deprecated module HTTPHeaders = HttpHeaders; - // --------------------------------------------------------------------------- // tornado // --------------------------------------------------------------------------- diff --git a/python/ql/lib/semmle/python/pointsto/PointsTo.qll b/python/ql/lib/semmle/python/pointsto/PointsTo.qll index 1369d6d6ce7..fb05e9b49ff 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsTo.qll @@ -1445,14 +1445,6 @@ module Expressions { ) } - deprecated predicate subscriptPointsTo( - SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode obj, ObjectInternal objvalue - ) { - subscriptPointsTo(subscr, context, value, obj, objvalue) and - origin = subscr - } - pragma[noinline] private predicate subscriptPointsTo( SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj, @@ -1489,14 +1481,6 @@ module Expressions { index = subscr.getIndex() } - deprecated predicate binaryPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - binaryPointsTo(b, context, value, operand, opvalue) and - origin = b - } - /** * Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'. */ @@ -1521,14 +1505,6 @@ module Expressions { ) } - deprecated predicate addPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - addPointsTo(b, context, value, operand, opvalue) and - origin = b - } - pragma[noinline] private predicate addPointsTo( BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand, @@ -1545,14 +1521,6 @@ module Expressions { ) } - deprecated predicate bitOrPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - bitOrPointsTo(b, context, value, operand, opvalue) and - origin = b - } - pragma[noinline] private predicate bitOrPointsTo( BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand, @@ -1577,14 +1545,6 @@ module Expressions { value = obj.intValue() } - deprecated predicate unaryPointsTo( - UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - unaryPointsTo(u, context, value, operand, opvalue) and - origin = u - } - pragma[noinline] private predicate unaryPointsTo( UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand, @@ -1603,14 +1563,6 @@ module Expressions { ) } - deprecated predicate builtinCallPointsTo( - CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode arg, ObjectInternal argvalue - ) { - builtinCallPointsTo(call, context, value, arg, argvalue) and - origin = call - } - pragma[noinline] private predicate builtinCallPointsTo( CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg, diff --git a/python/ql/lib/semmle/python/security/ClearText.qll b/python/ql/lib/semmle/python/security/ClearText.qll deleted file mode 100644 index c466be17ae6..00000000000 --- a/python/ql/lib/semmle/python/security/ClearText.qll +++ /dev/null @@ -1,54 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.SensitiveData -import semmle.python.dataflow.Files -import semmle.python.web.Http - -deprecated module ClearTextStorage { - abstract class Sink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } - } - - class CookieStorageSink extends Sink { - CookieStorageSink() { any(CookieSet cookie).getValue() = this } - } - - class FileStorageSink extends Sink { - FileStorageSink() { - exists(CallNode call, AttrNode meth, string name | - any(OpenFile fd).taints(meth.getObject(name)) and - call.getFunction() = meth and - call.getAnArg() = this - | - name = "write" - ) - } - } -} - -deprecated module ClearTextLogging { - abstract class Sink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } - } - - class PrintSink extends Sink { - PrintSink() { - exists(CallNode call | - call.getAnArg() = this and - call = Value::named("print").getACall() - ) - } - } - - class LoggingSink extends Sink { - LoggingSink() { - exists(CallNode call, AttrNode meth, string name | - call.getFunction() = meth and - meth.getObject(name).(NameNode).getId().matches("logg%") and - call.getAnArg() = this - | - name = ["error", "warn", "warning", "debug", "info"] - ) - } - } -} diff --git a/python/ql/lib/semmle/python/security/Crypto.qll b/python/ql/lib/semmle/python/security/Crypto.qll deleted file mode 100644 index dbf53f8a0fa..00000000000 --- a/python/ql/lib/semmle/python/security/Crypto.qll +++ /dev/null @@ -1,139 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -private import semmle.python.security.SensitiveData -private import semmle.crypto.Crypto as CryptoLib - -abstract deprecated class WeakCryptoSink extends TaintSink { - override predicate sinks(TaintKind taint) { taint instanceof SensitiveData } -} - -/** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */ -deprecated module Pycrypto { - ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) } - - class CipherInstance extends TaintKind { - string name; - - CipherInstance() { - this = "Crypto.Cipher." + name and - exists(cipher(name)) - } - - string getName() { result = name } - - CryptoLib::CryptographicAlgorithm getAlgorithm() { result.getName() = name } - - predicate isWeak() { this.getAlgorithm().isWeak() } - } - - class CipherInstanceSource extends TaintSource { - CipherInstance instance; - - CipherInstanceSource() { - exists(AttrNode attr | - this.(CallNode).getFunction() = attr and - attr.getObject("new").pointsTo(cipher(instance.getName())) - ) - } - - override string toString() { result = "Source of " + instance } - - override predicate isSourceOf(TaintKind kind) { kind = instance } - } - - class PycryptoWeakCryptoSink extends WeakCryptoSink { - string name; - - PycryptoWeakCryptoSink() { - exists(CallNode call, AttrNode method, CipherInstance cipher | - call.getAnArg() = this and - call.getFunction() = method and - cipher.taints(method.getObject("encrypt")) and - cipher.isWeak() and - cipher.getName() = name - ) - } - - override string toString() { result = "Use of weak crypto algorithm " + name } - } -} - -deprecated module Cryptography { - ModuleValue ciphers() { - result = Module::named("cryptography.hazmat.primitives.ciphers") and - result.isPackage() - } - - class CipherClass extends ClassValue { - CipherClass() { ciphers().attr("Cipher") = this } - } - - class AlgorithmClass extends ClassValue { - AlgorithmClass() { ciphers().attr("algorithms").attr(_) = this } - - string getAlgorithmName() { result = this.declaredAttribute("name").(StringValue).getText() } - - predicate isWeak() { - exists(CryptoLib::CryptographicAlgorithm algo | - algo.getName() = this.getAlgorithmName() and - algo.isWeak() - ) - } - } - - class CipherInstance extends TaintKind { - AlgorithmClass cls; - - CipherInstance() { this = "cryptography.Cipher." + cls.getAlgorithmName() } - - AlgorithmClass getAlgorithm() { result = cls } - - predicate isWeak() { cls.isWeak() } - - override TaintKind getTaintOfMethodResult(string name) { - name = "encryptor" and - result.(Encryptor).getAlgorithm() = this.getAlgorithm() - } - } - - class CipherSource extends TaintSource { - CipherSource() { this.(CallNode).getFunction().pointsTo(any(CipherClass cls)) } - - override predicate isSourceOf(TaintKind kind) { - this.(CallNode).getArg(0).pointsTo().getClass() = kind.(CipherInstance).getAlgorithm() - } - - override string toString() { result = "cryptography.Cipher.source" } - } - - class Encryptor extends TaintKind { - AlgorithmClass cls; - - Encryptor() { this = "cryptography.encryptor." + cls.getAlgorithmName() } - - AlgorithmClass getAlgorithm() { result = cls } - } - - class CryptographyWeakCryptoSink extends WeakCryptoSink { - CryptographyWeakCryptoSink() { - exists(CallNode call, AttrNode method, Encryptor encryptor | - call.getAnArg() = this and - call.getFunction() = method and - encryptor.taints(method.getObject("update")) and - encryptor.getAlgorithm().isWeak() - ) - } - - override string toString() { result = "Use of weak crypto algorithm" } - } -} - -deprecated private class CipherConfig extends TaintTracking::Configuration { - CipherConfig() { this = "Crypto cipher config" } - - override predicate isSource(TaintTracking::Source source) { - source instanceof Pycrypto::CipherInstanceSource - or - source instanceof Cryptography::CipherSource - } -} diff --git a/python/ql/lib/semmle/python/security/SensitiveData.qll b/python/ql/lib/semmle/python/security/SensitiveData.qll deleted file mode 100644 index 7a955c0fd5a..00000000000 --- a/python/ql/lib/semmle/python/security/SensitiveData.qll +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Provides classes and predicates for identifying sensitive data and methods for security. - * - * 'Sensitive' data in general is anything that should not be sent around in unencrypted form. This - * library tries to guess where sensitive data may either be stored in a variable or produced by a - * method. - * - * In addition, there are methods that ought not to be executed or not in a fashion that the user - * can control. This includes authorization methods such as logins, and sending of data, etc. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.HttpRequest -import semmle.python.security.internal.SensitiveDataHeuristics -private import HeuristicNames - -abstract deprecated class SensitiveData extends TaintKind { - bindingset[this] - SensitiveData() { this = this } - - /** Gets the classification of this sensitive data taint kind. */ - abstract SensitiveDataClassification getClassification(); -} - -deprecated module SensitiveData { - class Secret extends SensitiveData { - Secret() { this = "sensitive.data.secret" } - - override string repr() { result = "a secret" } - - override SensitiveDataClassification getClassification() { - result = SensitiveDataClassification::secret() - } - } - - class Id extends SensitiveData { - Id() { this = "sensitive.data.id" } - - override string repr() { result = "an ID" } - - override SensitiveDataClassification getClassification() { - result = SensitiveDataClassification::id() - } - } - - class Password extends SensitiveData { - Password() { this = "sensitive.data.password" } - - override string repr() { result = "a password" } - - override SensitiveDataClassification getClassification() { - result = SensitiveDataClassification::password() - } - } - - class Certificate extends SensitiveData { - Certificate() { this = "sensitive.data.certificate" } - - override string repr() { result = "a certificate or key" } - - override SensitiveDataClassification getClassification() { - result = SensitiveDataClassification::certificate() - } - } - - private SensitiveData fromFunction(Value func) { - nameIndicatesSensitiveData(func.getName(), result.getClassification()) - } - - abstract class Source extends TaintSource { - abstract string repr(); - } - - private class SensitiveCallSource extends Source { - SensitiveData data; - - SensitiveCallSource() { - exists(Value callee | callee.getACall() = this | data = fromFunction(callee)) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "a call returning " + data.repr() } - } - - /** An access to a variable or property that might contain sensitive data. */ - private class SensitiveVariableAccess extends SensitiveData::Source { - SensitiveData data; - - SensitiveVariableAccess() { - nameIndicatesSensitiveData(this.(AttrNode).getName(), data.getClassification()) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "an attribute or property containing " + data.repr() } - } - - private class SensitiveRequestParameter extends SensitiveData::Source { - SensitiveData data; - - SensitiveRequestParameter() { - this.(CallNode).getFunction().(AttrNode).getName() = "get" and - exists(StringValue sensitive | - this.(CallNode).getAnArg().pointsTo(sensitive) and - nameIndicatesSensitiveData(sensitive.getText(), data.getClassification()) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "a request parameter containing " + data.repr() } - } -} - -//Backwards compatibility -deprecated class SensitiveDataSource = SensitiveData::Source; diff --git a/python/ql/lib/semmle/python/security/dataflow/ChainedConfigs12.qll b/python/ql/lib/semmle/python/security/dataflow/ChainedConfigs12.qll deleted file mode 100644 index 7eee413131b..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/ChainedConfigs12.qll +++ /dev/null @@ -1,95 +0,0 @@ -/** - * DEPRECATED -- use flow state instead - * - * This defines a `PathGraph` where sinks from `TaintTracking::Configuration`s are identified with - * sources from `TaintTracking2::Configuration`s if they represent the same `ControlFlowNode`. - * - * Paths are then connected appropriately. - */ - -import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.DataFlow2 -import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.TaintTracking2 - -/** - * A `DataFlow::Node` that appears as a sink in Config1 and a source in Config2. - */ -private predicate crossoverNode(DataFlow::Node n) { - any(TaintTracking::Configuration t1).isSink(n) and - any(TaintTracking2::Configuration t2).isSource(n) -} - -/** - * A new type which represents the union of the two sets of nodes. - */ -private newtype TCustomPathNode = - Config1Node(DataFlow::PathNode node1) { not crossoverNode(node1.getNode()) } or - Config2Node(DataFlow2::PathNode node2) { not crossoverNode(node2.getNode()) } or - CrossoverNode(DataFlow::Node node) { crossoverNode(node) } - -/** - * DEPRECATED: Use flow state instead - * - * A class representing the set of all the path nodes in either config. - */ -deprecated class CustomPathNode extends TCustomPathNode { - /** Gets the PathNode if it is in Config1. */ - DataFlow::PathNode asNode1() { - this = Config1Node(result) or this = CrossoverNode(result.getNode()) - } - - /** Gets the PathNode if it is in Config2. */ - DataFlow2::PathNode asNode2() { - this = Config2Node(result) or this = CrossoverNode(result.getNode()) - } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.asNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - or - this.asNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets a textual representation of this element. */ - string toString() { - result = this.asNode1().toString() - or - result = this.asNode2().toString() - } -} - -/** - * DEPRECATED: Use flow state instead - * - * Holds if `(a,b)` is an edge in the graph of data flow path explanations. - */ -deprecated query predicate edges(CustomPathNode a, CustomPathNode b) { - // Edge is in Config1 graph - DataFlow::PathGraph::edges(a.asNode1(), b.asNode1()) - or - // Edge is in Config2 graph - DataFlow2::PathGraph::edges(a.asNode2(), b.asNode2()) -} - -/** - * DEPRECATED: Use flow state instead - * - * Holds if `n` is a node in the graph of data flow path explanations. - */ -deprecated query predicate nodes(CustomPathNode n, string key, string val) { - // Node is in Config1 graph - DataFlow::PathGraph::nodes(n.asNode1(), key, val) - or - // Node is in Config2 graph - DataFlow2::PathGraph::nodes(n.asNode2(), key, val) -} diff --git a/python/ql/lib/semmle/python/security/dataflow/CleartextLogging.qll b/python/ql/lib/semmle/python/security/dataflow/CleartextLogging.qll deleted file mode 100644 index 4471c9f4c34..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/CleartextLogging.qll +++ /dev/null @@ -1,14 +0,0 @@ -/** DEPRECATED. Import `CleartextLoggingQuery` instead. */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.dataflow.new.BarrierGuards -private import semmle.python.dataflow.new.SensitiveDataSources - -/** DEPRECATED. Import `CleartextLoggingQuery` instead. */ -deprecated module CleartextLogging { - import CleartextLoggingQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/CleartextStorage.qll b/python/ql/lib/semmle/python/security/dataflow/CleartextStorage.qll deleted file mode 100644 index 105510aaeb5..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/CleartextStorage.qll +++ /dev/null @@ -1,14 +0,0 @@ -/** DEPRECATED. Import `CleartextStorageQuery` instead. */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.dataflow.new.BarrierGuards -private import semmle.python.dataflow.new.SensitiveDataSources - -/** DEPRECATED. Import `CleartextStorageQuery` instead. */ -deprecated module CleartextStorage { - import CleartextStorageQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/CodeInjection.qll b/python/ql/lib/semmle/python/security/dataflow/CodeInjection.qll deleted file mode 100644 index 35f6d96b753..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/CodeInjection.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** DEPRECATED. Import `CodeInjectionQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `CodeInjectionQuery` instead. */ -deprecated module CodeInjection { - import CodeInjectionQuery // ignore-query-import -} - -/** DEPRECATED. Import `CodeInjectionQuery` instead. */ -deprecated class CodeInjectionConfiguration = CodeInjection::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/CommandInjection.qll b/python/ql/lib/semmle/python/security/dataflow/CommandInjection.qll deleted file mode 100644 index c72be4985fc..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/CommandInjection.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** DEPRECATED. Import `CommandInjectionQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `CommandInjectionQuery` instead. */ -deprecated module CommandInjection { - import CommandInjectionQuery // ignore-query-import -} - -/** DEPRECATED. Import `CommandInjectionQuery` instead. */ -deprecated class CommandInjectionConfiguration = CommandInjection::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/LdapInjection.qll b/python/ql/lib/semmle/python/security/dataflow/LdapInjection.qll deleted file mode 100644 index df9e89dbf82..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/LdapInjection.qll +++ /dev/null @@ -1,12 +0,0 @@ -/** DEPRECATED. Import `LdapInjectionQuery` instead. */ - -import python -import semmle.python.Concepts -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.RemoteFlowSources - -/** DEPRECATED. Import `LdapInjectionQuery` instead. */ -deprecated module LdapInjection { - import LdapInjectionQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/LogInjection.qll b/python/ql/lib/semmle/python/security/dataflow/LogInjection.qll deleted file mode 100644 index 0a00e695483..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/LogInjection.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** DEPRECATED. Import `LogInjectionQuery` instead. */ - -import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `LogInjectionQuery` instead. */ -deprecated module LogInjection { - import LogInjectionQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/PathInjection.qll b/python/ql/lib/semmle/python/security/dataflow/PathInjection.qll deleted file mode 100644 index 79e61abb0ce..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/PathInjection.qll +++ /dev/null @@ -1,133 +0,0 @@ -/** DEPRECATED. Import `PathInjectionQuery` instead. */ - -private import python -private import semmle.python.Concepts -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `PathInjectionQuery` instead. */ -deprecated module PathInjection { - import PathInjectionQuery // ignore-query-import -} - -// --------------------------------------------------------------------------- -// Old, deprecated code -// --------------------------------------------------------------------------- -private import semmle.python.dataflow.new.DataFlow2 -private import semmle.python.dataflow.new.TaintTracking2 -private import ChainedConfigs12 -import PathInjectionCustomizations::PathInjection - -// --------------------------------------------------------------------------- -// Case 1. The path is never normalized. -// --------------------------------------------------------------------------- -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Configuration to find paths from sources to sinks that contain no normalization. - */ -deprecated class PathNotNormalizedConfiguration extends TaintTracking::Configuration { - PathNotNormalizedConfiguration() { this = "PathNotNormalizedConfiguration" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - node instanceof Sanitizer - or - node instanceof Path::PathNormalization - } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof SanitizerGuard - } -} - -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Holds if there is a path injection from source to sink, where the (python) path is - * not normalized. - */ -deprecated predicate pathNotNormalized(CustomPathNode source, CustomPathNode sink) { - any(PathNotNormalizedConfiguration config).hasFlowPath(source.asNode1(), sink.asNode1()) -} - -// --------------------------------------------------------------------------- -// Case 2. The path is normalized at least once, but never checked afterwards. -// --------------------------------------------------------------------------- -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Configuration to find paths from sources to normalizations that contain no prior normalizations. - */ -deprecated class FirstNormalizationConfiguration extends TaintTracking::Configuration { - FirstNormalizationConfiguration() { this = "FirstNormalizationConfiguration" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Path::PathNormalization } - - override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } - - override predicate isSanitizerOut(DataFlow::Node node) { node instanceof Path::PathNormalization } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof SanitizerGuard - } -} - -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Configuration to find paths from normalizations to sinks that do not go through a check. - */ -deprecated class NormalizedPathNotCheckedConfiguration extends TaintTracking2::Configuration { - NormalizedPathNotCheckedConfiguration() { this = "NormalizedPathNotCheckedConfiguration" } - - override predicate isSource(DataFlow::Node source) { source instanceof Path::PathNormalization } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - node instanceof Path::SafeAccessCheck - or - node instanceof Sanitizer - } - - override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof SanitizerGuard - } -} - -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Holds if there is a path injection from source to sink, where the (python) path is - * normalized at least once, but never checked afterwards. - */ -deprecated predicate pathNotCheckedAfterNormalization(CustomPathNode source, CustomPathNode sink) { - exists( - FirstNormalizationConfiguration config, DataFlow::PathNode mid1, DataFlow2::PathNode mid2, - NormalizedPathNotCheckedConfiguration config2 - | - config.hasFlowPath(source.asNode1(), mid1) and - config2.hasFlowPath(mid2, sink.asNode2()) and - mid1.getNode().asCfgNode() = mid2.getNode().asCfgNode() - ) -} - -// --------------------------------------------------------------------------- -// Query: Either case 1 or case 2. -// --------------------------------------------------------------------------- -/** - * DEPRECATED: Import `PathInjectionQuery` instead. - * - * Holds if there is a path injection from source to sink - */ -deprecated predicate pathInjection(CustomPathNode source, CustomPathNode sink) { - pathNotNormalized(source, sink) - or - pathNotCheckedAfterNormalization(source, sink) -} diff --git a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoS.qll b/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoS.qll deleted file mode 100644 index 5454b889f03..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoS.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */ -deprecated module PolynomialReDoS { - import PolynomialReDoSQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSS.qll b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSS.qll deleted file mode 100644 index 2e481d25cf7..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSS.qll +++ /dev/null @@ -1,16 +0,0 @@ -/** DEPRECATED. Import `ReflectedXSSQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `ReflectedXSSQuery` instead. */ -deprecated module ReflectedXss { - import ReflectedXssQuery // ignore-query-import -} - -/** DEPRECATED. Import `ReflectedXSSQuery` instead. */ -deprecated module ReflectedXSS = ReflectedXss; - -/** DEPRECATED. Import `ReflectedXSSQuery` instead. */ -deprecated class ReflectedXssConfiguration = ReflectedXss::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll index ea826c3b0c5..2229d0c758c 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll @@ -76,6 +76,3 @@ module ReflectedXss { */ class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } } - -/** DEPRECATED: Alias for ReflectedXss */ -deprecated module ReflectedXSS = ReflectedXss; diff --git a/python/ql/lib/semmle/python/security/dataflow/RegexInjection.qll b/python/ql/lib/semmle/python/security/dataflow/RegexInjection.qll deleted file mode 100644 index decc9b00946..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/RegexInjection.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** DEPRECATED. Import `RegexInjectionQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `RegexInjectionQuery` instead. */ -deprecated module RegexInjection { - import RegexInjectionQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgery.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgery.qll deleted file mode 100644 index dd04ccf4cf5..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgery.qll +++ /dev/null @@ -1,25 +0,0 @@ -/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking -import semmle.python.Concepts -import ServerSideRequestForgeryQuery as ServerSideRequestForgeryQuery // ignore-query-import - -/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */ -deprecated module FullServerSideRequestForgery { - import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery - - class Configuration = ServerSideRequestForgeryQuery::FullServerSideRequestForgeryConfiguration; -} - -/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */ -deprecated predicate fullyControlledRequest = - ServerSideRequestForgeryQuery::fullyControlledRequest/1; - -/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */ -deprecated module PartialServerSideRequestForgery { - import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery - - class Configuration = ServerSideRequestForgeryQuery::PartialServerSideRequestForgeryConfiguration; -} diff --git a/python/ql/lib/semmle/python/security/dataflow/SqlInjection.qll b/python/ql/lib/semmle/python/security/dataflow/SqlInjection.qll deleted file mode 100644 index eebe6251c22..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/SqlInjection.qll +++ /dev/null @@ -1,16 +0,0 @@ -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ -deprecated module SqlInjection { - import SqlInjectionQuery // ignore-query-import -} - -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ -deprecated class SqlInjectionConfiguration = SqlInjection::Configuration; - -/** DEPRECATED. Import `SqlInjectionQuery` instead. */ -deprecated class SQLInjectionConfiguration = SqlInjectionConfiguration; diff --git a/python/ql/lib/semmle/python/security/dataflow/StackTraceExposure.qll b/python/ql/lib/semmle/python/security/dataflow/StackTraceExposure.qll deleted file mode 100644 index 64e59756dff..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/StackTraceExposure.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** DEPRECATED. Import `StackTraceExposureQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `StackTraceExposureQuery` instead. */ -deprecated module StackTraceExposure { - import StackTraceExposureQuery // ignore-query-import -} - -/** DEPRECATED. Import `StackTraceExposureQuery` instead. */ -deprecated class StackTraceExposureConfiguration = StackTraceExposure::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserialization.qll b/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserialization.qll deleted file mode 100644 index 3bdd569128d..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserialization.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */ -deprecated module UnsafeDeserialization { - import UnsafeDeserializationQuery // ignore-query-import -} - -/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */ -deprecated class UnsafeDeserializationConfiguration = UnsafeDeserialization::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/UrlRedirect.qll b/python/ql/lib/semmle/python/security/dataflow/UrlRedirect.qll deleted file mode 100644 index 4cb354eabf8..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/UrlRedirect.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** DEPRECATED. Import `UrlRedirectQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `UrlRedirectQuery` instead. */ -deprecated module UrlRedirect { - import UrlRedirectQuery // ignore-query-import -} - -/** DEPRECATED. Import `UrlRedirectQuery` instead. */ -deprecated class UrlRedirectConfiguration = UrlRedirect::Configuration; diff --git a/python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashing.qll b/python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashing.qll deleted file mode 100644 index 867b3bedd0b..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashing.qll +++ /dev/null @@ -1,19 +0,0 @@ -/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.dataflow.new.BarrierGuards -private import semmle.python.dataflow.new.SensitiveDataSources - -/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */ -deprecated module NormalHashFunction { - import WeakSensitiveDataHashingQuery::NormalHashFunction // ignore-query-import -} - -/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */ -deprecated module ComputationallyExpensiveHashFunction { - import WeakSensitiveDataHashingQuery::ComputationallyExpensiveHashFunction // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll deleted file mode 100644 index 2ed69d035f9..00000000000 --- a/python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** DEPRECATED. Import `XpathInjectionQuery` instead. */ - -private import python -import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking - -/** DEPRECATED. Import `XpathInjectionQuery` instead. */ -deprecated module XpathInjection { - import XpathInjectionQuery // ignore-query-import -} diff --git a/python/ql/lib/semmle/python/security/flow/AnyCall.qll b/python/ql/lib/semmle/python/security/flow/AnyCall.qll deleted file mode 100644 index 6c93f3841b2..00000000000 --- a/python/ql/lib/semmle/python/security/flow/AnyCall.qll +++ /dev/null @@ -1,9 +0,0 @@ -import python -import semmle.python.security.strings.Basic - -/** Assume that taint flows from argument to result for *any* call */ -deprecated class AnyCallStringFlow extends DataFlowExtension::DataFlowNode { - AnyCallStringFlow() { any(CallNode call).getAnArg() = this } - - override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this } -} diff --git a/python/ql/lib/semmle/python/security/injection/Deserialization.qll b/python/ql/lib/semmle/python/security/injection/Deserialization.qll deleted file mode 100644 index b516a2d6b2f..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Deserialization.qll +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking - -/** `pickle.loads(untrusted)` vulnerability. */ -abstract deprecated class DeserializationSink extends TaintSink { - bindingset[this] - DeserializationSink() { this = this } -} diff --git a/python/ql/lib/semmle/python/security/injection/Exec.qll b/python/ql/lib/semmle/python/security/injection/Exec.qll deleted file mode 100644 index 3ff84915ae0..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Exec.qll +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious Python code. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -/** - * A taint sink that represents an argument to exec or eval that is vulnerable to malicious input. - * The `vuln` in `exec(vuln)` or similar. - */ -deprecated class StringEvaluationNode extends TaintSink { - override string toString() { result = "exec or eval" } - - StringEvaluationNode() { - exists(Exec exec | exec.getASubExpression().getAFlowNode() = this) - or - Value::named("exec").getACall().getAnArg() = this - or - Value::named("eval").getACall().getAnArg() = this - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/security/injection/Marshal.qll b/python/ql/lib/semmle/python/security/injection/Marshal.qll deleted file mode 100644 index 815890903bd..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Marshal.qll +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious marshals. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.injection.Deserialization - -deprecated private FunctionObject marshalLoads() { - result = ModuleObject::named("marshal").attr("loads") -} - -/** - * A taint sink that is potentially vulnerable to malicious marshaled objects. - * The `vuln` in `marshal.loads(vuln)`. - */ -deprecated class UnmarshalingNode extends DeserializationSink { - override string toString() { result = "unmarshaling vulnerability" } - - UnmarshalingNode() { - exists(CallNode call | - marshalLoads().getACall() = call and - call.getAnArg() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/security/injection/Path.qll b/python/ql/lib/semmle/python/security/injection/Path.qll deleted file mode 100644 index 73d76104493..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Path.qll +++ /dev/null @@ -1,81 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -/** - * Prevents taint flowing through ntpath.normpath() - * NormalizedPath below handles that case. - */ -deprecated class PathSanitizer extends Sanitizer { - PathSanitizer() { this = "path.sanitizer" } - - override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { - taint instanceof ExternalStringKind and - abspath_call(node, _) - } -} - -deprecated private FunctionObject abspath() { - exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path | - os_path.attr("abspath") = result - or - os_path.attr("normpath") = result - ) -} - -/** A path that has been normalized, but not verified to be safe */ -deprecated class NormalizedPath extends TaintKind { - NormalizedPath() { this = "normalized.path.injection" } - - override string repr() { result = "normalized path" } -} - -deprecated private predicate abspath_call(CallNode call, ControlFlowNode arg) { - call.getFunction().refersTo(abspath()) and - arg = call.getArg(0) -} - -deprecated class AbsPath extends DataFlowExtension::DataFlowNode { - AbsPath() { abspath_call(_, this) } - - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - abspath_call(result, this) and - tokind instanceof NormalizedPath and - fromkind instanceof ExternalStringKind - } -} - -deprecated class NormalizedPathSanitizer extends Sanitizer { - NormalizedPathSanitizer() { this = "normalized.path.sanitizer" } - - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof NormalizedPath and - test.getTest().(CallNode).getFunction().(AttrNode).getName() = "startswith" and - test.getSense() = true - } -} - -/** - * A taint sink that is vulnerable to malicious paths. - * The `vuln` in `open(vuln)` and similar. - */ -deprecated class OpenNode extends TaintSink { - override string toString() { result = "argument to open()" } - - OpenNode() { - exists(CallNode call | - call = Value::named("open").getACall() and - ( - call.getArg(0) = this - or - call.getArgByName("file") = this - ) - ) - } - - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - or - kind instanceof NormalizedPath - } -} diff --git a/python/ql/lib/semmle/python/security/injection/Pickle.qll b/python/ql/lib/semmle/python/security/injection/Pickle.qll deleted file mode 100644 index 621eccbd6ce..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Pickle.qll +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious pickles. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.injection.Deserialization - -deprecated private ModuleObject pickleModule() { - result.getName() = "pickle" - or - result.getName() = "cPickle" - or - result.getName() = "dill" -} - -deprecated private FunctionObject pickleLoads() { result = pickleModule().attr("loads") } - -/** `pickle.loads(untrusted)` vulnerability. */ -deprecated class UnpicklingNode extends DeserializationSink { - override string toString() { result = "unpickling untrusted data" } - - UnpicklingNode() { - exists(CallNode call | - pickleLoads().getACall() = call and - call.getAnArg() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/security/injection/RegexInjection.qll b/python/ql/lib/semmle/python/security/injection/RegexInjection.qll deleted file mode 100644 index c0c0f42dbd6..00000000000 --- a/python/ql/lib/semmle/python/security/injection/RegexInjection.qll +++ /dev/null @@ -1,6 +0,0 @@ -/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */ - -private import semmle.python.security.dataflow.RegexInjection as New - -/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */ -deprecated module RegexInjection = New::RegexInjection; diff --git a/python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll deleted file mode 100644 index 0738f2b58b6..00000000000 --- a/python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll +++ /dev/null @@ -1,6 +0,0 @@ -/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */ - -private import semmle.python.security.dataflow.RegexInjectionCustomizations as New - -/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */ -deprecated module RegexInjection = New::RegexInjection; diff --git a/python/ql/lib/semmle/python/security/injection/Xml.qll b/python/ql/lib/semmle/python/security/injection/Xml.qll deleted file mode 100644 index 6f61e0a5ef5..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Xml.qll +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious XML objects. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.injection.Deserialization - -deprecated private ModuleObject xmlElementTreeModule() { - result.getName() = "xml.etree.ElementTree" -} - -deprecated private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" } - -deprecated private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" } - -deprecated private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" } - -deprecated private class ExpatParser extends TaintKind { - ExpatParser() { this = "expat.parser" } -} - -deprecated private FunctionObject expatCreateParseFunction() { - result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate") -} - -deprecated private class ExpatCreateParser extends TaintSource { - ExpatCreateParser() { expatCreateParseFunction().getACall() = this } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser } - - override string toString() { result = "expat.create.parser" } -} - -deprecated private FunctionObject xmlFromString() { - result = xmlElementTreeModule().attr("fromstring") - or - result = xmlMiniDomModule().attr("parseString") - or - result = xmlPullDomModule().attr("parseString") - or - result = xmlSaxModule().attr("parseString") -} - -/** A (potentially) malicious XML string. */ -deprecated class ExternalXmlString extends ExternalStringKind { - ExternalXmlString() { this = "external xml encoded object" } -} - -/** - * A call to an XML library function that is potentially vulnerable to a - * specially crafted XML string. - */ -deprecated class XmlLoadNode extends DeserializationSink { - override string toString() { result = "xml.load vulnerability" } - - XmlLoadNode() { - exists(CallNode call | call.getAnArg() = this | - xmlFromString().getACall() = call or - any(ExpatParser parser).taints(call.getFunction().(AttrNode).getObject("Parse")) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlString } -} diff --git a/python/ql/lib/semmle/python/security/injection/Yaml.qll b/python/ql/lib/semmle/python/security/injection/Yaml.qll deleted file mode 100644 index 585552442f7..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Yaml.qll +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious yaml-encoded objects. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.injection.Deserialization - -deprecated private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") } - -/** `yaml.load(untrusted)` vulnerability. */ -deprecated class YamlLoadNode extends DeserializationSink { - override string toString() { result = "yaml.load vulnerability" } - - YamlLoadNode() { - exists(CallNode call | - yamlLoad().getACall() = call and - call.getAnArg() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/types/Extensions.qll b/python/ql/lib/semmle/python/types/Extensions.qll index 8b5b357723f..f6c824f9ab2 100644 --- a/python/ql/lib/semmle/python/types/Extensions.qll +++ b/python/ql/lib/semmle/python/types/Extensions.qll @@ -14,7 +14,6 @@ import python private import semmle.python.pointsto.PointsTo private import semmle.python.pointsto.PointsToContext private import semmle.python.objects.TObject -private import semmle.python.web.HttpConstants /* Make ObjectInternal visible to save extra imports in user code */ import semmle.python.objects.ObjectInternal @@ -52,30 +51,6 @@ class RangeIterationVariableFact extends PointsToExtension { } } -/* bottle module route constants */ -deprecated class BottleRoutePointToExtension extends PointsToExtension { - string name; - - BottleRoutePointToExtension() { - exists(DefinitionNode defn | - defn.getScope().(Module).getName() = "bottle" and - this = defn.getValue() and - name = defn.(NameNode).getId() - | - name = "route" or - name = httpVerbLower() - ) - } - - override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { - context.isImport() and - exists(CfgOrigin orig | - Module::named("bottle").attr("Bottle").(ClassObjectInternal).attribute(name, value, orig) and - origin = orig.asCfgNodeOrHere(this) - ) - } -} - /* Python 3.6+ regex module constants */ string short_flag(string flag) { flag in ["ASCII", "IGNORECASE", "LOCALE", "UNICODE", "MULTILINE", "TEMPLATE"] and diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index bdf55bfc4f2..766cf6845af 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -33,9 +33,6 @@ class SafeExternalApi extends Unit { DataFlowPrivate::DataFlowCallable getSafeCallable() { none() } } -/** DEPRECATED: Alias for SafeExternalApi */ -deprecated class SafeExternalAPI = SafeExternalApi; - /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApi extends SafeExternalApi { override DataFlow::CallCfgNode getSafeCall() { @@ -170,9 +167,6 @@ class ExternalApiDataNode extends DataFlow::Node { } } -/** DEPRECATED: Alias for ExternalApiDataNode */ -deprecated class ExternalAPIDataNode = ExternalApiDataNode; - /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" } @@ -182,9 +176,6 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } } -/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ -deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; - /** A node representing untrusted data being passed to an external API. */ class UntrustedExternalApiDataNode extends ExternalApiDataNode { UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) } @@ -195,9 +186,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode { } } -/** DEPRECATED: Alias for UntrustedExternalApiDataNode */ -deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; - /** An external API which is used with untrusted data. */ private newtype TExternalApi = MkExternalApi(string repr, DataFlowPrivate::ArgumentPosition apos) { @@ -230,6 +218,3 @@ class ExternalApiUsedWithUntrustedData extends MkExternalApi { /** Gets a textual representation of this element. */ string toString() { result = repr + " [" + apos + "]" } } - -/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ -deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index 65f1e0d8e01..3331e1117e0 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -90,9 +90,6 @@ module LdapQuery { } } -/** DEPRECATED: Alias for LdapQuery */ -deprecated module LDAPQuery = LdapQuery; - /** * A data-flow node that collect methods executing a LDAP query. * @@ -106,9 +103,6 @@ class LdapQuery extends DataFlow::Node instanceof LdapQuery::Range { DataFlow::Node getQuery() { result = super.getQuery() } } -/** DEPRECATED: Alias for LdapQuery */ -deprecated class LDAPQuery = LdapQuery; - /** Provides classes for modeling LDAP components escape-related APIs. */ module LdapEscape { /** @@ -125,9 +119,6 @@ module LdapEscape { } } -/** DEPRECATED: Alias for LdapEscape */ -deprecated module LDAPEscape = LdapEscape; - /** * A data-flow node that collects functions escaping LDAP components. * @@ -141,9 +132,6 @@ class LdapEscape extends DataFlow::Node instanceof LdapEscape::Range { DataFlow::Node getAnInput() { result = super.getAnInput() } } -/** DEPRECATED: Alias for LdapEscape */ -deprecated class LDAPEscape = LdapEscape; - /** Provides classes for modeling LDAP bind-related APIs. */ module LdapBind { /** @@ -173,9 +161,6 @@ module LdapBind { } } -/** DEPRECATED: Alias for LdapBind */ -deprecated module LDAPBind = LdapBind; - /** * A data-flow node that collects methods binding a LDAP connection. * @@ -202,9 +187,6 @@ class LdapBind extends DataFlow::Node instanceof LdapBind::Range { deprecated predicate useSSL() { this.useSsl() } } -/** DEPRECATED: Alias for LdapBind */ -deprecated class LDAPBind = LdapBind; - /** Provides classes for modeling SQL sanitization libraries. */ module SqlEscape { /** @@ -221,9 +203,6 @@ module SqlEscape { } } -/** DEPRECATED: Alias for SqlEscape */ -deprecated module SQLEscape = SqlEscape; - /** * A data-flow node that collects functions escaping SQL statements. * @@ -237,9 +216,6 @@ class SqlEscape extends DataFlow::Node instanceof SqlEscape::Range { DataFlow::Node getAnInput() { result = super.getAnInput() } } -/** DEPRECATED: Alias for SqlEscape */ -deprecated class SQLEscape = SqlEscape; - /** Provides a class for modeling NoSql execution APIs. */ module NoSqlQuery { /** @@ -254,9 +230,6 @@ module NoSqlQuery { } } -/** DEPRECATED: Alias for NoSqlQuery */ -deprecated module NoSQLQuery = NoSqlQuery; - /** * A data-flow node that executes NoSQL queries. * @@ -268,9 +241,6 @@ class NoSqlQuery extends DataFlow::Node instanceof NoSqlQuery::Range { DataFlow::Node getQuery() { result = super.getQuery() } } -/** DEPRECATED: Alias for NoSqlQuery */ -deprecated class NoSQLQuery = NoSqlQuery; - /** Provides classes for modeling NoSql sanitization-related APIs. */ module NoSqlSanitizer { /** @@ -285,9 +255,6 @@ module NoSqlSanitizer { } } -/** DEPRECATED: Alias for NoSqlSanitizer */ -deprecated module NoSQLSanitizer = NoSqlSanitizer; - /** * A data-flow node that collects functions sanitizing NoSQL queries. * @@ -299,9 +266,6 @@ class NoSqlSanitizer extends DataFlow::Node instanceof NoSqlSanitizer::Range { DataFlow::Node getAnInput() { result = super.getAnInput() } } -/** DEPRECATED: Alias for NoSqlSanitizer */ -deprecated class NoSQLSanitizer = NoSqlSanitizer; - /** Provides classes for modeling HTTP Header APIs. */ module HeaderDeclaration { /** @@ -450,9 +414,6 @@ module JwtEncoding { } } -/** DEPRECATED: Alias for JwtEncoding */ -deprecated module JWTEncoding = JwtEncoding; - /** * A data-flow node that collects methods encoding a JWT token. * @@ -481,9 +442,6 @@ class JwtEncoding extends DataFlow::Node instanceof JwtEncoding::Range { string getAlgorithmString() { result = super.getAlgorithmString() } } -/** DEPRECATED: Alias for JwtEncoding */ -deprecated class JWTEncoding = JwtEncoding; - /** Provides classes for modeling JWT decoding-related APIs. */ module JwtDecoding { /** @@ -525,9 +483,6 @@ module JwtDecoding { } } -/** DEPRECATED: Alias for JwtDecoding */ -deprecated module JWTDecoding = JwtDecoding; - /** * A data-flow node that collects methods encoding a JWT token. * @@ -566,9 +521,6 @@ class JwtDecoding extends DataFlow::Node instanceof JwtDecoding::Range { predicate verifiesSignature() { super.verifiesSignature() } } -/** DEPRECATED: Alias for JwtDecoding */ -deprecated class JWTDecoding = JwtDecoding; - /** Provides classes for modeling Email APIs. */ module EmailSender { /** diff --git a/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll b/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll index dbe1cbe4117..56fffe3a2a0 100644 --- a/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll +++ b/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll @@ -29,23 +29,14 @@ class LdapFullHost extends StrConst { } } -/** DEPRECATED: Alias for LdapFullHost */ -deprecated class LDAPFullHost = LdapFullHost; - class LdapSchema extends StrConst { LdapSchema() { this.getText().regexpMatch(getSchemaRegex()) } } -/** DEPRECATED: Alias for LdapSchema */ -deprecated class LDAPSchema = LdapSchema; - class LdapPrivateHost extends StrConst { LdapPrivateHost() { this.getText().regexpMatch(getPrivateHostRegex()) } } -/** DEPRECATED: Alias for LdapPrivateHost */ -deprecated class LDAPPrivateHost = LdapPrivateHost; - predicate concatAndCompareAgainstFullHostRegex(LdapSchema schema, StrConst host) { not host instanceof LdapPrivateHost and (schema.getText() + host.getText()).regexpMatch(getFullHostRegex()) @@ -56,9 +47,6 @@ class LdapBothStrings extends BinaryExpr { LdapBothStrings() { concatAndCompareAgainstFullHostRegex(this.getLeft(), this.getRight()) } } -/** DEPRECATED: Alias for LdapBothStrings */ -deprecated class LDAPBothStrings = LdapBothStrings; - // schema + host class LdapBothVar extends BinaryExpr { LdapBothVar() { @@ -73,9 +61,6 @@ class LdapBothVar extends BinaryExpr { } } -/** DEPRECATED: Alias for LdapBothVar */ -deprecated class LDAPBothVar = LdapBothVar; - // schema + "somethingon.theinternet.com" class LdapVarString extends BinaryExpr { LdapVarString() { @@ -89,9 +74,6 @@ class LdapVarString extends BinaryExpr { } } -/** DEPRECATED: Alias for LdapVarString */ -deprecated class LDAPVarString = LdapVarString; - // "ldap://" + host class LdapStringVar extends BinaryExpr { LdapStringVar() { @@ -103,9 +85,6 @@ class LdapStringVar extends BinaryExpr { } } -/** DEPRECATED: Alias for LdapStringVar */ -deprecated class LDAPStringVar = LdapStringVar; - /** * A taint-tracking configuration for detecting LDAP insecure authentications. */ @@ -125,6 +104,3 @@ class LdapInsecureAuthConfig extends TaintTracking::Configuration { exists(LdapBind ldapBind | not ldapBind.useSsl() and sink = ldapBind.getHost()) } } - -/** DEPRECATED: Alias for LdapInsecureAuthConfig */ -deprecated class LDAPInsecureAuthConfig = LdapInsecureAuthConfig; diff --git a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll index e6f3832e4ff..f7a40fb3ee6 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll @@ -52,6 +52,3 @@ module NoSqlInjection { ConvertedToDict() { this = "ConvertedToDict" } } } - -/** DEPRECATED: Alias for NoSqlInjection */ -deprecated module NoSQLInjection = NoSqlInjection; diff --git a/python/ql/test/library-tests/security/sensitive/Sources.expected b/python/ql/test/library-tests/security/sensitive/Sources.expected deleted file mode 100644 index 4500a2c23a5..00000000000 --- a/python/ql/test/library-tests/security/sensitive/Sources.expected +++ /dev/null @@ -1,6 +0,0 @@ -WARNING: Module SensitiveData has been deprecated and may be removed in future (Sources.ql:4,6-19) -| test.py:16:1:16:14 | test.py:16 | a call returning a password | -| test.py:17:1:17:12 | test.py:17 | a call returning a password | -| test.py:18:1:18:12 | test.py:18 | a call returning a secret | -| test.py:19:1:19:19 | test.py:19 | a call returning a certificate or key | -| test.py:20:1:20:12 | test.py:20 | a call returning an ID | diff --git a/python/ql/test/library-tests/security/sensitive/Sources.ql b/python/ql/test/library-tests/security/sensitive/Sources.ql deleted file mode 100644 index b5328a9f105..00000000000 --- a/python/ql/test/library-tests/security/sensitive/Sources.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import semmle.python.security.SensitiveData - -from SensitiveData::Source src -select src.getLocation(), src.repr() diff --git a/python/ql/test/library-tests/security/sensitive/test.py b/python/ql/test/library-tests/security/sensitive/test.py deleted file mode 100644 index bd5aaf238d8..00000000000 --- a/python/ql/test/library-tests/security/sensitive/test.py +++ /dev/null @@ -1,21 +0,0 @@ - -from not_found import get_passwd, account_id - -def get_password(): - pass - -def get_secret(): - pass - -def fetch_certificate(): - pass - -def encrypt_password(pwd): - pass - -get_password() -get_passwd() -get_secret() -fetch_certificate() -account_id() -safe_to_store = encrypt_password(pwd) diff --git a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected deleted file mode 100644 index 196468fd4c1..00000000000 --- a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.expected +++ /dev/null @@ -1,5 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:9:12:9:26 | bottle handler function result | externally controlled string | -| test.py:13:12:13:24 | bottle handler function result | externally controlled string | -| test.py:19:12:19:33 | bottle handler function result | externally controlled string | -| test.py:36:21:36:51 | Taint sink | externally controlled string | diff --git a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql b/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/bottle/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/bottle/HttpSources.expected b/python/ql/test/library-tests/web/bottle/HttpSources.expected deleted file mode 100644 index 63d149e955a..00000000000 --- a/python/ql/test/library-tests/web/bottle/HttpSources.expected +++ /dev/null @@ -1,9 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| ../../../query-tests/Security/lib/bottle.py:64:11:64:24 | LocalRequest() | bottle.request | -| test.py:3:35:3:41 | ImportMember | bottle.request | -| test.py:8:11:8:14 | name | externally controlled string | -| test.py:12:9:12:12 | name | externally controlled string | -| test.py:18:12:18:18 | request | bottle.request | -| test.py:27:12:27:16 | where | externally controlled string | -| test.py:32:14:32:20 | request | bottle.request | -| test.py:36:34:36:40 | request | bottle.request | diff --git a/python/ql/test/library-tests/web/bottle/HttpSources.ql b/python/ql/test/library-tests/web/bottle/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/bottle/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/bottle/Routing.expected b/python/ql/test/library-tests/web/bottle/Routing.expected deleted file mode 100644 index d07889879a3..00000000000 --- a/python/ql/test/library-tests/web/bottle/Routing.expected +++ /dev/null @@ -1,8 +0,0 @@ -WARNING: Type BottleRoute has been deprecated and may be removed in future (Routing.ql:4,6-17) -| /args | test.py:31:1:31:14 | Function unsafe2 | -| /bye/<name> | test.py:12:1:12:25 | Function bye | -| /hello/<name> | test.py:8:1:8:27 | Function hello | -| /other | test.py:17:1:17:12 | Function other | -| /wrong/<where> | test.py:27:1:27:31 | Function unsafe | -| /wrong/url | test.py:23:1:23:11 | Function safe | -| /xss | test.py:35:1:35:16 | Function maybe_xss | diff --git a/python/ql/test/library-tests/web/bottle/Routing.ql b/python/ql/test/library-tests/web/bottle/Routing.ql deleted file mode 100644 index 988b8398f04..00000000000 --- a/python/ql/test/library-tests/web/bottle/Routing.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import semmle.python.web.bottle.General - -from BottleRoute route -select route.getUrl(), route.getFunction() diff --git a/python/ql/test/library-tests/web/bottle/Taint.expected b/python/ql/test/library-tests/web/bottle/Taint.expected deleted file mode 100644 index 451b1ee3e00..00000000000 --- a/python/ql/test/library-tests/web/bottle/Taint.expected +++ /dev/null @@ -1,23 +0,0 @@ -| ../../../query-tests/Security/lib/bottle.py:64 | LocalRequest() | bottle.request | -| ../../../query-tests/Security/lib/bottle.py:68 | url | externally controlled string | -| test.py:3 | ImportMember | bottle.request | -| test.py:8 | name | externally controlled string | -| test.py:9 | BinaryExpr | externally controlled string | -| test.py:9 | name | externally controlled string | -| test.py:12 | name | externally controlled string | -| test.py:13 | BinaryExpr | externally controlled string | -| test.py:13 | name | externally controlled string | -| test.py:18 | Attribute | bottle.FormsDict | -| test.py:18 | Attribute | externally controlled string | -| test.py:18 | request | bottle.request | -| test.py:19 | BinaryExpr | externally controlled string | -| test.py:19 | name | externally controlled string | -| test.py:27 | where | externally controlled string | -| test.py:28 | where | externally controlled string | -| test.py:32 | Attribute | bottle.FormsDict | -| test.py:32 | Attribute | externally controlled string | -| test.py:32 | request | bottle.request | -| test.py:36 | Attribute | bottle.FormsDict | -| test.py:36 | Attribute | externally controlled string | -| test.py:36 | BinaryExpr | externally controlled string | -| test.py:36 | request | bottle.request | diff --git a/python/ql/test/library-tests/web/bottle/Taint.ql b/python/ql/test/library-tests/web/bottle/Taint.ql deleted file mode 100644 index 09972af5f98..00000000000 --- a/python/ql/test/library-tests/web/bottle/Taint.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/bottle/options b/python/ql/test/library-tests/web/bottle/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/library-tests/web/bottle/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/bottle/test.py b/python/ql/test/library-tests/web/bottle/test.py deleted file mode 100644 index 8975de72ea4..00000000000 --- a/python/ql/test/library-tests/web/bottle/test.py +++ /dev/null @@ -1,36 +0,0 @@ - - -from bottle import Bottle, route, request, redirect, response - -app = Bottle() - -@app.route('/hello/<name>') -def hello(name = "World!"): - return "Hello " + name - -@route('/bye/<name>') -def bye(name = "World!"): - return "Bye " + name - - -@route('/other') -def other(): - name = request.cookies.username - return "User name is " + name - - -@route('/wrong/url') -def safe(): - redirect("/right/url") - -@route('/wrong/<where>') -def unsafe(where="/right/url"): - redirect(where) - -@route('/args') -def unsafe2(): - redirect(request.query.where, code) - -@route('/xss') -def maybe_xss(): - response.body = "name is " + request.query.name diff --git a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected deleted file mode 100644 index d45cfd65989..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| red.py:8:16:8:20 | cherrypy handler function result | externally controlled string | -| test.py:11:16:11:29 | cherrypy handler function result | externally controlled string | -| test.py:17:16:17:27 | cherrypy handler function result | externally controlled string | diff --git a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql b/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/cherrypy/HttpSources.expected b/python/ql/test/library-tests/web/cherrypy/HttpSources.expected deleted file mode 100644 index e0d1d7c4e59..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/HttpSources.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| ../../../query-tests/Security/lib/cherrypy/__init__.py:10:11:10:38 | _ThreadLocalProxy() | cherrypy.request | -| test.py:10:17:10:19 | arg | externally controlled string | -| test.py:16:17:16:19 | arg | externally controlled string | diff --git a/python/ql/test/library-tests/web/cherrypy/HttpSources.ql b/python/ql/test/library-tests/web/cherrypy/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/cherrypy/options b/python/ql/test/library-tests/web/cherrypy/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/cherrypy/red.py b/python/ql/test/library-tests/web/cherrypy/red.py deleted file mode 100644 index 5fa25b5aa0f..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/red.py +++ /dev/null @@ -1,11 +0,0 @@ - -import cherrypy - -class MultiPath(object): - - @cherrypy.expose(['color', 'colour']) - def red(self): - return "RED" - -if __name__ == '__main__': - cherrypy.quickstart(MultiPath()) diff --git a/python/ql/test/library-tests/web/cherrypy/test.py b/python/ql/test/library-tests/web/cherrypy/test.py deleted file mode 100644 index 5d44b54077b..00000000000 --- a/python/ql/test/library-tests/web/cherrypy/test.py +++ /dev/null @@ -1,23 +0,0 @@ - -import random -import string - -import cherrypy - -class A(object): - - @cherrypy.expose - def a(self, arg): - return "hello " + arg - -class B(object): - - @cherrypy.expose - def b(self, arg): - return "bye " + arg - -cherrypy.tree.mount(A(), '/a', a_conf) -cherrypy.tree.mount(B(), '/b', b_conf) - -cherrypy.engine.start() -cherrypy.engine.block() \ No newline at end of file diff --git a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected deleted file mode 100644 index fa93ffe7e88..00000000000 --- a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.expected +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: Module Client has been deprecated and may be removed in future (ClientHttpRequests.ql:5,6-12) -| test.py:3:1:3:27 | ControlFlowNode for Attribute() | test.py:3:14:3:26 | ControlFlowNode for Str | GET | -| test.py:4:1:4:28 | ControlFlowNode for Attribute() | test.py:4:15:4:27 | ControlFlowNode for Str | POST | diff --git a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql deleted file mode 100644 index 52fd7ff218e..00000000000 --- a/python/ql/test/library-tests/web/client/requests/ClientHttpRequests.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.Http -import semmle.python.web.ClientHttpRequest - -from Client::HttpRequest req, string method -where if exists(req.getMethodUpper()) then method = req.getMethodUpper() else method = "<NO METHOD>" -select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/requests/options b/python/ql/test/library-tests/web/client/requests/options deleted file mode 100644 index f1858a6caf9..00000000000 --- a/python/ql/test/library-tests/web/client/requests/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../../../query-tests/Security/lib/ --max-import-depth=1 diff --git a/python/ql/test/library-tests/web/client/requests/test.py b/python/ql/test/library-tests/web/client/requests/test.py deleted file mode 100644 index 1cb5e47e166..00000000000 --- a/python/ql/test/library-tests/web/client/requests/test.py +++ /dev/null @@ -1,4 +0,0 @@ -import requests - -requests.get('example.com') -requests.post('example.com') diff --git a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected deleted file mode 100644 index 40400cce819..00000000000 --- a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.expected +++ /dev/null @@ -1,11 +0,0 @@ -WARNING: Module Client has been deprecated and may be removed in future (ClientHttpRequests.ql:5,6-12) -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:5:27:5:39 | ControlFlowNode for Str | GET | -| test.py:6:5:6:32 | ControlFlowNode for Attribute() | test.py:6:25:6:31 | ControlFlowNode for Str | GET | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:10:28:10:40 | ControlFlowNode for Str | POST | -| test.py:15:5:15:33 | ControlFlowNode for Attribute() | test.py:15:26:15:32 | ControlFlowNode for Str | POST | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:19:27:19:39 | ControlFlowNode for Str | <NO METHOD> | -| test.py:20:5:20:33 | ControlFlowNode for Attribute() | test.py:20:26:20:32 | ControlFlowNode for Str | <NO METHOD> | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:28:27:28:30 | ControlFlowNode for fake | GET | -| test.py:30:5:30:32 | ControlFlowNode for Attribute() | test.py:30:25:30:31 | ControlFlowNode for Str | GET | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:35:27:35:39 | ControlFlowNode for Str | HEAD | -| test.py:37:5:37:29 | ControlFlowNode for req_meth() | test.py:37:22:37:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql deleted file mode 100644 index 52fd7ff218e..00000000000 --- a/python/ql/test/library-tests/web/client/six/ClientHttpRequests.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.Http -import semmle.python.web.ClientHttpRequest - -from Client::HttpRequest req, string method -where if exists(req.getMethodUpper()) then method = req.getMethodUpper() else method = "<NO METHOD>" -select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/six/options b/python/ql/test/library-tests/web/client/six/options deleted file mode 100644 index 1f95e64d742..00000000000 --- a/python/ql/test/library-tests/web/client/six/options +++ /dev/null @@ -1,2 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -optimize: true diff --git a/python/ql/test/library-tests/web/client/six/test.py b/python/ql/test/library-tests/web/client/six/test.py deleted file mode 100644 index cdd79021d87..00000000000 --- a/python/ql/test/library-tests/web/client/six/test.py +++ /dev/null @@ -1,37 +0,0 @@ -from six.moves.http_client import HTTPConnection, HTTPSConnection - - -def basic(): - conn = HTTPConnection('example.com') - conn.request('GET', '/path') - - -def indirect_caller(): - conn = HTTPSConnection('example.com') - indirect_callee(conn) - - -def indirect_callee(conn): - conn.request('POST', '/path') - - -def method_not_known(method): - conn = HTTPConnection('example.com') - conn.request(method, '/path') - - -def sneaky_setting_host(): - # We don't handle that the host is overwritten directly. - # A contrived example; you're not supposed to do this, but you certainly can. - fake = 'fakehost.com' - real = 'realhost.com' - conn = HTTPConnection(fake) - conn.host = real - conn.request('GET', '/path') - - -def tricky_not_attribute_node(): - # A contrived example; you're not supposed to do this, but you certainly can. - conn = HTTPConnection('example.com') - req_meth = conn.request - req_meth('HEAD', '/path') diff --git a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected deleted file mode 100644 index 73540db65e6..00000000000 --- a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.expected +++ /dev/null @@ -1,11 +0,0 @@ -WARNING: Module Client has been deprecated and may be removed in future (ClientHttpRequests.ql:5,6-12) -| test.py:13:5:13:32 | ControlFlowNode for Attribute() | test.py:12:27:12:39 | ControlFlowNode for Str | GET | -| test.py:13:5:13:32 | ControlFlowNode for Attribute() | test.py:13:25:13:31 | ControlFlowNode for Str | GET | -| test.py:22:5:22:33 | ControlFlowNode for Attribute() | test.py:17:28:17:40 | ControlFlowNode for Str | POST | -| test.py:22:5:22:33 | ControlFlowNode for Attribute() | test.py:22:26:22:32 | ControlFlowNode for Str | POST | -| test.py:27:5:27:33 | ControlFlowNode for Attribute() | test.py:26:27:26:39 | ControlFlowNode for Str | <NO METHOD> | -| test.py:27:5:27:33 | ControlFlowNode for Attribute() | test.py:27:26:27:32 | ControlFlowNode for Str | <NO METHOD> | -| test.py:37:5:37:32 | ControlFlowNode for Attribute() | test.py:35:27:35:30 | ControlFlowNode for fake | GET | -| test.py:37:5:37:32 | ControlFlowNode for Attribute() | test.py:37:25:37:31 | ControlFlowNode for Str | GET | -| test.py:44:5:44:29 | ControlFlowNode for req_meth() | test.py:42:27:42:39 | ControlFlowNode for Str | HEAD | -| test.py:44:5:44:29 | ControlFlowNode for req_meth() | test.py:44:22:44:28 | ControlFlowNode for Str | HEAD | diff --git a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql b/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql deleted file mode 100644 index 52fd7ff218e..00000000000 --- a/python/ql/test/library-tests/web/client/stdlib/ClientHttpRequests.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.Http -import semmle.python.web.ClientHttpRequest - -from Client::HttpRequest req, string method -where if exists(req.getMethodUpper()) then method = req.getMethodUpper() else method = "<NO METHOD>" -select req, req.getAUrlPart(), method diff --git a/python/ql/test/library-tests/web/client/stdlib/options b/python/ql/test/library-tests/web/client/stdlib/options deleted file mode 100644 index eb214fc2931..00000000000 --- a/python/ql/test/library-tests/web/client/stdlib/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=1 diff --git a/python/ql/test/library-tests/web/client/stdlib/test.py b/python/ql/test/library-tests/web/client/stdlib/test.py deleted file mode 100644 index 179f9b30858..00000000000 --- a/python/ql/test/library-tests/web/client/stdlib/test.py +++ /dev/null @@ -1,44 +0,0 @@ -import sys -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -if PY2: - from httplib import HTTPConnection, HTTPSConnection -if PY3: - from http.client import HTTPConnection, HTTPSConnection - - -def basic(): - conn = HTTPConnection('example.com') - conn.request('GET', '/path') - - -def indirect_caller(): - conn = HTTPSConnection('example.com') - indirect_callee(conn) - - -def indirect_callee(conn): - conn.request('POST', '/path') - - -def method_not_known(method): - conn = HTTPConnection('example.com') - conn.request(method, '/path') - - -def sneaky_setting_host(): - # We don't handle that the host is overwritten directly. - # A contrived example; you're not supposed to do this, but you certainly can. - fake = 'fakehost.com' - real = 'realhost.com' - conn = HTTPConnection(fake) - conn.host = real - conn.request('GET', '/path') - - -def tricky_not_attribute_node(): - # A contrived example; you're not supposed to do this, but you certainly can. - conn = HTTPConnection('example.com') - req_meth = conn.request - req_meth('HEAD', '/path') diff --git a/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected b/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected deleted file mode 100644 index 6753f22d31f..00000000000 --- a/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected +++ /dev/null @@ -1,5 +0,0 @@ -WARNING: Type HttpRedirectTaintSink has been deprecated and may be removed in future (HttpRedirectSinks.ql:5,6-27) -| test_1x.py:13:21:13:24 | DjangoShortcutsRedirectSink | externally controlled string | -| test_2x_3x.py:13:21:13:24 | DjangoShortcutsRedirectSink | externally controlled string | -| views_1x.py:99:33:99:55 | DjangoRedirectResponseSink | externally controlled string | -| views_2x_3x.py:120:33:120:55 | DjangoRedirectResponseSink | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/HttpRedirectSinks.ql b/python/ql/test/library-tests/web/django/HttpRedirectSinks.ql deleted file mode 100644 index 157ef2d4430..00000000000 --- a/python/ql/test/library-tests/web/django/HttpRedirectSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRedirect -import semmle.python.security.strings.Untrusted - -from HttpRedirectTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected deleted file mode 100644 index 2f620ac508f..00000000000 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected +++ /dev/null @@ -1,32 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| views_1x.py:8:25:8:63 | django.Response(...) | externally controlled string | -| views_1x.py:12:25:12:52 | django.Response(...) | externally controlled string | -| views_1x.py:16:25:16:53 | django.Response(...) | externally controlled string | -| views_1x.py:21:15:21:42 | django.Response.write(...) | externally controlled string | -| views_1x.py:30:29:30:60 | django.Response(...) | externally controlled string | -| views_1x.py:36:29:36:65 | django.Response(...) | externally controlled string | -| views_1x.py:41:25:41:63 | django.Response(...) | externally controlled string | -| views_1x.py:45:25:45:70 | django.Response(...) | externally controlled string | -| views_1x.py:66:25:66:55 | django.Response(...) | externally controlled string | -| views_1x.py:75:25:75:33 | django.Response(...) | externally controlled string | -| views_1x.py:90:25:90:33 | django.Response(...) | externally controlled string | -| views_1x.py:94:25:94:58 | django.Response(...) | externally controlled string | -| views_1x.py:103:33:103:55 | django.Response(...) | externally controlled string | -| views_1x.py:107:25:107:47 | django.Response(...) | externally controlled string | -| views_2x_3x.py:8:25:8:63 | django.Response(...) | externally controlled string | -| views_2x_3x.py:12:25:12:52 | django.Response(...) | externally controlled string | -| views_2x_3x.py:16:25:16:53 | django.Response(...) | externally controlled string | -| views_2x_3x.py:21:15:21:42 | django.Response.write(...) | externally controlled string | -| views_2x_3x.py:30:29:30:60 | django.Response(...) | externally controlled string | -| views_2x_3x.py:36:29:36:65 | django.Response(...) | externally controlled string | -| views_2x_3x.py:41:25:41:63 | django.Response(...) | externally controlled string | -| views_2x_3x.py:45:25:45:70 | django.Response(...) | externally controlled string | -| views_2x_3x.py:66:25:66:40 | django.Response(...) | externally controlled string | -| views_2x_3x.py:79:25:79:61 | django.Response(...) | externally controlled string | -| views_2x_3x.py:82:25:82:69 | django.Response(...) | externally controlled string | -| views_2x_3x.py:85:25:85:64 | django.Response(...) | externally controlled string | -| views_2x_3x.py:88:25:88:32 | django.Response(...) | externally controlled string | -| views_2x_3x.py:111:25:111:33 | django.Response(...) | externally controlled string | -| views_2x_3x.py:115:25:115:58 | django.Response(...) | externally controlled string | -| views_2x_3x.py:124:33:124:55 | django.Response(...) | externally controlled string | -| views_2x_3x.py:128:25:128:47 | django.Response(...) | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.ql b/python/ql/test/library-tests/web/django/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/django/HttpSources.expected b/python/ql/test/library-tests/web/django/HttpSources.expected deleted file mode 100644 index 2aa9c979334..00000000000 --- a/python/ql/test/library-tests/web/django/HttpSources.expected +++ /dev/null @@ -1,53 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test_1x.py:6:19:6:25 | request | django.request.HttpRequest | -| test_1x.py:6:28:6:31 | path | externally controlled string | -| test_1x.py:12:19:12:25 | request | django.request.HttpRequest | -| test_1x.py:12:28:12:31 | path | externally controlled string | -| test_2x_3x.py:6:19:6:25 | request | django.request.HttpRequest | -| test_2x_3x.py:6:28:6:31 | path | externally controlled string | -| test_2x_3x.py:12:19:12:25 | request | django.request.HttpRequest | -| test_2x_3x.py:12:28:12:31 | path | externally controlled string | -| views_1x.py:7:19:7:25 | request | django.request.HttpRequest | -| views_1x.py:7:28:7:30 | foo | externally controlled string | -| views_1x.py:7:33:7:35 | bar | externally controlled string | -| views_1x.py:11:20:11:26 | request | django.request.HttpRequest | -| views_1x.py:15:21:15:27 | request | django.request.HttpRequest | -| views_1x.py:19:21:19:27 | request | django.request.HttpRequest | -| views_1x.py:29:20:29:26 | request | django.request.HttpRequest | -| views_1x.py:29:29:29:37 | untrusted | externally controlled string | -| views_1x.py:35:19:35:25 | request | django.request.HttpRequest | -| views_1x.py:35:28:35:36 | untrusted | externally controlled string | -| views_1x.py:39:19:39:25 | request | django.request.HttpRequest | -| views_1x.py:39:28:39:38 | page_number | externally controlled string | -| views_1x.py:44:24:44:30 | request | django.request.HttpRequest | -| views_1x.py:44:33:44:36 | arg0 | externally controlled string | -| views_1x.py:44:39:44:42 | arg1 | externally controlled string | -| views_1x.py:65:15:65:21 | request | django.request.HttpRequest | -| views_1x.py:65:24:65:31 | username | externally controlled string | -| views_1x.py:74:13:74:19 | request | django.request.HttpRequest | -| views_2x_3x.py:7:19:7:25 | request | django.request.HttpRequest | -| views_2x_3x.py:7:28:7:30 | foo | externally controlled string | -| views_2x_3x.py:7:33:7:35 | bar | externally controlled string | -| views_2x_3x.py:11:20:11:26 | request | django.request.HttpRequest | -| views_2x_3x.py:15:21:15:27 | request | django.request.HttpRequest | -| views_2x_3x.py:19:21:19:27 | request | django.request.HttpRequest | -| views_2x_3x.py:29:20:29:26 | request | django.request.HttpRequest | -| views_2x_3x.py:29:29:29:37 | untrusted | externally controlled string | -| views_2x_3x.py:35:19:35:25 | request | django.request.HttpRequest | -| views_2x_3x.py:35:28:35:36 | untrusted | externally controlled string | -| views_2x_3x.py:39:19:39:25 | request | django.request.HttpRequest | -| views_2x_3x.py:39:28:39:38 | page_number | externally controlled string | -| views_2x_3x.py:44:24:44:30 | request | django.request.HttpRequest | -| views_2x_3x.py:44:33:44:36 | arg0 | externally controlled string | -| views_2x_3x.py:44:39:44:42 | arg1 | externally controlled string | -| views_2x_3x.py:65:20:65:26 | request | django.request.HttpRequest | -| views_2x_3x.py:78:17:78:23 | request | django.request.HttpRequest | -| views_2x_3x.py:78:26:78:36 | page_number | externally controlled string | -| views_2x_3x.py:81:17:81:23 | request | django.request.HttpRequest | -| views_2x_3x.py:81:26:81:28 | foo | externally controlled string | -| views_2x_3x.py:81:31:81:33 | bar | externally controlled string | -| views_2x_3x.py:81:36:81:38 | baz | externally controlled string | -| views_2x_3x.py:84:17:84:23 | request | django.request.HttpRequest | -| views_2x_3x.py:84:26:84:28 | foo | externally controlled string | -| views_2x_3x.py:84:31:84:33 | bar | externally controlled string | -| views_2x_3x.py:87:26:87:32 | request | django.request.HttpRequest | diff --git a/python/ql/test/library-tests/web/django/HttpSources.ql b/python/ql/test/library-tests/web/django/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/django/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected b/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected deleted file mode 100644 index d9850f2f7c6..00000000000 --- a/python/ql/test/library-tests/web/django/SqlInjectionSinks.expected +++ /dev/null @@ -1,9 +0,0 @@ -| sql.py:13:24:13:64 | db.connection.execute | externally controlled string | -| sql.py:14:26:14:66 | django.models.QuerySet.raw(sink,...) | externally controlled string | -| sql.py:17:24:17:77 | db.connection.execute | externally controlled string | -| sql.py:20:38:20:95 | django.db.models.expressions.RawSQL(sink,...) | externally controlled string | -| sql.py:21:26:21:83 | django.models.QuerySet.raw(sink,...) | externally controlled string | -| sql.py:22:28:22:85 | django.models.QuerySet.extra(sink,...) | externally controlled string | -| sql.py:36:26:36:68 | django.models.QuerySet.raw(sink,...) | externally controlled string | -| sql.py:42:11:42:52 | django.models.QuerySet.raw(sink,...) | externally controlled string | -| sql.py:47:13:47:54 | django.models.QuerySet.extra(sink,...) | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql b/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql deleted file mode 100644 index b12dd8ea041..00000000000 --- a/python/ql/test/library-tests/web/django/SqlInjectionSinks.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.security.injection.Sql -import semmle.python.web.django.Db -import semmle.python.web.django.Model - -from SqlInjectionSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/django/options b/python/ql/test/library-tests/web/django/options deleted file mode 100644 index a87f995c396..00000000000 --- a/python/ql/test/library-tests/web/django/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/django/sql.py b/python/ql/test/library-tests/web/django/sql.py deleted file mode 100644 index 7809c24edc1..00000000000 --- a/python/ql/test/library-tests/web/django/sql.py +++ /dev/null @@ -1,53 +0,0 @@ -from django.db import connection, models -from django.db.models.expressions import RawSQL - - -class User(models.Model): - username = models.CharField(max_length=100) - description = models.TextField(blank=True) - - -def show_user(username): - with connection.cursor() as cursor: - # GOOD -- Using parameters - cursor.execute("SELECT * FROM users WHERE username = %s", username) - User.objects.raw("SELECT * FROM users WHERE username = %s", (username,)) - - # BAD -- Using string formatting - cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) - - # BAD -- other ways of executing raw SQL code with string interpolation - User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) - User.objects.raw("insert into names_file ('name') values ('%s')" % username) - User.objects.extra("insert into names_file ('name') values ('%s')" % username) - - # BAD (but currently no custom query to find this) - # - # It is exposed to SQL injection (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra) - # For example, using name = "; DROP ALL TABLES -- " - # will result in SQL: SELECT * FROM name WHERE name = ''; DROP ALL TABLES -- '' - # - # This shouldn't be very widespread, since using a normal string will result in invalid SQL - # Using name = "example", will result in SQL: SELECT * FROM name WHERE name = ''example'' - # which in MySQL will give a syntax error - # - # When testing this out locally, none of the queries worked against SQLite3, but I could use - # the SQL injection against MySQL. - User.objects.raw("SELECT * FROM users WHERE username = '%s'", (username,)) - - -def raw3(arg): - m = User.objects.filter('foo') - m = m.filter('bar') - m.raw("select foo from bar where baz = %s" % arg) - - -def raw4(arg): - m = User.objects.filter('foo') - m.extra("select foo from bar where baz = %s" % arg) - - -def update_user(key, description1): - # Neither of these are exposed to sql-injections - user = User.objects.get(pk=key) - item.description = description diff --git a/python/ql/test/library-tests/web/django/test_1x.py b/python/ql/test/library-tests/web/django/test_1x.py deleted file mode 100644 index ce15a5e71bf..00000000000 --- a/python/ql/test/library-tests/web/django/test_1x.py +++ /dev/null @@ -1,19 +0,0 @@ -"""tests for Django 1.x""" -from django.conf.urls import url -from django.shortcuts import redirect, render - - -def with_template(request, path='default'): - env = {'path': path} - # We would need to understand django templates to know if this is safe or not - return render(request, 'possibly-vulnerable-template.html', env) - - -def vuln_redirect(request, path): - return redirect(path) - - -urlpatterns = [ - url(r'^(?P<path>.*)$', with_template), - url(r'^redirect/(?P<path>.*)$', vuln_redirect), -] diff --git a/python/ql/test/library-tests/web/django/test_2x_3x.py b/python/ql/test/library-tests/web/django/test_2x_3x.py deleted file mode 100644 index da08a80c27c..00000000000 --- a/python/ql/test/library-tests/web/django/test_2x_3x.py +++ /dev/null @@ -1,19 +0,0 @@ -"""tests for Django 2.x and 3.x""" -from django.urls import path -from django.shortcuts import redirect, render - - -def with_template(request, path='default'): - env = {'path': path} - # We would need to understand django templates to know if this is safe or not - return render(request, 'possibly-vulnerable-template.html', env) - - -def vuln_redirect(request, path): - return redirect(path) - - -urlpatterns = [ - path('/<path>', with_template), - path('/redirect/<path>', vuln_redirect), -] diff --git a/python/ql/test/library-tests/web/django/views_1x.py b/python/ql/test/library-tests/web/django/views_1x.py deleted file mode 100644 index f5476a13cef..00000000000 --- a/python/ql/test/library-tests/web/django/views_1x.py +++ /dev/null @@ -1,107 +0,0 @@ -"""test of views for Django 1.x""" -from django.conf.urls import patterns, url -from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound -from django.views.generic import View - - -def url_match_xss(request, foo, bar, no_taint=None): - return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) - - -def get_params_xss(request): - return HttpResponse(request.GET.get("untrusted")) - - -def post_params_xss(request): - return HttpResponse(request.POST.get("untrusted")) - - -def http_resp_write(request): - rsp = HttpResponse() - rsp.write(request.GET.get("untrusted")) - return rsp - - -class Foo(object): - # Note: since Foo is used as the super type in a class view, it will be able to handle requests. - - - def post(self, request, untrusted): - return HttpResponse('Foo post: {}'.format(untrusted)) - - -class ClassView(View, Foo): - - def get(self, request, untrusted): - return HttpResponse('ClassView get: {}'.format(untrusted)) - - -def show_articles(request, page_number=1): - page_number = int(page_number) - return HttpResponse('articles page: {}'.format(page_number)) - - -def xxs_positional_arg(request, arg0, arg1, no_taint=None): - return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) - - -urlpatterns = [ - url(r'^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)$', url_match_xss), - url(r'^get_params$', get_params_xss), - url(r'^post_params$', post_params_xss), - url(r'^http_resp_write$', http_resp_write), - url(r'^class_view/(?P<untrusted>.+)$', ClassView.as_view()), - - # one pattern to support `articles/page-<n>` and ensuring that articles/ goes to page-1 - url(r'articles/^(?:page-(?P<page_number>\d+)/)?$', show_articles), - # passing as positional argument is not the recommended way of doing things, but it is certainly - # possible - url(r'^([^/]+)/(?:foo|bar)/([^/]+)$', xxs_positional_arg, name='xxs_positional_arg'), -] - -################################################################################ -# Using patterns() for routing - -def show_user(request, username): - return HttpResponse('show_user {}'.format(username)) - - -urlpatterns = patterns(url(r'^users/(?P<username>[^/]+)$', show_user)) - -################################################################################ -# Show we understand the keyword arguments to django.conf.urls.url - -def kw_args(request): - return HttpResponse('kw_args') - -urlpatterns = [ - url(view=kw_args, regex=r'^kw_args$') -] - -# Not an XSS sink, since the Content-Type is not "text/html" -# FP reported in https://github.com/github/codeql-python-team/issues/38 -def fp_json_response(request): - # implicitly sets Content-Type to "application/json" - return JsonResponse({"foo": request.GET.get("foo")}) - -# Not an XSS sink, since the Content-Type is not "text/html" -def fp_manual_json_response(request): - json_data = '{"json": "{}"}'.format(request.GET.get("foo")) - return HttpResponse(json_data, content_type="application/json") - -# Not an XSS sink, since the Content-Type is not "text/html" -def fp_manual_content_type(reuqest): - return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") - -# XSS FP reported in https://github.com/github/codeql/issues/3466 -# Note: This should be a open-redirect sink, but not a XSS sink. -def fp_redirect(request): - return HttpResponseRedirect(request.GET.get("next")) - -# Ensure that simple subclasses are still vuln to XSS -def tp_not_found(request): - return HttpResponseNotFound(request.GET.get("name")) - -# Ensure we still have a XSS sink when manually setting the content_type to HTML -def tp_manual_response_type(request): - return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") diff --git a/python/ql/test/library-tests/web/django/views_2x_3x.py b/python/ql/test/library-tests/web/django/views_2x_3x.py deleted file mode 100644 index d61792004e9..00000000000 --- a/python/ql/test/library-tests/web/django/views_2x_3x.py +++ /dev/null @@ -1,128 +0,0 @@ -"""testing views for Django 2.x and 3.x""" -from django.urls import path, re_path -from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound -from django.views import View - - -def url_match_xss(request, foo, bar, no_taint=None): - return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) - - -def get_params_xss(request): - return HttpResponse(request.GET.get("untrusted")) - - -def post_params_xss(request): - return HttpResponse(request.POST.get("untrusted")) - - -def http_resp_write(request): - rsp = HttpResponse() - rsp.write(request.GET.get("untrusted")) - return rsp - - -class Foo(object): - # Note: since Foo is used as the super type in a class view, it will be able to handle requests. - - - def post(self, request, untrusted): - return HttpResponse('Foo post: {}'.format(untrusted)) - - -class ClassView(View, Foo): - - def get(self, request, untrusted): - return HttpResponse('ClassView get: {}'.format(untrusted)) - - -def show_articles(request, page_number=1): - page_number = int(page_number) - return HttpResponse('articles page: {}'.format(page_number)) - - -def xxs_positional_arg(request, arg0, arg1, no_taint=None): - return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) - - -urlpatterns = [ - re_path(r'^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)$', url_match_xss), - re_path(r'^get_params$', get_params_xss), - re_path(r'^post_params$', post_params_xss), - re_path(r'^http_resp_write$', http_resp_write), - re_path(r'^class_view/(?P<untrusted>.+)$', ClassView.as_view()), - - # one pattern to support `articles/page-<n>` and ensuring that articles/ goes to page-1 - re_path(r'articles/^(?:page-(?P<page_number>\d+)/)?$', show_articles), - # passing as positional argument is not the recommended way of doing things, but it is certainly - # possible - re_path(r'^([^/]+)/(?:foo|bar)/([^/]+)$', xxs_positional_arg, name='xxs_positional_arg'), -] - - -# Show we understand the keyword arguments to from django.urls.re_path - -def re_path_kwargs(request): - return HttpResponse('re_path_kwargs') - - -urlpatterns = [ - re_path(view=re_path_kwargs, route=r'^specifying-as-kwargs-is-not-a-problem$') -] - -################################################################################ -# Using path -################################################################################ - -# saying page_number is an externally controlled *string* is a bit strange, when we have an int converter :O -def page_number(request, page_number=1): - return HttpResponse('page_number: {}'.format(page_number)) - -def foo_bar_baz(request, foo, bar, baz): - return HttpResponse('foo_bar_baz: {} {} {}'.format(foo, bar, baz)) - -def path_kwargs(request, foo, bar): - return HttpResponse('path_kwargs: {} {} {}'.format(foo, bar)) - -def not_valid_identifier(request): - return HttpResponse('<foo!>') - -urlpatterns = [ - path('articles/', page_number), - path('articles/page-<int:page_number>', page_number), - path('<int:foo>/<str:bar>/<baz>', foo_bar_baz, name='foo-bar-baz'), - - path(view=path_kwargs, route='<foo>/<bar>'), - - # We should not report there is a request parameter called `not_valid!` - path('not_valid/<not_valid!>', not_valid_identifier), -] - - -# Not an XSS sink, since the Content-Type is not "text/html" -# FP reported in https://github.com/github/codeql-python-team/issues/38 -def fp_json_response(request): - # implicitly sets Content-Type to "application/json" - return JsonResponse({"foo": request.GET.get("foo")}) - -# Not an XSS sink, since the Content-Type is not "text/html" -def fp_manual_json_response(request): - json_data = '{"json": "{}"}'.format(request.GET.get("foo")) - return HttpResponse(json_data, content_type="application/json") - -# Not an XSS sink, since the Content-Type is not "text/html" -def fp_manual_content_type(reuqest): - return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") - -# XSS FP reported in https://github.com/github/codeql/issues/3466 -# Note: This should be a open-redirect sink, but not a XSS sink. -def fp_redirect(request): - return HttpResponseRedirect(request.GET.get("next")) - -# Ensure that simple subclasses are still vuln to XSS -def tp_not_found(request): - return HttpResponseNotFound(request.GET.get("name")) - -# Ensure we still have a XSS sink when manually setting the content_type to HTML -def tp_manual_response_type(request): - return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") diff --git a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected deleted file mode 100644 index 76fe8773866..00000000000 --- a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.expected +++ /dev/null @@ -1 +0,0 @@ -| FIXME: temporarily disabled since it's not working | diff --git a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql b/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql deleted file mode 100644 index eec9b1ef3cf..00000000000 --- a/python/ql/test/library-tests/web/falcon/HttpResponseSinks.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -// from HttpResponseTaintSink sink, TaintKind kind -// where sink.sinks(kind) -// select sink, kind -select "FIXME: temporarily disabled since it's not working" diff --git a/python/ql/test/library-tests/web/falcon/HttpSources.expected b/python/ql/test/library-tests/web/falcon/HttpSources.expected deleted file mode 100644 index 3cc29f418ab..00000000000 --- a/python/ql/test/library-tests/web/falcon/HttpSources.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:9:22:9:24 | req | falcon.request | -| test.py:19:23:19:25 | req | falcon.request | -| test.py:22:25:22:27 | req | falcon.request | diff --git a/python/ql/test/library-tests/web/falcon/HttpSources.ql b/python/ql/test/library-tests/web/falcon/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/falcon/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/falcon/Routing.expected b/python/ql/test/library-tests/web/falcon/Routing.expected deleted file mode 100644 index 47bcb473273..00000000000 --- a/python/ql/test/library-tests/web/falcon/Routing.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type FalconRoute has been deprecated and may be removed in future (Routing.ql:4,6-17) -| /hello | delete | test.py:22:5:22:35 | Function on_delete | -| /hello | get | test.py:9:5:9:32 | Function on_get | -| /hello | post | test.py:19:5:19:33 | Function on_post | diff --git a/python/ql/test/library-tests/web/falcon/Routing.ql b/python/ql/test/library-tests/web/falcon/Routing.ql deleted file mode 100644 index fde6c933b65..00000000000 --- a/python/ql/test/library-tests/web/falcon/Routing.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import semmle.python.web.falcon.General - -from FalconRoute route, string method -select route.getUrl(), method, route.getHandlerFunction(method) diff --git a/python/ql/test/library-tests/web/falcon/Sinks.expected b/python/ql/test/library-tests/web/falcon/Sinks.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/library-tests/web/falcon/Sinks.ql b/python/ql/test/library-tests/web/falcon/Sinks.ql deleted file mode 100644 index efaafe17f02..00000000000 --- a/python/ql/test/library-tests/web/falcon/Sinks.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind diff --git a/python/ql/test/library-tests/web/falcon/Taint.expected b/python/ql/test/library-tests/web/falcon/Taint.expected deleted file mode 100644 index f1e7abb4f0d..00000000000 --- a/python/ql/test/library-tests/web/falcon/Taint.expected +++ /dev/null @@ -1,20 +0,0 @@ -| test.py:9 | req | falcon.request | -| test.py:9 | resp | falcon.response | -| test.py:10 | Attribute | file[externally controlled string] | -| test.py:10 | Attribute() | externally controlled string | -| test.py:10 | req | falcon.request | -| test.py:11 | Attribute() | json[externally controlled string] | -| test.py:11 | raw_json | externally controlled string | -| test.py:12 | resp | falcon.response | -| test.py:13 | Dict | {json[externally controlled string]} | -| test.py:15 | result | json[externally controlled string] | -| test.py:17 | result | {json[externally controlled string]} | -| test.py:19 | req | falcon.request | -| test.py:19 | resp | falcon.response | -| test.py:22 | req | falcon.request | -| test.py:22 | resp | falcon.response | -| test.py:23 | Attribute | wsgi.environment | -| test.py:23 | req | falcon.request | -| test.py:24 | Subscript | externally controlled string | -| test.py:24 | env | wsgi.environment | -| test.py:25 | qs | externally controlled string | diff --git a/python/ql/test/library-tests/web/falcon/Taint.ql b/python/ql/test/library-tests/web/falcon/Taint.ql deleted file mode 100644 index d68b12079b8..00000000000 --- a/python/ql/test/library-tests/web/falcon/Taint.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -where node.getLocation().getFile().getShortName() = "test.py" -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/falcon/options b/python/ql/test/library-tests/web/falcon/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/library-tests/web/falcon/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/falcon/test.py b/python/ql/test/library-tests/web/falcon/test.py deleted file mode 100644 index 72853c94ad0..00000000000 --- a/python/ql/test/library-tests/web/falcon/test.py +++ /dev/null @@ -1,28 +0,0 @@ -import json - -from falcon import API - -app = API() - -class Handler(object): - - def on_get(self, req, resp): - raw_json = req.stream.read() - result = json.loads(raw_json) - resp.status = 200 - result = { - 'status': 'success', - 'data': result - } - resp.body = json.dumps(result) - - def on_post(self, req, resp): - pass - - def on_delete(self, req, resp): - env = req.env - qs = env["QUERY_STRING"] - return qs - -app.add_route('/hello', Handler()) - diff --git a/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected b/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected deleted file mode 100644 index e860c6f2f87..00000000000 --- a/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected +++ /dev/null @@ -1,17 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:8:12:8:25 | flask.routed.response | externally controlled string | -| test.py:29:12:29:38 | flask.routed.response | externally controlled string | -| test.py:35:16:35:37 | flask.routed.response | externally controlled string | -| test.py:36:12:36:15 | flask.routed.response | externally controlled string | -| test.py:41:12:41:54 | flask.routed.response | externally controlled string | -| test.py:41:26:41:53 | flask.response.argument | externally controlled string | -| test.py:46:12:46:62 | flask.routed.response | externally controlled string | -| test.py:46:26:46:61 | flask.response.argument | externally controlled string | -| test.py:50:12:50:48 | flask.routed.response | externally controlled string | -| test.py:50:26:50:47 | flask.response.argument | externally controlled string | -| test.py:54:12:54:53 | flask.routed.response | externally controlled string | -| test.py:54:26:54:52 | flask.response.argument | externally controlled string | -| test.py:60:12:60:62 | flask.routed.response | externally controlled string | -| test.py:60:26:60:61 | flask.response.argument | externally controlled string | -| test.py:64:12:64:58 | flask.routed.response | externally controlled string | -| test.py:64:26:64:57 | flask.response.argument | externally controlled string | diff --git a/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql b/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/flask/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/flask/HttpSources.expected b/python/ql/test/library-tests/web/flask/HttpSources.expected deleted file mode 100644 index e313f9bf1c2..00000000000 --- a/python/ql/test/library-tests/web/flask/HttpSources.expected +++ /dev/null @@ -1,10 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:29:12:29:23 | Attribute | {externally controlled string} | -| test.py:33:9:33:20 | Attribute | {externally controlled string} | -| test.py:35:16:35:27 | Attribute | {externally controlled string} | -| test.py:40:18:40:29 | Attribute | {externally controlled string} | -| test.py:45:18:45:29 | Attribute | {externally controlled string} | -| test.py:49:11:49:14 | name | externally controlled string | -| test.py:53:9:53:15 | subpath | externally controlled string | -| test.py:59:24:59:26 | bar | externally controlled string | -| test.py:63:13:63:21 | lang_code | externally controlled string | diff --git a/python/ql/test/library-tests/web/flask/HttpSources.ql b/python/ql/test/library-tests/web/flask/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/flask/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/flask/Routing.expected b/python/ql/test/library-tests/web/flask/Routing.expected deleted file mode 100644 index 90e70bcee8a..00000000000 --- a/python/ql/test/library-tests/web/flask/Routing.expected +++ /dev/null @@ -1,11 +0,0 @@ -WARNING: Predicate flask_routing has been deprecated and may be removed in future (Routing.ql:5,7-20) -| / | Function hello_world | -| /complex/<string(length=2):lang_code> | Function complex | -| /dangerous | Function dangerous | -| /dangerous-with-cfg-split | Function dangerous2 | -| /foo/<path:subpath> | Function foo | -| /hello/<name> | Function hello | -| /multiple/bar/<bar> | Function multiple | -| /safe | Function safe | -| /the/ | Function get | -| /unsafe | Function unsafe | diff --git a/python/ql/test/library-tests/web/flask/Routing.ql b/python/ql/test/library-tests/web/flask/Routing.ql deleted file mode 100644 index 92ae6740f0d..00000000000 --- a/python/ql/test/library-tests/web/flask/Routing.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import semmle.python.web.flask.General - -from ControlFlowNode regex, Function func -where flask_routing(regex, func) -select regex.getNode().(StrConst).getText(), func.toString() diff --git a/python/ql/test/library-tests/web/flask/Taint.expected b/python/ql/test/library-tests/web/flask/Taint.expected deleted file mode 100644 index 48562648096..00000000000 --- a/python/ql/test/library-tests/web/flask/Taint.expected +++ /dev/null @@ -1,33 +0,0 @@ -| test.py:22 | Attribute() | flask/MyView.as.view | -| test.py:25 | the_view | flask/MyView.as.view | -| test.py:29 | Attribute | {externally controlled string} | -| test.py:29 | Attribute() | externally controlled string | -| test.py:33 | Attribute | {externally controlled string} | -| test.py:33 | Subscript | externally controlled string | -| test.py:35 | Attribute | {externally controlled string} | -| test.py:35 | Subscript | externally controlled string | -| test.py:40 | Attribute | {externally controlled string} | -| test.py:40 | Attribute() | externally controlled string | -| test.py:41 | BinaryExpr | externally controlled string | -| test.py:41 | first_name | externally controlled string | -| test.py:41 | make_response() | flask.Response | -| test.py:45 | Attribute | {externally controlled string} | -| test.py:45 | Attribute() | externally controlled string | -| test.py:46 | first_name | externally controlled string | -| test.py:46 | make_response() | flask.Response | -| test.py:49 | name | externally controlled string | -| test.py:50 | BinaryExpr | externally controlled string | -| test.py:50 | make_response() | flask.Response | -| test.py:50 | name | externally controlled string | -| test.py:53 | subpath | externally controlled string | -| test.py:54 | BinaryExpr | externally controlled string | -| test.py:54 | make_response() | flask.Response | -| test.py:54 | subpath | externally controlled string | -| test.py:59 | bar | externally controlled string | -| test.py:60 | Attribute() | externally controlled string | -| test.py:60 | bar | externally controlled string | -| test.py:60 | make_response() | flask.Response | -| test.py:63 | lang_code | externally controlled string | -| test.py:64 | Attribute() | externally controlled string | -| test.py:64 | lang_code | externally controlled string | -| test.py:64 | make_response() | flask.Response | diff --git a/python/ql/test/library-tests/web/flask/Taint.ql b/python/ql/test/library-tests/web/flask/Taint.ql deleted file mode 100644 index d68b12079b8..00000000000 --- a/python/ql/test/library-tests/web/flask/Taint.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -where node.getLocation().getFile().getShortName() = "test.py" -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/flask/options b/python/ql/test/library-tests/web/flask/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/library-tests/web/flask/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/flask/test.py b/python/ql/test/library-tests/web/flask/test.py deleted file mode 100644 index bedeaa56423..00000000000 --- a/python/ql/test/library-tests/web/flask/test.py +++ /dev/null @@ -1,67 +0,0 @@ -import flask - -from flask import Flask, request, make_response -app = Flask(__name__) - -@app.route("/") -def hello_world(): - return "Hello World!" - -from flask.views import MethodView - -class MyView(MethodView): - - def get(self, user_id): - if user_id is None: - # return a list of users - pass - else: - # expose a single user - pass - -the_view = MyView.as_view('my_view') - -app.add_url_rule('/the/', defaults={'user_id': None}, - view_func=the_view, methods=['GET',]) - -@app.route("/dangerous") -def dangerous(): - return request.args.get('payload') - -@app.route("/dangerous-with-cfg-split") -def dangerous2(): - x = request.form['param0'] - if request.method == "POST": - return request.form['param1'] - return None - -@app.route('/unsafe') -def unsafe(): - first_name = request.args.get('name', '') - return make_response("Your name is " + first_name) - -@app.route('/safe') -def safe(): - first_name = request.args.get('name', '') - return make_response("Your name is " + escape(first_name)) - -@app.route('/hello/<name>') -def hello(name): - return make_response("Your name is " + name) - -@app.route('/foo/<path:subpath>') -def foo(subpath): - return make_response("The subpath is " + subpath) - -@app.route('/multiple/') # TODO: not recognized as route -@app.route('/multiple/foo/<foo>') # TODO: not recognized as route -@app.route('/multiple/bar/<bar>') -def multiple(foo=None, bar=None): - return make_response("foo={!r} bar={!r}".format(foo, bar)) - -@app.route('/complex/<string(length=2):lang_code>') -def complex(lang_code): - return make_response("lang_code {}".format(lang_code)) - -if __name__ == "__main__": - app.run(debug=True) diff --git a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected deleted file mode 100644 index 959217e0acd..00000000000 --- a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:8:12:8:31 | pyramid.routed.response | externally controlled string | -| test.py:17:12:17:41 | pyramid.routed.response | externally controlled string | -| test.py:25:12:25:43 | pyramid.routed.response | externally controlled string | diff --git a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql b/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/pyramid/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/pyramid/HttpSources.expected b/python/ql/test/library-tests/web/pyramid/HttpSources.expected deleted file mode 100644 index 23f8ab8e3ab..00000000000 --- a/python/ql/test/library-tests/web/pyramid/HttpSources.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:7:10:7:16 | request | pyramid.request | -| test.py:15:11:15:17 | request | pyramid.request | -| test.py:24:11:24:17 | request | pyramid.request | diff --git a/python/ql/test/library-tests/web/pyramid/HttpSources.ql b/python/ql/test/library-tests/web/pyramid/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/pyramid/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/pyramid/Routing.expected b/python/ql/test/library-tests/web/pyramid/Routing.expected deleted file mode 100644 index 41e66136a68..00000000000 --- a/python/ql/test/library-tests/web/pyramid/Routing.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Predicate is_pyramid_view_function has been deprecated and may be removed in future (Routing.ql:5,7-31) -| test.py:7 | Function home | -| test.py:15 | Function greet | -| test.py:24 | Function stuff | diff --git a/python/ql/test/library-tests/web/pyramid/Routing.ql b/python/ql/test/library-tests/web/pyramid/Routing.ql deleted file mode 100644 index 4a442c1115e..00000000000 --- a/python/ql/test/library-tests/web/pyramid/Routing.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import semmle.python.web.pyramid.View - -from Function func -where is_pyramid_view_function(func) -select func.getLocation().toString(), func.toString() diff --git a/python/ql/test/library-tests/web/pyramid/Taint.expected b/python/ql/test/library-tests/web/pyramid/Taint.expected deleted file mode 100644 index 94b8f844efb..00000000000 --- a/python/ql/test/library-tests/web/pyramid/Taint.expected +++ /dev/null @@ -1,11 +0,0 @@ -| test.py:7 | request | pyramid.request | -| test.py:15 | request | pyramid.request | -| test.py:16 | Attribute | {externally controlled string} | -| test.py:16 | Subscript | externally controlled string | -| test.py:16 | request | pyramid.request | -| test.py:17 | BinaryExpr | externally controlled string | -| test.py:17 | name | externally controlled string | -| test.py:24 | request | pyramid.request | -| test.py:25 | Attribute | externally controlled string | -| test.py:25 | Dict | {externally controlled string} | -| test.py:25 | request | pyramid.request | diff --git a/python/ql/test/library-tests/web/pyramid/Taint.ql b/python/ql/test/library-tests/web/pyramid/Taint.ql deleted file mode 100644 index d68b12079b8..00000000000 --- a/python/ql/test/library-tests/web/pyramid/Taint.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -where node.getLocation().getFile().getShortName() = "test.py" -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/pyramid/options b/python/ql/test/library-tests/web/pyramid/options deleted file mode 100644 index 1d132442a3b..00000000000 --- a/python/ql/test/library-tests/web/pyramid/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/pyramid/test.py b/python/ql/test/library-tests/web/pyramid/test.py deleted file mode 100644 index 9fad8a7ba00..00000000000 --- a/python/ql/test/library-tests/web/pyramid/test.py +++ /dev/null @@ -1,25 +0,0 @@ -from pyramid.view import view_config -from pyramid.response import Response - -@view_config( - route_name='home' -) -def home(request): - return Response('Welcome!') - - -@view_config( - route_name='greet', - request_method='POST' -) -def greet(request): - name = request.POST['arg'] - return Response('Welcome %s!' % name) - - -@view_config( - route_name='stuff', - renderer='json' -) -def stuff(request): - return {"err": 0, "body": request.body} diff --git a/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.expected b/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.expected deleted file mode 100644 index c4344d158b7..00000000000 --- a/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.expected +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:72:26:72:58 | Taint sink | externally controlled string | -| test.py:73:31:73:54 | Taint sink | [externally controlled string] | diff --git a/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.ql b/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/stdlib/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/stdlib/HttpSources.expected b/python/ql/test/library-tests/web/stdlib/HttpSources.expected deleted file mode 100644 index e979c63fd84..00000000000 --- a/python/ql/test/library-tests/web/stdlib/HttpSources.expected +++ /dev/null @@ -1,35 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:18:13:18:16 | self | BaseHTTPRequestHandlerKind | -| test.py:20:13:20:16 | self | BaseHTTPRequestHandlerKind | -| test.py:22:13:22:16 | self | BaseHTTPRequestHandlerKind | -| test.py:24:13:24:16 | self | BaseHTTPRequestHandlerKind | -| test.py:25:13:25:16 | self | BaseHTTPRequestHandlerKind | -| test.py:26:13:26:16 | self | BaseHTTPRequestHandlerKind | -| test.py:27:13:27:16 | self | BaseHTTPRequestHandlerKind | -| test.py:28:13:28:16 | self | BaseHTTPRequestHandlerKind | -| test.py:29:13:29:16 | self | BaseHTTPRequestHandlerKind | -| test.py:30:13:30:16 | self | BaseHTTPRequestHandlerKind | -| test.py:31:13:31:16 | self | BaseHTTPRequestHandlerKind | -| test.py:32:13:32:16 | self | BaseHTTPRequestHandlerKind | -| test.py:33:17:33:20 | self | BaseHTTPRequestHandlerKind | -| test.py:34:19:34:22 | self | BaseHTTPRequestHandlerKind | -| test.py:36:13:36:16 | self | BaseHTTPRequestHandlerKind | -| test.py:37:13:37:16 | self | BaseHTTPRequestHandlerKind | -| test.py:40:16:44:9 | Attribute() | CgiFieldStorageFormKind | -| test.py:41:13:41:16 | self | BaseHTTPRequestHandlerKind | -| test.py:42:13:42:16 | self | BaseHTTPRequestHandlerKind | -| test.py:43:64:43:67 | self | BaseHTTPRequestHandlerKind | -| test.py:69:9:69:12 | self | BaseHTTPRequestHandlerKind | -| test.py:70:9:70:12 | self | BaseHTTPRequestHandlerKind | -| test.py:71:9:71:12 | self | BaseHTTPRequestHandlerKind | -| test.py:72:9:72:12 | self | BaseHTTPRequestHandlerKind | -| test.py:73:9:73:12 | self | BaseHTTPRequestHandlerKind | -| test.py:74:15:74:18 | self | BaseHTTPRequestHandlerKind | -| test.py:78:16:82:9 | Attribute() | CgiFieldStorageFormKind | -| test.py:79:13:79:16 | self | BaseHTTPRequestHandlerKind | -| test.py:80:13:80:16 | self | BaseHTTPRequestHandlerKind | -| test.py:81:64:81:67 | self | BaseHTTPRequestHandlerKind | -| test.py:85:13:85:16 | self | BaseHTTPRequestHandlerKind | -| test.py:86:13:86:16 | self | BaseHTTPRequestHandlerKind | -| test.py:96:9:96:12 | self | BaseHTTPRequestHandlerKind | -| test.py:97:9:97:12 | self | BaseHTTPRequestHandlerKind | diff --git a/python/ql/test/library-tests/web/stdlib/HttpSources.ql b/python/ql/test/library-tests/web/stdlib/HttpSources.ql deleted file mode 100644 index f4e9a1b48d3..00000000000 --- a/python/ql/test/library-tests/web/stdlib/HttpSources.ql +++ /dev/null @@ -1,9 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where - source.isSourceOf(kind) and - source.getLocation().getFile().getShortName() != "cgi.py" -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/stdlib/TestTaint.expected b/python/ql/test/library-tests/web/stdlib/TestTaint.expected deleted file mode 100644 index eba1bff195a..00000000000 --- a/python/ql/test/library-tests/web/stdlib/TestTaint.expected +++ /dev/null @@ -1,32 +0,0 @@ -| test.py:18 | ok | taint_sources | self | BaseHTTPRequestHandlerKind | -| test.py:20 | ok | taint_sources | Attribute | externally controlled string | -| test.py:22 | ok | taint_sources | Attribute | externally controlled string | -| test.py:24 | ok | taint_sources | Attribute | {externally controlled string} | -| test.py:25 | ok | taint_sources | Subscript | externally controlled string | -| test.py:26 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:27 | ok | taint_sources | Attribute() | [externally controlled string] | -| test.py:28 | fail | taint_sources | Attribute() | <NO TAINT> | -| test.py:29 | ok | taint_sources | Attribute() | [externally controlled string] | -| test.py:30 | fail | taint_sources | Attribute() | <NO TAINT> | -| test.py:31 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:32 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:33 | ok | taint_sources | str() | externally controlled string | -| test.py:34 | ok | taint_sources | bytes() | externally controlled string | -| test.py:36 | ok | taint_sources | Attribute | file[externally controlled string] | -| test.py:37 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:47 | ok | taint_sources | form | CgiFieldStorageFormKind | -| test.py:49 | ok | taint_sources | Subscript | CgiFieldStorageFieldKind | -| test.py:49 | ok | taint_sources | Subscript | [CgiFieldStorageFieldKind] | -| test.py:50 | ok | taint_sources | Attribute | externally controlled string | -| test.py:51 | ok | taint_sources | Attribute | file[externally controlled string] | -| test.py:52 | ok | taint_sources | Attribute | externally controlled string | -| test.py:53 | ok | taint_sources | Subscript | CgiFieldStorageFieldKind | -| test.py:54 | ok | taint_sources | Attribute | externally controlled string | -| test.py:55 | ok | taint_sources | Attribute | file[externally controlled string] | -| test.py:56 | ok | taint_sources | Attribute | externally controlled string | -| test.py:58 | ok | taint_sources | Attribute() | [externally controlled string] | -| test.py:58 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:59 | ok | taint_sources | Subscript | externally controlled string | -| test.py:61 | ok | taint_sources | Attribute() | externally controlled string | -| test.py:63 | ok | taint_sources | Attribute() | [externally controlled string] | -| test.py:64 | ok | taint_sources | Subscript | externally controlled string | diff --git a/python/ql/test/library-tests/web/stdlib/TestTaint.ql b/python/ql/test/library-tests/web/stdlib/TestTaint.ql deleted file mode 100644 index cd2b08ef235..00000000000 --- a/python/ql/test/library-tests/web/stdlib/TestTaint.ql +++ /dev/null @@ -1,32 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false - ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "<NO TAINT>" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok " else test_res = "fail" -// if expected_taint = has_taint then test_res = "✓" else test_res = "✕" -select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/web/stdlib/test.py b/python/ql/test/library-tests/web/stdlib/test.py deleted file mode 100644 index 1c239f776bb..00000000000 --- a/python/ql/test/library-tests/web/stdlib/test.py +++ /dev/null @@ -1,108 +0,0 @@ -import sys -import os -import cgi - -if sys.version_info[0] == 2: - from BaseHTTPServer import BaseHTTPRequestHandler - from BaseHTTPServer import HTTPServer - -if sys.version_info[0] == 3: - from http.server import HTTPServer, BaseHTTPRequestHandler - - -class MyHandler(BaseHTTPRequestHandler): - - def taint_sources(self): - - ensure_tainted( - self, - - self.requestline, - - self.path, - - self.headers, - self.headers['Foo'], - self.headers.get('Foo'), - self.headers.get_all('Foo'), - self.headers.keys(), - self.headers.values(), - self.headers.items(), - self.headers.as_bytes(), - self.headers.as_string(), - str(self.headers), - bytes(self.headers), - - self.rfile, - self.rfile.read(), - ) - - form = cgi.FieldStorage( - self.rfile, - self.headers, - environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('content-type')}, - ) - - ensure_tainted( - form, - - form['key'], - form['key'].value, - form['key'].file, - form['key'].filename, - form['key'][0], # will be a list, if multiple fields named "key" are provided - form['key'][0].value, - form['key'][0].file, - form['key'][0].filename, - - form.getvalue('key'), - form.getvalue('key')[0], # will be a list, if multiple fields named "key" are provided - - form.getfirst('key'), - - form.getlist('key'), - form.getlist('key')[0], - ) - - def do_GET(self): - # send_response will log a line to stderr - self.send_response(200) - self.send_header("Content-type", "text/plain; charset=utf-8") - self.end_headers() - self.wfile.write(b"Hello BaseHTTPRequestHandler\n") - self.wfile.writelines([b"1\n", b"2\n", b"3\n"]) - print(self.headers) - - - def do_POST(self): - form = cgi.FieldStorage( - self.rfile, - self.headers, - environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('content-type')}, - ) - - if 'myfile' not in form: - self.send_response(422) - self.end_headers() - return - - field = form['myfile'] - - field.file.seek(0, os.SEEK_END) - filesize = field.file.tell() - - print("Uploaded {!r} with {} bytes".format(field.filename, filesize)) - - self.send_response(200) - self.end_headers() - - -if __name__ == "__main__": - server = HTTPServer(("127.0.0.1", 8080), MyHandler) - server.serve_forever() - - # Headers works case insensitvely, so self.headers['foo'] == self.headers['FOO'] - # curl localhost:8080 --header "Foo: 1" --header "foo: 2" - - # To test file submission through forms, use - # curl -F myfile=@<yourfile> localhost:8080 diff --git a/python/ql/test/library-tests/web/tornado/Classes.expected b/python/ql/test/library-tests/web/tornado/Classes.expected deleted file mode 100644 index 693976a2480..00000000000 --- a/python/ql/test/library-tests/web/tornado/Classes.expected +++ /dev/null @@ -1,5 +0,0 @@ -WARNING: Predicate aTornadoRequestHandlerClass has been deprecated and may be removed in future (Classes.ql:6,13-40) -| test.py:4 | class Handler1 | -| test.py:8 | class Handler2 | -| test.py:14 | class Handler3 | -| test.py:23 | class DeepInheritance | diff --git a/python/ql/test/library-tests/web/tornado/Classes.ql b/python/ql/test/library-tests/web/tornado/Classes.ql deleted file mode 100644 index fda9b6eb00a..00000000000 --- a/python/ql/test/library-tests/web/tornado/Classes.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.TestUtils -import semmle.python.web.tornado.Tornado - -from ClassValue cls -where cls = aTornadoRequestHandlerClass() -select remove_library_prefix(cls.getScope().getLocation()), cls.toString() diff --git a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected deleted file mode 100644 index aced656734c..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type HttpRedirectTaintSink has been deprecated and may be removed in future (HttpRedirectSinks.ql:5,6-27) -| test.py:20:23:20:25 | tornado.HttpRequestHandler.redirect | externally controlled string | diff --git a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql b/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql deleted file mode 100644 index 157ef2d4430..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpRedirectSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRedirect -import semmle.python.security.strings.Untrusted - -from HttpRedirectTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected deleted file mode 100644 index 0681e121664..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:6:20:6:43 | tornado.HttpRequestHandler.write | externally controlled string | -| test.py:12:20:12:23 | tornado.HttpRequestHandler.write | externally controlled string | -| test.py:26:20:26:48 | tornado.HttpRequestHandler.write | externally controlled string | diff --git a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql b/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/tornado/HttpSources.expected b/python/ql/test/library-tests/web/tornado/HttpSources.expected deleted file mode 100644 index 7e882de7791..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpSources.expected +++ /dev/null @@ -1,5 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:6:20:6:43 | Attribute() | externally controlled string | -| test.py:10:16:10:40 | Attribute() | [externally controlled string] | -| test.py:17:15:17:26 | Attribute | tornado.request.HttpRequest | -| test.py:26:20:26:48 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/tornado/HttpSources.ql b/python/ql/test/library-tests/web/tornado/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/tornado/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/tornado/Taint.expected b/python/ql/test/library-tests/web/tornado/Taint.expected deleted file mode 100644 index 6028c194b94..00000000000 --- a/python/ql/test/library-tests/web/tornado/Taint.expected +++ /dev/null @@ -1,12 +0,0 @@ -| test.py:6 | Attribute() | externally controlled string | -| test.py:10 | Attribute() | [externally controlled string] | -| test.py:11 | Subscript | externally controlled string | -| test.py:11 | args | [externally controlled string] | -| test.py:12 | name | externally controlled string | -| test.py:17 | Attribute | tornado.request.HttpRequest | -| test.py:18 | Attribute | {externally controlled string} | -| test.py:18 | req | tornado.request.HttpRequest | -| test.py:19 | Subscript | externally controlled string | -| test.py:19 | h | {externally controlled string} | -| test.py:20 | url | externally controlled string | -| test.py:26 | Attribute() | externally controlled string | diff --git a/python/ql/test/library-tests/web/tornado/Taint.ql b/python/ql/test/library-tests/web/tornado/Taint.ql deleted file mode 100644 index d4fc34b643c..00000000000 --- a/python/ql/test/library-tests/web/tornado/Taint.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -import semmle.python.TestUtils -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -// Add this restriction to keep Python2 and 3 results the same. -where not exists(node.getContext().getCaller()) -select remove_library_prefix(node.getLocation()), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/tornado/options b/python/ql/test/library-tests/web/tornado/options deleted file mode 100644 index 1d132442a3b..00000000000 --- a/python/ql/test/library-tests/web/tornado/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/tornado/test.py b/python/ql/test/library-tests/web/tornado/test.py deleted file mode 100644 index a5a467a81ab..00000000000 --- a/python/ql/test/library-tests/web/tornado/test.py +++ /dev/null @@ -1,26 +0,0 @@ - -import tornado.web - -class Handler1(tornado.web.RequestHandler): - def get(self): - self.write(self.get_argument("xss")) - -class Handler2(tornado.web.RequestHandler): - def get(self): - args = self.get_body_arguments() - name = args[0] - self.write(name) - -class Handler3(tornado.web.RequestHandler): - - def get(self): - req = self.request - h = req.headers - url = h["url"] - self.redirect(url) - - -class DeepInheritance(Handler3): - - def get(self): - self.write(self.get_argument("also_xss")) diff --git a/python/ql/test/library-tests/web/turbogears/Controller.expected b/python/ql/test/library-tests/web/turbogears/Controller.expected deleted file mode 100644 index 1f47639b5a5..00000000000 --- a/python/ql/test/library-tests/web/turbogears/Controller.expected +++ /dev/null @@ -1,6 +0,0 @@ -WARNING: Type TurboGearsControllerMethod has been deprecated and may be removed in future (Controller.ql:4,6-32) -| test.py:7:5:7:32 | Function onerror | -| test.py:13:5:13:50 | Function ok_validated | -| test.py:18:5:18:57 | Function partially_validated | -| test.py:22:5:22:51 | Function not_validated | -| test.py:26:5:26:28 | Function with_template | diff --git a/python/ql/test/library-tests/web/turbogears/Controller.ql b/python/ql/test/library-tests/web/turbogears/Controller.ql deleted file mode 100644 index 850e56ef453..00000000000 --- a/python/ql/test/library-tests/web/turbogears/Controller.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import semmle.python.web.turbogears.TurboGears - -from TurboGearsControllerMethod m -select m diff --git a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected deleted file mode 100644 index f2c1d0ee324..00000000000 --- a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.expected +++ /dev/null @@ -1,6 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:8:16:8:69 | TurboGears ControllerMethodReturnValue | externally controlled string | -| test.py:14:16:14:50 | TurboGears ControllerMethodReturnValue | externally controlled string | -| test.py:19:16:19:50 | TurboGears ControllerMethodReturnValue | externally controlled string | -| test.py:23:16:23:50 | TurboGears ControllerMethodReturnValue | externally controlled string | -| test.py:27:16:27:38 | TurboGears ControllerMethodTemplatedReturnValue | {externally controlled string} | diff --git a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql b/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/turbogears/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/turbogears/HttpSources.expected b/python/ql/test/library-tests/web/turbogears/HttpSources.expected deleted file mode 100644 index 0d0dc0f72fe..00000000000 --- a/python/ql/test/library-tests/web/turbogears/HttpSources.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:18:43:18:43 | b | externally controlled string | -| test.py:22:29:22:29 | a | externally controlled string | -| test.py:22:37:22:37 | b | externally controlled string | diff --git a/python/ql/test/library-tests/web/turbogears/HttpSources.ql b/python/ql/test/library-tests/web/turbogears/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/turbogears/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/turbogears/Taint.expected b/python/ql/test/library-tests/web/turbogears/Taint.expected deleted file mode 100644 index 45b84df72c2..00000000000 --- a/python/ql/test/library-tests/web/turbogears/Taint.expected +++ /dev/null @@ -1,12 +0,0 @@ -| test.py:18 | b | externally controlled string | -| test.py:19 | BinaryExpr | [externally controlled string] | -| test.py:19 | BinaryExpr | externally controlled string | -| test.py:19 | Tuple | [externally controlled string] | -| test.py:19 | b | externally controlled string | -| test.py:22 | a | externally controlled string | -| test.py:22 | b | externally controlled string | -| test.py:23 | BinaryExpr | [externally controlled string] | -| test.py:23 | BinaryExpr | externally controlled string | -| test.py:23 | Tuple | [externally controlled string] | -| test.py:23 | a | externally controlled string | -| test.py:23 | b | externally controlled string | diff --git a/python/ql/test/library-tests/web/turbogears/Taint.ql b/python/ql/test/library-tests/web/turbogears/Taint.ql deleted file mode 100644 index 09972af5f98..00000000000 --- a/python/ql/test/library-tests/web/turbogears/Taint.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -select node.getLocation().toString(), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/turbogears/options b/python/ql/test/library-tests/web/turbogears/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/library-tests/web/turbogears/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/turbogears/test.py b/python/ql/test/library-tests/web/turbogears/test.py deleted file mode 100644 index bae3a460f43..00000000000 --- a/python/ql/test/library-tests/web/turbogears/test.py +++ /dev/null @@ -1,27 +0,0 @@ - -from tg import request, validate, expose, TGController -from formencode import validators - -class RootController(TGController): - @expose() - def onerror(self, **kwargs): - return 'An error occurred: %s' % request.validation['errors'] - - @expose() - @validate({"a": validators.Int(not_empty=True), "b": validators.Email}, - error_handler=onerror) - def ok_validated(self, a=None, b=None, *args): - return 'Values: %s, %s, %s' % (a, b, args) - - @expose() - @validate({"a": validators.Int(not_empty=True)}) - def partially_validated(self, a=None, b=None, *args): - return 'Values: %s, %s, %s' % (a, b, args) - - @expose() - def not_validated(self, a=None, b=None, *args): - return 'Values: %s, %s, %s' % (a, b, args) - - @expose("<template_path>") - def with_template(self): - return {'template_var': 'foo'} diff --git a/python/ql/test/library-tests/web/twisted/Classes.expected b/python/ql/test/library-tests/web/twisted/Classes.expected deleted file mode 100644 index b818907e98f..00000000000 --- a/python/ql/test/library-tests/web/twisted/Classes.expected +++ /dev/null @@ -1,6 +0,0 @@ -WARNING: Predicate aTwistedRequestHandlerClass has been deprecated and may be removed in future (Classes.ql:6,13-40) -| class MyRequestHandler1 | test.py:3 | -| class MyRequestHandler2 | test.py:23 | -| class MyRequestHandler3 | test.py:27 | -| class MyRequestHandler4 | test.py:38 | -| class MyRequestHandler5 | test.py:42 | diff --git a/python/ql/test/library-tests/web/twisted/Classes.ql b/python/ql/test/library-tests/web/twisted/Classes.ql deleted file mode 100644 index ccc3618b61e..00000000000 --- a/python/ql/test/library-tests/web/twisted/Classes.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.TestUtils -import semmle.python.web.twisted.Twisted - -from ClassValue cls -where cls = aTwistedRequestHandlerClass() -select cls.toString(), remove_library_prefix(cls.getScope().getLocation()) diff --git a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected deleted file mode 100644 index 763655ffe37..00000000000 --- a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.expected +++ /dev/null @@ -1,11 +0,0 @@ -WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27) -| test.py:7:16:7:23 | Twisted response | externally controlled string | -| test.py:14:16:14:23 | Twisted response | externally controlled string | -| test.py:21:16:21:23 | Twisted response | externally controlled string | -| test.py:36:16:36:37 | Twisted response | externally controlled string | -| test.py:40:23:40:30 | Twisted request setter | externally controlled string | -| test.py:44:27:44:31 | Twisted request setter | externally controlled string | -| test.py:44:34:44:38 | Twisted request setter | externally controlled string | -| test.py:45:27:45:31 | Twisted request setter | externally controlled string | -| test.py:45:34:45:40 | Twisted request setter | externally controlled string | -| test.py:46:16:46:37 | Twisted response | externally controlled string | diff --git a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql b/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql deleted file mode 100644 index e62ec486da6..00000000000 --- a/python/ql/test/library-tests/web/twisted/HttpResponseSinks.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from HttpResponseTaintSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/web/twisted/HttpSources.expected b/python/ql/test/library-tests/web/twisted/HttpSources.expected deleted file mode 100644 index 4e7cb4c7abb..00000000000 --- a/python/ql/test/library-tests/web/twisted/HttpSources.expected +++ /dev/null @@ -1,9 +0,0 @@ -WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28) -| test.py:4:22:4:28 | request | twisted.request.http.Request | -| test.py:9:26:9:32 | request | twisted.request.http.Request | -| test.py:16:27:16:33 | request | twisted.request.http.Request | -| test.py:24:24:24:30 | request | twisted.request.http.Request | -| test.py:28:22:28:30 | myrequest | twisted.request.http.Request | -| test.py:31:27:31:37 | postrequest | twisted.request.http.Request | -| test.py:39:22:39:28 | request | twisted.request.http.Request | -| test.py:43:22:43:28 | request | twisted.request.http.Request | diff --git a/python/ql/test/library-tests/web/twisted/HttpSources.ql b/python/ql/test/library-tests/web/twisted/HttpSources.ql deleted file mode 100644 index 6fa1a7d2a6b..00000000000 --- a/python/ql/test/library-tests/web/twisted/HttpSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted - -from HttpRequestTaintSource source, TaintKind kind -where source.isSourceOf(kind) -select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/twisted/Methods.expected b/python/ql/test/library-tests/web/twisted/Methods.expected deleted file mode 100644 index 6578ef88da9..00000000000 --- a/python/ql/test/library-tests/web/twisted/Methods.expected +++ /dev/null @@ -1,9 +0,0 @@ -WARNING: Predicate getTwistedRequestHandlerMethod has been deprecated and may be removed in future (Methods.ql:6,14-44) -| myrender | Function MyRequestHandler2.myrender | test.py:24 | -| render | Function MyRequestHandler1.render | test.py:4 | -| render | Function MyRequestHandler3.render | test.py:28 | -| render | Function MyRequestHandler4.render | test.py:39 | -| render | Function MyRequestHandler5.render | test.py:43 | -| render_GET | Function MyRequestHandler1.render_GET | test.py:9 | -| render_POST | Function MyRequestHandler1.render_POST | test.py:16 | -| render_POST | Function MyRequestHandler3.render_POST | test.py:31 | diff --git a/python/ql/test/library-tests/web/twisted/Methods.ql b/python/ql/test/library-tests/web/twisted/Methods.ql deleted file mode 100644 index f997b7deef3..00000000000 --- a/python/ql/test/library-tests/web/twisted/Methods.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.TestUtils -import semmle.python.web.twisted.Twisted - -from FunctionValue func, string name -where func = getTwistedRequestHandlerMethod(name) -select name, func.toString(), remove_library_prefix(func.getScope().getLocation()) diff --git a/python/ql/test/library-tests/web/twisted/Taint.expected b/python/ql/test/library-tests/web/twisted/Taint.expected deleted file mode 100644 index 1c793c973bd..00000000000 --- a/python/ql/test/library-tests/web/twisted/Taint.expected +++ /dev/null @@ -1,41 +0,0 @@ -| test.py:4 | request | twisted.request.http.Request | -| test.py:5 | Attribute | externally controlled string | -| test.py:5 | request | twisted.request.http.Request | -| test.py:6 | request | twisted.request.http.Request | -| test.py:9 | request | twisted.request.http.Request | -| test.py:10 | request | twisted.request.http.Request | -| test.py:11 | Attribute | externally controlled string | -| test.py:11 | x | twisted.request.http.Request | -| test.py:12 | request | twisted.request.http.Request | -| test.py:13 | request | twisted.request.http.Request | -| test.py:16 | request | twisted.request.http.Request | -| test.py:17 | Attribute | {[externally controlled string]} | -| test.py:17 | request | twisted.request.http.Request | -| test.py:18 | Attribute | {[externally controlled string]} | -| test.py:18 | Attribute() | [externally controlled string] | -| test.py:18 | request | twisted.request.http.Request | -| test.py:19 | Subscript | externally controlled string | -| test.py:19 | foo | [externally controlled string] | -| test.py:20 | quux | externally controlled string | -| test.py:24 | request | twisted.request.http.Request | -| test.py:25 | request | twisted.request.http.Request | -| test.py:28 | myrequest | twisted.request.http.Request | -| test.py:29 | myrequest | twisted.request.http.Request | -| test.py:31 | postrequest | twisted.request.http.Request | -| test.py:32 | Attribute() | externally controlled string | -| test.py:32 | postrequest | twisted.request.http.Request | -| test.py:33 | Attribute() | externally controlled string | -| test.py:33 | postrequest | twisted.request.http.Request | -| test.py:34 | Attribute() | externally controlled string | -| test.py:34 | postrequest | twisted.request.http.Request | -| test.py:35 | Attribute() | externally controlled string | -| test.py:35 | postrequest | twisted.request.http.Request | -| test.py:36 | w | externally controlled string | -| test.py:36 | x | externally controlled string | -| test.py:36 | y | externally controlled string | -| test.py:36 | z | externally controlled string | -| test.py:39 | request | twisted.request.http.Request | -| test.py:40 | request | twisted.request.http.Request | -| test.py:43 | request | twisted.request.http.Request | -| test.py:44 | request | twisted.request.http.Request | -| test.py:45 | request | twisted.request.http.Request | diff --git a/python/ql/test/library-tests/web/twisted/Taint.ql b/python/ql/test/library-tests/web/twisted/Taint.ql deleted file mode 100644 index e92616b6b29..00000000000 --- a/python/ql/test/library-tests/web/twisted/Taint.ql +++ /dev/null @@ -1,8 +0,0 @@ -import python -import semmle.python.TestUtils -import semmle.python.web.HttpRequest -import semmle.python.web.HttpResponse -import semmle.python.security.strings.Untrusted - -from TaintedNode node -select remove_library_prefix(node.getLocation()), node.getAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/web/twisted/options b/python/ql/test/library-tests/web/twisted/options deleted file mode 100644 index 4084b102b55..00000000000 --- a/python/ql/test/library-tests/web/twisted/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=1 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/web/twisted/test.py b/python/ql/test/library-tests/web/twisted/test.py deleted file mode 100644 index f6691b84d95..00000000000 --- a/python/ql/test/library-tests/web/twisted/test.py +++ /dev/null @@ -1,51 +0,0 @@ -from twisted.web import resource - -class MyRequestHandler1(resource.Resource): - def render(self, request): - foo(request.uri) - response = do_stuff_with(request) - return response - - def render_GET(self, request): - x = request - bar(x.uri) - do_stuff_with(request) - response = do_stuff_with(request) - return response - - def render_POST(self, request): - baz(request.args) - foo = request.args.get("baz") - quux = foo[5] - response = do_stuff_with(quux) - return response - -class MyRequestHandler2(resource.Resource): - def myrender(self, request): - do_stuff_with(request) - -class MyRequestHandler3(resource.Resource): - def render(self, myrequest): - do_stuff_with(myrequest) - - def render_POST(self, postrequest): - x = postrequest.getHeader("someheader") - y = postrequest.getCookie("somecookie") - z = postrequest.getUser() - w = postrequest.getPassword() - return do_stuff_with(x,y,z,w) - -class MyRequestHandler4(resource.Resource): - def render(self, request): - request.write("Foobar") - -class MyRequestHandler5(resource.Resource): - def render(self, request): - request.setHeader("foo", "bar") - request.addCookie("key", "value") - return "This is my response." - -class NotATwistedRequestHandler(object): - def render(self, request): - return do_stuff_with(request) - diff --git a/python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll b/python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll index 4d1bfeb3859..c8d1acff57a 100644 --- a/python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll +++ b/python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll @@ -2,27 +2,18 @@ import python abstract class XmlBytecodeExpr extends XmlElement { } -/** DEPRECATED: Alias for XmlBytecodeExpr */ -deprecated class XMLBytecodeExpr = XmlBytecodeExpr; - class XmlBytecodeConst extends XmlBytecodeExpr { XmlBytecodeConst() { this.hasName("BytecodeConst") } string get_value_data_raw() { result = this.getAChild("value").getTextValue() } } -/** DEPRECATED: Alias for XmlBytecodeConst */ -deprecated class XMLBytecodeConst = XmlBytecodeConst; - class XmlBytecodeVariableName extends XmlBytecodeExpr { XmlBytecodeVariableName() { this.hasName("BytecodeVariableName") } string get_name_data() { result = this.getAChild("name").getTextValue() } } -/** DEPRECATED: Alias for XmlBytecodeVariableName */ -deprecated class XMLBytecodeVariableName = XmlBytecodeVariableName; - class XmlBytecodeAttribute extends XmlBytecodeExpr { XmlBytecodeAttribute() { this.hasName("BytecodeAttribute") } @@ -31,9 +22,6 @@ class XmlBytecodeAttribute extends XmlBytecodeExpr { XmlBytecodeExpr get_object_data() { result.getParent() = this.getAChild("object") } } -/** DEPRECATED: Alias for XmlBytecodeAttribute */ -deprecated class XMLBytecodeAttribute = XmlBytecodeAttribute; - class XmlBytecodeSubscript extends XmlBytecodeExpr { XmlBytecodeSubscript() { this.hasName("BytecodeSubscript") } @@ -42,9 +30,6 @@ class XmlBytecodeSubscript extends XmlBytecodeExpr { XmlBytecodeExpr get_object_data() { result.getParent() = this.getAChild("object") } } -/** DEPRECATED: Alias for XmlBytecodeSubscript */ -deprecated class XMLBytecodeSubscript = XmlBytecodeSubscript; - class XmlBytecodeTuple extends XmlBytecodeExpr { XmlBytecodeTuple() { this.hasName("BytecodeTuple") } @@ -53,9 +38,6 @@ class XmlBytecodeTuple extends XmlBytecodeExpr { } } -/** DEPRECATED: Alias for XmlBytecodeTuple */ -deprecated class XMLBytecodeTuple = XmlBytecodeTuple; - class XmlBytecodeList extends XmlBytecodeExpr { XmlBytecodeList() { this.hasName("BytecodeList") } @@ -64,27 +46,18 @@ class XmlBytecodeList extends XmlBytecodeExpr { } } -/** DEPRECATED: Alias for XmlBytecodeList */ -deprecated class XMLBytecodeList = XmlBytecodeList; - class XmlBytecodeCall extends XmlBytecodeExpr { XmlBytecodeCall() { this.hasName("BytecodeCall") } XmlBytecodeExpr get_function_data() { result.getParent() = this.getAChild("function") } } -/** DEPRECATED: Alias for XmlBytecodeCall */ -deprecated class XMLBytecodeCall = XmlBytecodeCall; - class XmlBytecodeUnknown extends XmlBytecodeExpr { XmlBytecodeUnknown() { this.hasName("BytecodeUnknown") } string get_opname_data() { result = this.getAChild("opname").getTextValue() } } -/** DEPRECATED: Alias for XmlBytecodeUnknown */ -deprecated class XMLBytecodeUnknown = XmlBytecodeUnknown; - class XmlBytecodeMakeFunction extends XmlBytecodeExpr { XmlBytecodeMakeFunction() { this.hasName("BytecodeMakeFunction") } @@ -93,14 +66,8 @@ class XmlBytecodeMakeFunction extends XmlBytecodeExpr { } } -/** DEPRECATED: Alias for XmlBytecodeMakeFunction */ -deprecated class XMLBytecodeMakeFunction = XmlBytecodeMakeFunction; - class XmlSomethingInvolvingScaryBytecodeJump extends XmlBytecodeExpr { XmlSomethingInvolvingScaryBytecodeJump() { this.hasName("SomethingInvolvingScaryBytecodeJump") } string get_opname_data() { result = this.getAChild("opname").getTextValue() } } - -/** DEPRECATED: Alias for XmlSomethingInvolvingScaryBytecodeJump */ -deprecated class XMLSomethingInvolvingScaryBytecodeJump = XmlSomethingInvolvingScaryBytecodeJump; diff --git a/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll b/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll index d6ad84ae3a1..4d0c11fa3fd 100644 --- a/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll +++ b/python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll @@ -57,9 +57,6 @@ class XmlRecordedCall extends XmlElement { } } -/** DEPRECATED: Alias for XmlRecordedCall */ -deprecated class XMLRecordedCall = XmlRecordedCall; - /** The XML data for the call part a recorded call. */ class XmlCall extends XmlElement { XmlCall() { this.hasName("Call") } @@ -110,15 +107,9 @@ class XmlCall extends XmlElement { } } -/** DEPRECATED: Alias for XmlCall */ -deprecated class XMLCall = XmlCall; - /** The XML data for the callee part a recorded call. */ abstract class XmlCallee extends XmlElement { } -/** DEPRECATED: Alias for XmlCallee */ -deprecated class XMLCallee = XmlCallee; - /** The XML data for the callee part a recorded call, when the callee is a Python function. */ class XmlPythonCallee extends XmlCallee { XmlPythonCallee() { this.hasName("PythonCallee") } @@ -140,9 +131,6 @@ class XmlPythonCallee extends XmlCallee { } } -/** DEPRECATED: Alias for XmlPythonCallee */ -deprecated class XMLPythonCallee = XmlPythonCallee; - /** The XML data for the callee part a recorded call, when the callee is a C function or builtin. */ class XmlExternalCallee extends XmlCallee { XmlExternalCallee() { this.hasName("ExternalCallee") } @@ -161,9 +149,6 @@ class XmlExternalCallee extends XmlCallee { } } -/** DEPRECATED: Alias for XmlExternalCallee */ -deprecated class XMLExternalCallee = XmlExternalCallee; - /** * Helper predicate. If parent = `builtins` and qualname = `list.append`, it will * return the result of `builtins.list.append`.class From 42d67d0137d806a63c48eec662a0df3fe3d20f7a Mon Sep 17 00:00:00 2001 From: erik-krogh <erik-krogh@github.com> Date: Fri, 9 Jun 2023 15:24:12 +0200 Subject: [PATCH 218/219] add change-note --- python/ql/lib/change-notes/2023-06-09-delete-deps.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-06-09-delete-deps.md diff --git a/python/ql/lib/change-notes/2023-06-09-delete-deps.md b/python/ql/lib/change-notes/2023-06-09-delete-deps.md new file mode 100644 index 00000000000..75753ea93b7 --- /dev/null +++ b/python/ql/lib/change-notes/2023-06-09-delete-deps.md @@ -0,0 +1,9 @@ +--- +category: minorAnalysis +--- +* Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead. +* Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead. +* Deleted many deprecated predicates in `PointsTo.qll`. +* Deleted many deprecated files from the `semmle.python.security` package. +* Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`. \ No newline at end of file From a628384d836f02293507259e3f6a504529c605db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 00:18:38 +0000 Subject: [PATCH 219/219] Add changed framework coverage reports --- java/documentation/library-coverage/coverage.csv | 2 +- java/documentation/library-coverage/coverage.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index acfd9b9224c..447797aff24 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -58,7 +58,7 @@ java.io,49,,45,,22,,,,,,,,,,,,,,27,,,,,,,,,,,,,,,,,,,43,2 java.lang,18,,92,,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 java.net,13,3,20,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,20, java.nio,47,,35,,3,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,35, -java.sql,13,,3,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2,1 +java.sql,13,,2,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2, java.util,44,,484,,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,44,440 javafx.scene.web,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,, javax.faces.context,2,7,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index 3e2043369dc..8464e0ca23e 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -18,10 +18,10 @@ Java framework & library support `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,730,41,7,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,, `JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,, - Java Standard Library,``java.*``,3,683,184,76,,9,,,17 + Java Standard Library,``java.*``,3,682,184,76,,9,,,17 Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 `Spring <https://spring.io/>`_,``org.springframework.*``,29,483,115,4,,28,14,,35 Others,"``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",98,899,528,66,,18,18,,195 - Totals,,255,9199,1997,263,10,122,33,1,385 + Totals,,255,9198,1997,263,10,122,33,1,385