From d729ab501b0d7ed30e2a6e3ea9c14dcd96245973 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Sep 2025 08:45:18 +0200 Subject: [PATCH 01/90] JS: Add test that calls .json or .jsonp --- .../frameworks/Express/src/json.js | 10 +++ .../frameworks/Express/tests.expected | 73 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/json.js diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/json.js b/javascript/ql/test/library-tests/frameworks/Express/src/json.js new file mode 100644 index 00000000000..6b87cad68cf --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/json.js @@ -0,0 +1,10 @@ +const express = require('express'); +const app = express(); + +app.get('/test/json', function(req, res) { + res.json(req.query.data); +}); + +app.get('/test/jsonp', function(req, res) { + res.jsonp(req.query.data); +}); diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index ec4253740f7..0abc2dbdf95 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -131,6 +131,12 @@ test_isRequest | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:7:2:7:4 | req | +| src/json.js:4:32:4:34 | req | +| src/json.js:4:32:4:34 | req | +| src/json.js:5:14:5:16 | req | +| src/json.js:8:33:8:35 | req | +| src/json.js:8:33:8:35 | req | +| src/json.js:9:15:9:17 | req | | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:6:5:6:7 | req | @@ -201,6 +207,8 @@ test_RouteSetup | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | false | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | false | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | false | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | false | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | false | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:2:13:2:21 | express() | true | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:2:13:2:21 | express() | false | | src/middleware-flow.js:39:1:43:2 | unrelat ... .db;\\n}) | src/middleware-flow.js:37:22:37:30 | express() | false | @@ -345,6 +353,14 @@ test_isResponse | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:6:2:6:4 | res | +| src/json.js:4:37:4:39 | res | +| src/json.js:4:37:4:39 | res | +| src/json.js:5:5:5:7 | res | +| src/json.js:5:5:5:28 | res.jso ... y.data) | +| src/json.js:8:38:8:40 | res | +| src/json.js:8:38:8:40 | res | +| src/json.js:9:5:9:7 | res | +| src/json.js:9:5:9:29 | res.jso ... y.data) | | src/middleware-flow.js:5:25:5:27 | res | | src/middleware-flow.js:17:30:17:32 | res | | src/middleware-flow.js:23:23:23:25 | res | @@ -575,6 +591,12 @@ test_RequestExpr | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:32:4:34 | req | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:4:32:4:34 | req | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:5:14:5:16 | req | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:33:8:35 | req | src/json.js:8:24:10:1 | functio ... ata);\\n} | +| src/json.js:8:33:8:35 | req | src/json.js:8:24:10:1 | functio ... ata);\\n} | +| src/json.js:9:15:9:17 | req | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:6:5:6:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | @@ -627,6 +649,7 @@ test_appCreation | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/json.js:2:13:2:21 | express() | | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:37:22:37:30 | express() | | src/params.js:2:11:2:19 | express() | @@ -820,6 +843,14 @@ test_ResponseExpr | src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:37:4:39 | res | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:4:37:4:39 | res | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:5:5:5:7 | res | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:5:5:5:28 | res.jso ... y.data) | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:38:8:40 | res | src/json.js:8:24:10:1 | functio ... ata);\\n} | +| src/json.js:8:38:8:40 | res | src/json.js:8:24:10:1 | functio ... ata);\\n} | +| src/json.js:9:5:9:7 | res | src/json.js:8:24:10:1 | functio ... ata);\\n} | +| src/json.js:9:5:9:29 | res.jso ... y.data) | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:5:25:5:27 | res | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:17:30:17:32 | res | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:23:23:23:25 | res | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | @@ -940,6 +971,8 @@ test_RouteHandler | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:65:36:65:38 | req | src/express.js:65:41:65:43 | res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:71:32:71:34 | req | src/express.js:71:37:71:39 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:32:4:34 | req | src/json.js:4:37:4:39 | res | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:33:8:35 | req | src/json.js:8:38:8:40 | res | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:25:5:27 | res | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:30:17:32 | res | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:18:23:20 | req | src/middleware-flow.js:23:23:23:25 | res | @@ -1036,6 +1069,8 @@ test_RouteHandlerExpr | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:65:1:69:2 | app.get ... es);\\n}) | true | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:71:1:75:2 | app.get ... es);\\n}) | true | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | true | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:1:6:2 | app.get ... ta);\\n}) | true | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:1:10:2 | app.get ... ta);\\n}) | true | | src/middleware-flow.js:13:16:13:24 | installDb | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | false | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | true | | src/middleware-flow.js:27:23:27:32 | routers[p] | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | true | @@ -1068,6 +1103,7 @@ test_isRouterCreation | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/json.js:2:13:2:21 | express() | | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:37:22:37:30 | express() | | src/params.js:2:11:2:19 | express() | @@ -1111,6 +1147,8 @@ test_RequestInputAccess | src/express.js:67:12:67:25 | req.params.foo | parameter | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:73:12:73:19 | req.path | url | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:7:2:7:8 | req.url | url | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:5:14:5:27 | req.query.data | parameter | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:9:15:9:28 | req.query.data | parameter | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/params.js:4:35:4:39 | value | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:5:17:5:28 | req.query.xx | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:6:17:6:24 | req.body | body | src/params.js:4:18:12:1 | (req, r ... }\\n} | @@ -1182,6 +1220,8 @@ test_RouteSetup_getRouter | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | src/middleware-flow.js:2:13:2:21 | express() | @@ -1226,6 +1266,8 @@ test_RouteSetup_getServer | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:2:13:2:21 | express() | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:39:1:43:2 | unrelat ... .db;\\n}) | src/middleware-flow.js:37:22:37:30 | express() | @@ -1266,6 +1308,8 @@ test_StandardRouteHandler | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:2:11:2:19 | express() | src/express.js:65:36:65:38 | req | src/express.js:65:41:65:43 | res | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:2:11:2:19 | express() | src/express.js:71:32:71:34 | req | src/express.js:71:37:71:39 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:2:13:2:21 | express() | src/json.js:4:32:4:34 | req | src/json.js:4:37:4:39 | res | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:2:13:2:21 | express() | src/json.js:8:33:8:35 | req | src/json.js:8:38:8:40 | res | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:2:13:2:21 | express() | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:25:5:27 | res | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:2:13:2:21 | express() | src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:30:17:32 | res | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:37:22:37:30 | express() | src/middleware-flow.js:39:24:39:26 | req | src/middleware-flow.js:39:29:39:31 | res | @@ -1346,6 +1390,8 @@ test_RouteHandlerExpr_getBody | src/express.js:65:27:69:1 | functio ... res);\\n} | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:23:75:1 | functio ... res);\\n} | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:13:16:13:24 | installDb | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | @@ -1466,6 +1512,8 @@ test_RouteSetup_getARouteHandler | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | @@ -1526,6 +1574,8 @@ test_RouteSetup_getRequestMethod | src/express.js:65:1:69:2 | app.get ... es);\\n}) | GET | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | GET | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | POST | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | GET | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | GET | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | GET | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | GET | | src/middleware-flow.js:39:1:43:2 | unrelat ... .db;\\n}) | GET | @@ -1699,6 +1749,12 @@ test_RouteHandler_getARequestExpr | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:32:4:34 | req | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:32:4:34 | req | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:5:14:5:16 | req | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:33:8:35 | req | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:33:8:35 | req | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:9:15:9:17 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:6:5:6:7 | req | @@ -1909,6 +1965,14 @@ test_RouteHandler_getAResponseExpr | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:37:4:39 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:4:37:4:39 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:5:5:5:7 | res | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | src/json.js:5:5:5:28 | res.jso ... y.data) | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:38:8:40 | res | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:8:38:8:40 | res | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:9:5:9:7 | res | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | src/json.js:9:5:9:29 | res.jso ... y.data) | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:25:5:27 | res | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:30:17:32 | res | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:23:23:25 | res | @@ -2041,6 +2105,8 @@ test_RouteSetup_getRouteHandlerExpr | src/express.js:65:1:69:2 | app.get ... es);\\n}) | 0 | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | 0 | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | 0 | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | 0 | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | 0 | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | 0 | src/middleware-flow.js:13:16:13:24 | installDb | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | 0 | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | 0 | src/middleware-flow.js:27:23:27:32 | routers[p] | @@ -2149,6 +2215,8 @@ test_RouteSetup_getARouteHandlerExpr | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:13:16:13:24 | installDb | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | src/middleware-flow.js:27:23:27:32 | routers[p] | @@ -2181,6 +2249,7 @@ test_RouterDefinition_RouterDefinition | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/json.js:2:13:2:21 | express() | | src/middleware-flow.js:2:13:2:21 | express() | | src/middleware-flow.js:37:22:37:30 | express() | | src/params.js:2:11:2:19 | express() | @@ -2216,6 +2285,8 @@ test_RouterDefinition_getARouteHandler | src/express.js:2:11:2:19 | express() | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:2:13:2:21 | express() | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:2:13:2:21 | express() | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:2:13:2:21 | express() | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:2:13:2:21 | express() | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:37:22:37:30 | express() | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | @@ -2334,6 +2405,8 @@ test_RouteSetup_getLastRouteHandlerExpr | src/express.js:65:1:69:2 | app.get ... es);\\n}) | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:71:1:75:2 | app.get ... es);\\n}) | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:4:1:6:2 | app.get ... ta);\\n}) | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:8:1:10:2 | app.get ... ta);\\n}) | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:13:16:13:24 | installDb | | src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | src/middleware-flow.js:27:23:27:32 | routers[p] | From 132a8b8b53bd8ce115d0641c8b11d47a0e0648e2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Sep 2025 08:46:21 +0200 Subject: [PATCH 02/90] JS: Model json and jsonp methods --- .../semmle/javascript/frameworks/Express.qll | 34 +++++++++++++++++++ .../frameworks/Express/tests.expected | 12 +++++++ 2 files changed, 46 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 8c016b3afe9..41e4d1c860c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -781,6 +781,40 @@ module Express { override RouteHandler getRouteHandler() { result = response.getRouteHandler() } } + /** + * A call to `res.json()` or `res.jsonp()`. + * + * This sets the `content-type` header. + */ + private class ResponseJsonCall extends DataFlow::MethodCallNode, Http::HeaderDefinition { + private ResponseSource response; + + ResponseJsonCall() { this = response.ref().getAMethodCall(["json", "jsonp"]) } + + override RouteHandler getRouteHandler() { result = response.getRouteHandler() } + + override string getAHeaderName() { result = "content-type" } + + override predicate defines(string headerName, string headerValue) { + // Note: for `jsonp` the actual content-type header will be `text/javascript` or similar, but to avoid + // generating a spurious HTML injection sink, we treat it as `application/json` here. + headerName = "content-type" and headerValue = "application/json" + } + } + + /** + * An argument passed to the `json` or `json` method of an HTTP response object. + */ + private class ResponseJsonCallArgument extends Http::ResponseSendArgument { + ResponseJsonCall call; + + ResponseJsonCallArgument() { this = call.getArgument(0) } + + override RouteHandler getRouteHandler() { result = call.getRouteHandler() } + + override HeaderDefinition getAnAssociatedHeaderDefinition() { result = call } + } + /** * An invocation of the `cookie` method on an HTTP response object. */ diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 0abc2dbdf95..9007a1ed984 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -674,6 +674,8 @@ test_ResponseBody | src/express.js:61:12:61:25 | req.params.foo | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:67:12:67:25 | req.params.foo | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:73:12:73:19 | req.path | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/json.js:5:14:5:27 | req.query.data | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:9:15:9:28 | req.query.data | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_ResponseExpr @@ -1005,6 +1007,8 @@ test_HeaderDefinition | src/express.js:66:3:66:42 | res.hea ... plain") | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:72:3:72:41 | res.hea ... /html") | src/express.js:71:23:75:1 | functio ... res);\\n} | | src/inheritedFromNode.js:6:2:6:16 | res.setHeader() | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/json.js:5:5:5:28 | res.jso ... y.data) | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:9:5:9:29 | res.jso ... y.data) | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/responseExprs.js:19:5:19:16 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:7:37:18 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | @@ -1163,6 +1167,8 @@ test_ResponseSendArgument | src/express.js:61:12:61:25 | req.params.foo | src/express.js:59:23:63:1 | functio ... res);\\n} | | src/express.js:67:12:67:25 | req.params.foo | src/express.js:65:27:69:1 | functio ... res);\\n} | | src/express.js:73:12:73:19 | req.path | src/express.js:71:23:75:1 | functio ... res);\\n} | +| src/json.js:5:14:5:27 | req.query.data | src/json.js:4:23:6:1 | functio ... ata);\\n} | +| src/json.js:9:15:9:28 | req.query.data | src/json.js:8:24:10:1 | functio ... ata);\\n} | | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_RouteSetup_getRouter @@ -1366,6 +1372,8 @@ test_HeaderDefinition_defines | src/express.js:60:3:60:47 | res.hea ... n/xml") | content-type | application/xml | | src/express.js:66:3:66:42 | res.hea ... plain") | content-type | text/plain | | src/express.js:72:3:72:41 | res.hea ... /html") | content-type | text/html | +| src/json.js:5:5:5:28 | res.jso ... y.data) | content-type | application/json | +| src/json.js:9:5:9:29 | res.jso ... y.data) | content-type | application/json | test_RouteHandlerExpr_getBody | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | @@ -2139,6 +2147,8 @@ test_HeaderDefinition_getAHeaderName | src/express.js:60:3:60:47 | res.hea ... n/xml") | content-type | | src/express.js:66:3:66:42 | res.hea ... plain") | content-type | | src/express.js:72:3:72:41 | res.hea ... /html") | content-type | +| src/json.js:5:5:5:28 | res.jso ... y.data) | content-type | +| src/json.js:9:5:9:29 | res.jso ... y.data) | content-type | test_RouteHandlerExpr_getAsSubRouter | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:30:16:30:35 | new express.Router() | | src/express2.js:6:9:6:14 | router | src/express2.js:2:14:2:23 | e.Router() | @@ -2155,6 +2165,8 @@ test_RouteHandler_getAResponseHeader | src/express.js:65:27:69:1 | functio ... res);\\n} | content-type | src/express.js:66:3:66:42 | res.hea ... plain") | | src/express.js:71:23:75:1 | functio ... res);\\n} | access-control-allow-credentials | src/express.js:12:3:12:54 | arg.hea ... , true) | | src/express.js:71:23:75:1 | functio ... res);\\n} | content-type | src/express.js:72:3:72:41 | res.hea ... /html") | +| src/json.js:4:23:6:1 | functio ... ata);\\n} | content-type | src/json.js:5:5:5:28 | res.jso ... y.data) | +| src/json.js:8:24:10:1 | functio ... ata);\\n} | content-type | src/json.js:9:5:9:29 | res.jso ... y.data) | test_RouteSetup_getARouteHandlerExpr | src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | | src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | From d295acc3c33268fe10fa5aaf20fde43ef900c59d Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Sep 2025 19:22:05 -0400 Subject: [PATCH 03/90] Add initial support for Ruby Grape --- ruby/ql/lib/codeql/ruby/Frameworks.qll | 1 + ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 198 ++++++++++++++++++ .../frameworks/grape/Grape.expected | 25 +++ .../library-tests/frameworks/grape/Grape.ql | 18 ++ .../library-tests/frameworks/grape/app.rb | 54 +++++ .../security/cwe-089/ArelInjection.rb | 9 + .../security/cwe-089/SqlInjection.expected | 11 + 7 files changed, 316 insertions(+) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Grape.qll create mode 100644 ruby/ql/test/library-tests/frameworks/grape/Grape.expected create mode 100644 ruby/ql/test/library-tests/frameworks/grape/Grape.ql create mode 100644 ruby/ql/test/library-tests/frameworks/grape/app.rb diff --git a/ruby/ql/lib/codeql/ruby/Frameworks.qll b/ruby/ql/lib/codeql/ruby/Frameworks.qll index 9bc01874710..e8009c91b7d 100644 --- a/ruby/ql/lib/codeql/ruby/Frameworks.qll +++ b/ruby/ql/lib/codeql/ruby/Frameworks.qll @@ -21,6 +21,7 @@ private import codeql.ruby.frameworks.Rails private import codeql.ruby.frameworks.Railties private import codeql.ruby.frameworks.Stdlib private import codeql.ruby.frameworks.Files +private import codeql.ruby.frameworks.Grape private import codeql.ruby.frameworks.HttpClients private import codeql.ruby.frameworks.XmlParsing private import codeql.ruby.frameworks.ActionDispatch diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll new file mode 100644 index 00000000000..8e9a062dc9a --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -0,0 +1,198 @@ +/** + * Provides modeling for the `Grape` API framework. + */ + +private import codeql.ruby.AST +private import codeql.ruby.Concepts +private import codeql.ruby.controlflow.CfgNodes +private import codeql.ruby.DataFlow +private import codeql.ruby.dataflow.RemoteFlowSources +private import codeql.ruby.ApiGraphs +private import codeql.ruby.typetracking.TypeTracking +private import codeql.ruby.frameworks.Rails +private import codeql.ruby.frameworks.internal.Rails +private import codeql.ruby.dataflow.internal.DataFlowDispatch + +/** + * Provides modeling for Grape, a REST-like API framework for Ruby. + * Grape allows you to build RESTful APIs in Ruby with minimal effort. + */ +module Grape { + /** + * A Grape API class which sits at the top of the class hierarchy. + * In other words, it does not subclass any other Grape API class in source code. + */ + class RootAPI extends GrapeAPIClass { + RootAPI() { + not exists(GrapeAPIClass parent | this != parent and this = parent.getADescendent()) + } + } +} + +/** + * A class that extends `Grape::API`. + * For example, + * + * ```rb + * class FooAPI < Grape::API + * get '/users' do + * name = params[:name] + * User.where("name = #{name}") + * end + * end + * ``` + */ +class GrapeAPIClass extends DataFlow::ClassNode { + GrapeAPIClass() { + this = grapeAPIBaseClass().getADescendentModule() and + not exists(DataFlow::ModuleNode m | m = grapeAPIBaseClass().asModule() | this = m) + } + + /** + * Gets a `GrapeEndpoint` defined in this class. + */ + GrapeEndpoint getAnEndpoint() { + result.getAPIClass() = this + } + + /** + * Gets a `self` that possibly refers to an instance of this class. + */ + DataFlow::LocalSourceNode getSelf() { + result = this.getAnInstanceSelf() + or + // Include the module-level `self` to recover some cases where a block at the module level + // is invoked with an instance as the `self`. + result = this.getModuleLevelSelf() + } +} + +private DataFlow::ConstRef grapeAPIBaseClass() { + result = DataFlow::getConstant("Grape").getConstant("API") +} + +private API::Node grapeAPIInstance() { + result = any(GrapeAPIClass cls).getSelf().track() +} + +/** + * A Grape API endpoint (get, post, put, delete, etc.) call within a `Grape::API` class. + */ +class GrapeEndpoint extends DataFlow::CallNode { + private GrapeAPIClass apiClass; + + GrapeEndpoint() { + this = apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) + } + + /** + * Gets the HTTP method for this endpoint (e.g., "GET", "POST", etc.) + */ + string getHttpMethod() { + result = this.getMethodName().toUpperCase() + } + + /** + * Gets the API class containing this endpoint. + */ + GrapeAPIClass getAPIClass() { result = apiClass } + + /** + * Gets the block containing the endpoint logic. + */ + DataFlow::BlockNode getBody() { result = this.getBlock() } + + /** + * Gets the path pattern for this endpoint, if specified. + */ + string getPath() { + result = this.getArgument(0).getConstantValue().getString() + } +} + +/** + * A `RemoteFlowSource::Range` to represent accessing the + * Grape parameters available via the `params` method within an endpoint. + */ +class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { + GrapeParamsSource() { + this.asExpr().getExpr() instanceof GrapeParamsCall + } + + override string getSourceType() { result = "Grape::API#params" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } +} + +/** + * A call to `params` from within a Grape API endpoint. + */ +private class GrapeParamsCall extends ParamsCallImpl { + GrapeParamsCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "params" + ) + or + // Also handle cases where params is called on an instance of a Grape API class + this = grapeAPIInstance().getAMethodCall("params").asExpr().getExpr() + } +} + +/** + * A call to `headers` from within a Grape API endpoint. + * Headers can also be a source of user input. + */ +class GrapeHeadersSource extends Http::Server::RequestInputAccess::Range { + GrapeHeadersSource() { + this.asExpr().getExpr() instanceof GrapeHeadersCall + } + + override string getSourceType() { result = "Grape::API#headers" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } +} + +/** + * A call to `headers` from within a Grape API endpoint. + */ +private class GrapeHeadersCall extends MethodCall { + GrapeHeadersCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "headers" + ) + or + // Also handle cases where headers is called on an instance of a Grape API class + this = grapeAPIInstance().getAMethodCall("headers").asExpr().getExpr() + } +} + +/** + * A call to `request` from within a Grape API endpoint. + * The request object can contain user input. + */ +class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { + GrapeRequestSource() { + this.asExpr().getExpr() instanceof GrapeRequestCall + } + + override string getSourceType() { result = "Grape::API#request" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } +} + +/** + * A call to `request` from within a Grape API endpoint. + */ +private class GrapeRequestCall extends MethodCall { + GrapeRequestCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "request" + ) + or + // Also handle cases where request is called on an instance of a Grape API class + this = grapeAPIInstance().getAMethodCall("request").asExpr().getExpr() + } +} \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected new file mode 100644 index 00000000000..904cb36333a --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -0,0 +1,25 @@ +grapeAPIClasses +| app.rb:1:1:48:3 | MyAPI | +| app.rb:50:1:54:3 | AdminAPI | +grapeEndpoints +| app.rb:1:1:48:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name | +| app.rb:1:1:48:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages | +| app.rb:1:1:48:3 | MyAPI | app.rb:23:3:27:5 | call to put | PUT | /update/:id | +| app.rb:1:1:48:3 | MyAPI | app.rb:30:3:32:5 | call to delete | DELETE | /items/:id | +| app.rb:1:1:48:3 | MyAPI | app.rb:35:3:37:5 | call to patch | PATCH | /items/:id | +| app.rb:1:1:48:3 | MyAPI | app.rb:40:3:42:5 | call to head | HEAD | /status | +| app.rb:1:1:48:3 | MyAPI | app.rb:45:3:47:5 | call to options | OPTIONS | /info | +| app.rb:50:1:54:3 | AdminAPI | app.rb:51:3:53:5 | call to get | GET | /admin | +grapeParams +| app.rb:8:12:8:17 | call to params | +| app.rb:14:3:16:5 | call to params | +| app.rb:18:11:18:16 | call to params | +| app.rb:24:10:24:15 | call to params | +| app.rb:31:5:31:10 | call to params | +| app.rb:36:5:36:10 | call to params | +| app.rb:52:5:52:10 | call to params | +grapeHeaders +| app.rb:9:18:9:24 | call to headers | +| app.rb:46:5:46:11 | call to headers | +grapeRequest +| app.rb:25:12:25:18 | call to request | \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql new file mode 100644 index 00000000000..a35c639d9ad --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -0,0 +1,18 @@ +import ruby +import codeql.ruby.frameworks.Grape +import codeql.ruby.Concepts +import codeql.ruby.AST + +query predicate grapeAPIClasses(GrapeAPIClass api) { any() } + +query predicate grapeEndpoints(GrapeAPIClass api, GrapeEndpoint endpoint, string method, string path) { + endpoint = api.getAnEndpoint() and + method = endpoint.getHttpMethod() and + path = endpoint.getPath() +} + +query predicate grapeParams(GrapeParamsSource params) { any() } + +query predicate grapeHeaders(GrapeHeadersSource headers) { any() } + +query predicate grapeRequest(GrapeRequestSource request) { any() } \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb new file mode 100644 index 00000000000..3e33caa85e9 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -0,0 +1,54 @@ +class MyAPI < Grape::API + version 'v1', using: :header, vendor: 'myapi' + format :json + prefix :api + + desc 'Simple get endpoint' + get '/hello/:name' do + name = params[:name] + user_agent = headers['User-Agent'] + "Hello #{name}!" + end + + desc 'Post endpoint with params' + params do + requires :message, type: String + end + post '/messages' do + msg = params[:message] + { status: 'received', message: msg } + end + + desc 'Put endpoint accessing request' + put '/update/:id' do + id = params[:id] + body = request.body.read + { id: id, body: body } + end + + desc 'Delete endpoint' + delete '/items/:id' do + params[:id] + end + + desc 'Patch endpoint' + patch '/items/:id' do + params[:id] + end + + desc 'Head endpoint' + head '/status' do + # Just return status + end + + desc 'Options endpoint' + options '/info' do + headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' + end +end + +class AdminAPI < Grape::API + get '/admin' do + params[:token] + end +end \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb index 1cd6782b241..30832894b9e 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb @@ -6,4 +6,13 @@ class PotatoController < ActionController::Base sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") end +end + +class PotatoAPI < Grape::API + get '/unsafe_endpoint' do + name = params[:user_name] + # BAD: SQL statement constructed from user input + sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") + sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") + end end \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 069cb34810f..b8b1350882d 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -81,6 +81,10 @@ edges | ArelInjection.rb:4:5:4:8 | name | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:4:12:4:29 | ...[...] | provenance | | | ArelInjection.rb:4:12:4:29 | ...[...] | ArelInjection.rb:4:5:4:8 | name | provenance | | +| ArelInjection.rb:13:5:13:8 | name | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:13:5:13:8 | name | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:13:12:13:29 | ...[...] | provenance | | +| ArelInjection.rb:13:12:13:29 | ...[...] | ArelInjection.rb:13:5:13:8 | name | provenance | | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 : String | provenance | AdditionalTaintStep | @@ -209,6 +213,11 @@ nodes | ArelInjection.rb:4:12:4:29 | ...[...] | semmle.label | ...[...] | | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | +| ArelInjection.rb:13:5:13:8 | name | semmle.label | name | +| ArelInjection.rb:13:12:13:17 | call to params | semmle.label | call to params | +| ArelInjection.rb:13:12:13:29 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | +| ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | | PgInjection.rb:6:5:6:8 | name | semmle.label | name | | PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params | | PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] | @@ -266,6 +275,8 @@ subpaths | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | ActiveRecordInjection.rb:222:29:222:34 | call to params | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:222:29:222:34 | call to params | user-provided value | | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | +| ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | +| ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | | PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | From 738ab6fba7ff64b97c60cf7f2593f136c5bf0f04 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Sep 2025 19:23:15 -0400 Subject: [PATCH 04/90] Refactor Grape framework code for improved readability and consistency --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 2 +- .../test/library-tests/frameworks/grape/Grape.ql | 2 +- .../test/library-tests/frameworks/grape/app.rb | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 8e9a062dc9a..857b849f425 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -115,7 +115,7 @@ class GrapeEndpoint extends DataFlow::CallNode { * Grape parameters available via the `params` method within an endpoint. */ class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { - GrapeParamsSource() { + GrapeParamsSource() { this.asExpr().getExpr() instanceof GrapeParamsCall } diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index a35c639d9ad..3dd7c488a49 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -5,7 +5,7 @@ import codeql.ruby.AST query predicate grapeAPIClasses(GrapeAPIClass api) { any() } -query predicate grapeEndpoints(GrapeAPIClass api, GrapeEndpoint endpoint, string method, string path) { +query predicate grapeEndpoints(GrapeAPIClass api, GrapeEndpoint endpoint, string method, string path) { endpoint = api.getAnEndpoint() and method = endpoint.getHttpMethod() and path = endpoint.getPath() diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb index 3e33caa85e9..6333240debe 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/app.rb +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -9,7 +9,7 @@ class MyAPI < Grape::API user_agent = headers['User-Agent'] "Hello #{name}!" end - + desc 'Post endpoint with params' params do requires :message, type: String @@ -18,36 +18,36 @@ class MyAPI < Grape::API msg = params[:message] { status: 'received', message: msg } end - + desc 'Put endpoint accessing request' put '/update/:id' do id = params[:id] body = request.body.read { id: id, body: body } end - - desc 'Delete endpoint' + + desc 'Delete endpoint' delete '/items/:id' do params[:id] end - + desc 'Patch endpoint' patch '/items/:id' do params[:id] end - + desc 'Head endpoint' head '/status' do # Just return status end - + desc 'Options endpoint' options '/info' do headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' end end -class AdminAPI < Grape::API +class AdminAPI < Grape::API get '/admin' do params[:token] end From 3252bd39d2e671710e94ada3adaae1cefb1deaf1 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Sep 2025 22:13:21 -0400 Subject: [PATCH 05/90] Enhance Grape framework with additional data flow modeling and helper method support --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 57 +++++++++++++++---- .../frameworks/grape/Grape.expected | 2 +- .../security/cwe-089/ArelInjection.rb | 25 +++++++- .../security/cwe-089/SqlInjection.expected | 20 +++++++ 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 857b849f425..a3aa2f684c7 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -12,6 +12,7 @@ private import codeql.ruby.typetracking.TypeTracking private import codeql.ruby.frameworks.Rails private import codeql.ruby.frameworks.internal.Rails private import codeql.ruby.dataflow.internal.DataFlowDispatch +private import codeql.ruby.dataflow.FlowSteps /** * Provides modeling for Grape, a REST-like API framework for Ruby. @@ -125,21 +126,17 @@ class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { } /** - * A call to `params` from within a Grape API endpoint. + * A call to `params` from within a Grape API endpoint or helper method. */ private class GrapeParamsCall extends ParamsCallImpl { GrapeParamsCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "params" + // Simplified approach: find params calls that are descendants of Grape API class methods + exists(GrapeAPIClass api | + this.getMethodName() = "params" and + this.getParent+() = api.getADeclaration() ) - or - // Also handle cases where params is called on an instance of a Grape API class - this = grapeAPIInstance().getAMethodCall("params").asExpr().getExpr() } -} - -/** +}/** * A call to `headers` from within a Grape API endpoint. * Headers can also be a source of user input. */ @@ -195,4 +192,44 @@ private class GrapeRequestCall extends MethodCall { // Also handle cases where request is called on an instance of a Grape API class this = grapeAPIInstance().getAMethodCall("request").asExpr().getExpr() } +} + +/** + * A method defined within a `helpers` block in a Grape API class. + * These methods become available in endpoint contexts through Grape's DSL. + */ +private class GrapeHelperMethod extends Method { + private GrapeAPIClass apiClass; + + GrapeHelperMethod() { + exists(DataFlow::CallNode helpersCall | + helpersCall = apiClass.getAModuleLevelCall("helpers") and + this.getParent+() = helpersCall.getBlock().asExpr().getExpr() + ) + } + + /** + * Gets the API class that contains this helper method. + */ + GrapeAPIClass getAPIClass() { result = apiClass } +} + +/** + * Additional taint step to model dataflow from method arguments to parameters + * for Grape helper methods defined in `helpers` blocks. + * This bridges the gap where standard dataflow doesn't recognize the Grape DSL semantics. + */ +private class GrapeHelperMethodTaintStep extends AdditionalTaintStep { + override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + exists(GrapeHelperMethod helperMethod, MethodCall call, int i | + // Find calls to helper methods from within Grape endpoints + call.getMethodName() = helperMethod.getName() and + exists(GrapeEndpoint endpoint | + call.getParent+() = endpoint.getBody().asExpr().getExpr() + ) and + // Map argument to parameter + nodeFrom.asExpr().getExpr() = call.getArgument(i) and + nodeTo.asParameter() = helperMethod.getParameter(i) + ) + } } \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected index 904cb36333a..7e792465911 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -22,4 +22,4 @@ grapeHeaders | app.rb:9:18:9:24 | call to headers | | app.rb:46:5:46:11 | call to headers | grapeRequest -| app.rb:25:12:25:18 | call to request | \ No newline at end of file +| app.rb:25:12:25:18 | call to request | diff --git a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb index 30832894b9e..cf0769c0acd 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb @@ -15,4 +15,27 @@ class PotatoAPI < Grape::API sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") end -end \ No newline at end of file +end + +class SimpleAPI < Grape::API + get '/test' do + x = params[:name] + Arel.sql("SELECT * FROM users WHERE name = #{x}") + end +end + + # Test helper method pattern in Grape helpers block + class TestAPI < Grape::API + helpers do + def vulnerable_helper(user_id) + # BAD: SQL statement constructed from user input passed as parameter + Arel.sql("SELECT * FROM users WHERE id = #{user_id}") + end + end + + get '/helper_test' do + # This should be detected as SQL injection via helper method + user_id = params[:user_id] + vulnerable_helper(user_id) + end + end \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index b8b1350882d..0b14504058e 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -85,6 +85,14 @@ edges | ArelInjection.rb:13:5:13:8 | name | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:13:12:13:29 | ...[...] | provenance | | | ArelInjection.rb:13:12:13:29 | ...[...] | ArelInjection.rb:13:5:13:8 | name | provenance | | +| ArelInjection.rb:22:5:22:5 | x | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:22:9:22:21 | ...[...] | provenance | | +| ArelInjection.rb:22:9:22:21 | ...[...] | ArelInjection.rb:22:5:22:5 | x | provenance | | +| ArelInjection.rb:30:29:30:35 | user_id | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:38:7:38:13 | user_id | ArelInjection.rb:39:25:39:31 | user_id | provenance | | +| ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:38:17:38:32 | ...[...] | provenance | | +| ArelInjection.rb:38:17:38:32 | ...[...] | ArelInjection.rb:38:7:38:13 | user_id | provenance | | +| ArelInjection.rb:39:25:39:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 : String | provenance | AdditionalTaintStep | @@ -218,6 +226,16 @@ nodes | ArelInjection.rb:13:12:13:29 | ...[...] | semmle.label | ...[...] | | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | +| ArelInjection.rb:22:5:22:5 | x | semmle.label | x | +| ArelInjection.rb:22:9:22:14 | call to params | semmle.label | call to params | +| ArelInjection.rb:22:9:22:21 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | +| ArelInjection.rb:30:29:30:35 | user_id | semmle.label | user_id | +| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ArelInjection.rb:38:7:38:13 | user_id | semmle.label | user_id | +| ArelInjection.rb:38:17:38:22 | call to params | semmle.label | call to params | +| ArelInjection.rb:38:17:38:32 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:39:25:39:31 | user_id | semmle.label | user_id | | PgInjection.rb:6:5:6:8 | name | semmle.label | name | | PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params | | PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] | @@ -277,6 +295,8 @@ subpaths | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | +| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:22:9:22:14 | call to params | user-provided value | +| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:38:17:38:22 | call to params | user-provided value | | PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | From 5cfa6e83b390aafe6783eba0e282674a8247db46 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Sep 2025 22:51:47 -0400 Subject: [PATCH 06/90] Add support for route parameters(+ blocks), headers, and cookies in Grape API --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 92 ++++++++++++++++++- .../frameworks/grape/Grape.expected | 37 +++++--- .../library-tests/frameworks/grape/Grape.ql | 6 +- .../library-tests/frameworks/grape/app.rb | 42 +++++++++ .../security/cwe-089/ArelInjection.rb | 32 ++++++- .../security/cwe-089/SqlInjection.expected | 53 +++++++++-- 6 files changed, 239 insertions(+), 23 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index a3aa2f684c7..fbab28180b8 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -137,12 +137,14 @@ private class GrapeParamsCall extends ParamsCallImpl { ) } }/** - * A call to `headers` from within a Grape API endpoint. + * A call to `headers` from within a Grape API endpoint or headers block. * Headers can also be a source of user input. */ class GrapeHeadersSource extends Http::Server::RequestInputAccess::Range { GrapeHeadersSource() { this.asExpr().getExpr() instanceof GrapeHeadersCall + or + this.asExpr().getExpr() instanceof GrapeHeadersBlockCall } override string getSourceType() { result = "Grape::API#headers" } @@ -179,6 +181,20 @@ class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } } +/** + * A call to `route_param` from within a Grape API endpoint. + * Route parameters are extracted from the URL path and can be a source of user input. + */ +class GrapeRouteParamSource extends Http::Server::RequestInputAccess::Range { + GrapeRouteParamSource() { + this.asExpr().getExpr() instanceof GrapeRouteParamCall + } + + override string getSourceType() { result = "Grape::API#route_param" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } +} + /** * A call to `request` from within a Grape API endpoint. */ @@ -194,6 +210,80 @@ private class GrapeRequestCall extends MethodCall { } } +/** + * A call to `route_param` from within a Grape API endpoint. + */ +private class GrapeRouteParamCall extends MethodCall { + GrapeRouteParamCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asExpr().getExpr() and + this.getMethodName() = "route_param" + ) + or + // Also handle cases where route_param is called on an instance of a Grape API class + this = grapeAPIInstance().getAMethodCall("route_param").asExpr().getExpr() + } +} + +/** + * A call to `headers` block within a Grape API class. + * This is different from the headers() method call - this is the DSL block for defining header requirements. + */ +private class GrapeHeadersBlockCall extends MethodCall { + GrapeHeadersBlockCall() { + exists(GrapeAPIClass api | + this.getParent+() = api.getADeclaration() and + this.getMethodName() = "headers" and + exists(this.getBlock()) + ) + } +} + +/** + * A call to `cookies` block within a Grape API class. + * This DSL block defines cookie requirements and those cookies are user-controlled. + */ +private class GrapeCookiesBlockCall extends MethodCall { + GrapeCookiesBlockCall() { + exists(GrapeAPIClass api | + this.getParent+() = api.getADeclaration() and + this.getMethodName() = "cookies" and + exists(this.getBlock()) + ) + } +} + +/** + * A call to `cookies` method from within a Grape API endpoint or cookies block. + * Similar to headers, cookies can be accessed as a method and are user-controlled input. + */ +class GrapeCookiesSource extends Http::Server::RequestInputAccess::Range { + GrapeCookiesSource() { + this.asExpr().getExpr() instanceof GrapeCookiesCall + or + this.asExpr().getExpr() instanceof GrapeCookiesBlockCall + } + + override string getSourceType() { result = "Grape::API#cookies" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::cookieInputKind() } +} + +/** + * A call to `cookies` method from within a Grape API endpoint. + */ +private class GrapeCookiesCall extends MethodCall { + GrapeCookiesCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "cookies" + ) + or + // Also handle cases where cookies is called on an instance of a Grape API class + this = grapeAPIInstance().getAMethodCall("cookies").asExpr().getExpr() + } +} + /** * A method defined within a `helpers` block in a Grape API class. * These methods become available in endpoint contexts through Grape's DSL. diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected index 7e792465911..c0bee75371c 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -1,15 +1,18 @@ grapeAPIClasses -| app.rb:1:1:48:3 | MyAPI | -| app.rb:50:1:54:3 | AdminAPI | +| app.rb:1:1:90:3 | MyAPI | +| app.rb:92:1:96:3 | AdminAPI | grapeEndpoints -| app.rb:1:1:48:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name | -| app.rb:1:1:48:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages | -| app.rb:1:1:48:3 | MyAPI | app.rb:23:3:27:5 | call to put | PUT | /update/:id | -| app.rb:1:1:48:3 | MyAPI | app.rb:30:3:32:5 | call to delete | DELETE | /items/:id | -| app.rb:1:1:48:3 | MyAPI | app.rb:35:3:37:5 | call to patch | PATCH | /items/:id | -| app.rb:1:1:48:3 | MyAPI | app.rb:40:3:42:5 | call to head | HEAD | /status | -| app.rb:1:1:48:3 | MyAPI | app.rb:45:3:47:5 | call to options | OPTIONS | /info | -| app.rb:50:1:54:3 | AdminAPI | app.rb:51:3:53:5 | call to get | GET | /admin | +| app.rb:1:1:90:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name | +| app.rb:1:1:90:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages | +| app.rb:1:1:90:3 | MyAPI | app.rb:23:3:27:5 | call to put | PUT | /update/:id | +| app.rb:1:1:90:3 | MyAPI | app.rb:30:3:32:5 | call to delete | DELETE | /items/:id | +| app.rb:1:1:90:3 | MyAPI | app.rb:35:3:37:5 | call to patch | PATCH | /items/:id | +| app.rb:1:1:90:3 | MyAPI | app.rb:40:3:42:5 | call to head | HEAD | /status | +| app.rb:1:1:90:3 | MyAPI | app.rb:45:3:47:5 | call to options | OPTIONS | /info | +| app.rb:1:1:90:3 | MyAPI | app.rb:50:3:54:5 | call to get | GET | /users/:user_id/posts/:post_id | +| app.rb:1:1:90:3 | MyAPI | app.rb:78:3:82:5 | call to get | GET | /cookie_test | +| app.rb:1:1:90:3 | MyAPI | app.rb:85:3:89:5 | call to get | GET | /header_test | +| app.rb:92:1:96:3 | AdminAPI | app.rb:93:3:95:5 | call to get | GET | /admin | grapeParams | app.rb:8:12:8:17 | call to params | | app.rb:14:3:16:5 | call to params | @@ -17,9 +20,21 @@ grapeParams | app.rb:24:10:24:15 | call to params | | app.rb:31:5:31:10 | call to params | | app.rb:36:5:36:10 | call to params | -| app.rb:52:5:52:10 | call to params | +| app.rb:60:12:60:17 | call to params | +| app.rb:94:5:94:10 | call to params | grapeHeaders | app.rb:9:18:9:24 | call to headers | | app.rb:46:5:46:11 | call to headers | +| app.rb:66:3:69:5 | call to headers | +| app.rb:86:12:86:18 | call to headers | +| app.rb:87:14:87:20 | call to headers | grapeRequest | app.rb:25:12:25:18 | call to request | +grapeRouteParam +| app.rb:51:15:51:35 | call to route_param | +| app.rb:52:15:52:36 | call to route_param | +| app.rb:57:3:63:5 | call to route_param | +grapeCookies +| app.rb:72:3:75:5 | call to cookies | +| app.rb:79:15:79:21 | call to cookies | +| app.rb:80:16:80:22 | call to cookies | diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index 3dd7c488a49..63d59d0bdd7 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -15,4 +15,8 @@ query predicate grapeParams(GrapeParamsSource params) { any() } query predicate grapeHeaders(GrapeHeadersSource headers) { any() } -query predicate grapeRequest(GrapeRequestSource request) { any() } \ No newline at end of file +query predicate grapeRequest(GrapeRequestSource request) { any() } + +query predicate grapeRouteParam(GrapeRouteParamSource routeParam) { any() } + +query predicate grapeCookies(GrapeCookiesSource cookies) { any() } \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb index 6333240debe..a034f325f7b 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/app.rb +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -45,6 +45,48 @@ class MyAPI < Grape::API options '/info' do headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' end + + desc 'Route param endpoint' + get '/users/:user_id/posts/:post_id' do + user_id = route_param(:user_id) + post_id = route_param('post_id') + { user_id: user_id, post_id: post_id } + end + + desc 'Route param block pattern' + route_param :id do + get do + # params[:id] is user input from the path parameter + id = params[:id] + { id: id } + end + end + + # Headers block for defining expected headers + headers do + requires :Authorization, type: String + optional 'X-Custom-Header', type: String + end + + # Cookies block for defining expected cookies + cookies do + requires :session_id, type: String + optional :tracking_id, type: String + end + + desc 'Endpoint that uses cookies method' + get '/cookie_test' do + session = cookies[:session_id] + tracking = cookies['tracking_id'] + { session: session, tracking: tracking } + end + + desc 'Endpoint that uses headers method' + get '/header_test' do + auth = headers[:Authorization] + custom = headers['X-Custom-Header'] + { auth: auth, custom: custom } + end end class AdminAPI < Grape::API diff --git a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb index cf0769c0acd..8c9c3bff4fb 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb @@ -33,9 +33,39 @@ end end end + # Headers and cookies blocks for DSL testing + headers do + requires :Authorization, type: String + end + + cookies do + requires :session_id, type: String + end + + get '/comprehensive_test/:user_id' do + # BAD: Comprehensive test using all Grape input sources in one SQL query + user_id = params[:user_id] # params taint source + route_id = route_param(:user_id) # route_param taint source + auth = headers[:Authorization] # headers taint source + session = cookies[:session_id] # cookies taint source + body_data = request.body.read # request taint source + + # All sources flow to SQL injection + Arel.sql("SELECT * FROM users WHERE id = #{user_id} AND route_id = #{route_id} AND auth = #{auth} AND session = #{session} AND data = #{body_data}") + end + get '/helper_test' do - # This should be detected as SQL injection via helper method + # BAD: Test helper method dataflow user_id = params[:user_id] vulnerable_helper(user_id) end + + # Test route_param block pattern + route_param :id do + get do + # BAD: params[:id] should be user input from the path + user_id = params[:id] + Arel.sql("SELECT * FROM users WHERE id = #{user_id}") + end + end end \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 0b14504058e..34128474cb9 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -89,10 +89,24 @@ edges | ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:22:9:22:21 | ...[...] | provenance | | | ArelInjection.rb:22:9:22:21 | ...[...] | ArelInjection.rb:22:5:22:5 | x | provenance | | | ArelInjection.rb:30:29:30:35 | user_id | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:38:7:38:13 | user_id | ArelInjection.rb:39:25:39:31 | user_id | provenance | | -| ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:38:17:38:32 | ...[...] | provenance | | -| ArelInjection.rb:38:17:38:32 | ...[...] | ArelInjection.rb:38:7:38:13 | user_id | provenance | | -| ArelInjection.rb:39:25:39:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep | +| ArelInjection.rb:47:7:47:13 | user_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:47:17:47:32 | ...[...] | provenance | | +| ArelInjection.rb:47:17:47:32 | ...[...] | ArelInjection.rb:47:7:47:13 | user_id | provenance | | +| ArelInjection.rb:48:7:48:14 | route_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:48:7:48:14 | route_id | provenance | | +| ArelInjection.rb:49:7:49:10 | auth | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:49:14:49:36 | ...[...] | provenance | | +| ArelInjection.rb:49:14:49:36 | ...[...] | ArelInjection.rb:49:7:49:10 | auth | provenance | | +| ArelInjection.rb:50:7:50:13 | session | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:50:17:50:36 | ...[...] | provenance | | +| ArelInjection.rb:50:17:50:36 | ...[...] | ArelInjection.rb:50:7:50:13 | session | provenance | | +| ArelInjection.rb:59:7:59:13 | user_id | ArelInjection.rb:60:25:60:31 | user_id | provenance | | +| ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:59:17:59:32 | ...[...] | provenance | | +| ArelInjection.rb:59:17:59:32 | ...[...] | ArelInjection.rb:59:7:59:13 | user_id | provenance | | +| ArelInjection.rb:60:25:60:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep | +| ArelInjection.rb:67:9:67:15 | user_id | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:67:19:67:29 | ...[...] | provenance | | +| ArelInjection.rb:67:19:67:29 | ...[...] | ArelInjection.rb:67:9:67:15 | user_id | provenance | | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 : String | provenance | AdditionalTaintStep | @@ -232,10 +246,26 @@ nodes | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | | ArelInjection.rb:30:29:30:35 | user_id | semmle.label | user_id | | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | -| ArelInjection.rb:38:7:38:13 | user_id | semmle.label | user_id | -| ArelInjection.rb:38:17:38:22 | call to params | semmle.label | call to params | -| ArelInjection.rb:38:17:38:32 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:39:25:39:31 | user_id | semmle.label | user_id | +| ArelInjection.rb:47:7:47:13 | user_id | semmle.label | user_id | +| ArelInjection.rb:47:17:47:22 | call to params | semmle.label | call to params | +| ArelInjection.rb:47:17:47:32 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:48:7:48:14 | route_id | semmle.label | route_id | +| ArelInjection.rb:48:18:48:38 | call to route_param | semmle.label | call to route_param | +| ArelInjection.rb:49:7:49:10 | auth | semmle.label | auth | +| ArelInjection.rb:49:14:49:20 | call to headers | semmle.label | call to headers | +| ArelInjection.rb:49:14:49:36 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:50:7:50:13 | session | semmle.label | session | +| ArelInjection.rb:50:17:50:23 | call to cookies | semmle.label | call to cookies | +| ArelInjection.rb:50:17:50:36 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ArelInjection.rb:59:7:59:13 | user_id | semmle.label | user_id | +| ArelInjection.rb:59:17:59:22 | call to params | semmle.label | call to params | +| ArelInjection.rb:59:17:59:32 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:60:25:60:31 | user_id | semmle.label | user_id | +| ArelInjection.rb:67:9:67:15 | user_id | semmle.label | user_id | +| ArelInjection.rb:67:19:67:24 | call to params | semmle.label | call to params | +| ArelInjection.rb:67:19:67:29 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | | PgInjection.rb:6:5:6:8 | name | semmle.label | name | | PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params | | PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] | @@ -296,7 +326,12 @@ subpaths | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:22:9:22:14 | call to params | user-provided value | -| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:38:17:38:22 | call to params | user-provided value | +| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:59:17:59:22 | call to params | user-provided value | +| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:47:17:47:22 | call to params | user-provided value | +| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:48:18:48:38 | call to route_param | user-provided value | +| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:49:14:49:20 | call to headers | user-provided value | +| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:50:17:50:23 | call to cookies | user-provided value | +| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:67:19:67:24 | call to params | user-provided value | | PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | From 459f00ab415e1263c0756a03516e51e9963adc52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:25:11 +0000 Subject: [PATCH 07/90] Initial plan From e630bf86bdd0f9a678b234f04f11f4ba883b5571 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:44:05 +0000 Subject: [PATCH 08/90] Implement Rust non-HTTPS URL query (CWE-319) Co-authored-by: geoffw0 <40627776+geoffw0@users.noreply.github.com> --- .../rust-code-scanning.qls.expected | 1 + .../rust-security-and-quality.qls.expected | 1 + .../rust-security-extended.qls.expected | 1 + .../rust/security/UseOfHttpExtensions.qll | 60 + .../change-notes/2025-09-15-non-https-url.md | 4 + .../queries/security/CWE-319/UseOfHttp.qhelp | 48 + .../src/queries/security/CWE-319/UseOfHttp.ql | 42 + .../queries/security/CWE-319/UseOfHttpBad.rs | 10 + .../queries/security/CWE-319/UseOfHttpGood.rs | 10 + rust/ql/src/queries/summary/Stats.qll | 1 + .../query-tests/security/CWE-319/Cargo.lock | 1574 +++++++++++++++++ .../security/CWE-319/UseOfHttp.expected | 78 + .../security/CWE-319/UseOfHttp.qlref | 4 + .../test/query-tests/security/CWE-319/main.rs | 65 + .../query-tests/security/CWE-319/options.yml | 3 + 15 files changed, 1902 insertions(+) create mode 100644 rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll create mode 100644 rust/ql/src/change-notes/2025-09-15-non-https-url.md create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttp.ql create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs create mode 100644 rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs create mode 100644 rust/ql/test/query-tests/security/CWE-319/Cargo.lock create mode 100644 rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected create mode 100644 rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref create mode 100644 rust/ql/test/query-tests/security/CWE-319/main.rs create mode 100644 rust/ql/test/query-tests/security/CWE-319/options.yml diff --git a/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected b/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected index b601905e6a3..1b8e1015a1f 100644 --- a/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-code-scanning.qls.expected @@ -14,6 +14,7 @@ ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql diff --git a/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected b/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected index 074cb2ec888..a2d2e2b820c 100644 --- a/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-security-and-quality.qls.expected @@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql diff --git a/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected b/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected index 38846e281eb..9000990ad84 100644 --- a/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected +++ b/rust/ql/integration-tests/query-suite/rust-security-extended.qls.expected @@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql +ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll new file mode 100644 index 00000000000..026880785b6 --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -0,0 +1,60 @@ +/** + * Provides classes and predicates for reasoning about the use of + * non-HTTPS URLs in Rust code. + */ + +import rust +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.FlowSink +private import codeql.rust.elements.LiteralExprExt +private import codeql.rust.Concepts + +/** + * Provides default sources, sinks and barriers for detecting use of + * non-HTTPS URLs, as well as extension points for adding your own. + */ +module UseOfHttp { + /** + * A data flow source for use of non-HTTPS URLs. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for use of non-HTTPS URLs. + */ + abstract class Sink extends QuerySink::Range { + override string getSinkType() { result = "UseOfHttp" } + } + + /** + * A barrier for use of non-HTTPS URLs. + */ + abstract class Barrier extends DataFlow::Node { } + + /** + * A string containing an HTTP URL. + */ + class HttpStringLiteral extends StringLiteralExpr { + HttpStringLiteral() { + exists(string s | this.getTextValue() = s | + // Match HTTP URLs that are not private/local + s.regexpMatch("\"http://.*\"") and + not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.16\\.[0-9]+\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + ) + } + } + + /** + * An HTTP string literal as a source. + */ + private class HttpStringLiteralAsSource extends Source { + HttpStringLiteralAsSource() { this.asExpr().getExpr() instanceof HttpStringLiteral } + } + + /** + * A sink for use of HTTP URLs from model data. + */ + private class ModelsAsDataSink extends Sink { + ModelsAsDataSink() { sinkNode(this, "request-url") } + } +} diff --git a/rust/ql/src/change-notes/2025-09-15-non-https-url.md b/rust/ql/src/change-notes/2025-09-15-non-https-url.md new file mode 100644 index 00000000000..c4ab664f732 --- /dev/null +++ b/rust/ql/src/change-notes/2025-09-15-non-https-url.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties. \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp new file mode 100644 index 00000000000..a8ca1d9c7c7 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -0,0 +1,48 @@ + + + + +

Constructing URLs with the HTTP protocol can lead to unsecured connections.

+ +

Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the +code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, +which may fail or fall back to insecure behavior when provided with HTTP URLs instead of HTTPS URLs.

+ +
+ + +

When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. +Then, any connections that are made using that URL are secure SSL/TLS connections.

+ +
+ + +

The following example shows two ways of making a network request using a URL. When the request is +made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted +by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

+ + + +

A better approach is to use HTTPS:

+ + + +
+ + +
  • +OWASP: +Transport Layer Protection Cheat Sheet. +
  • +
  • +OWASP Top 10: +A08:2021 - Software and Data Integrity Failures. +
  • +
  • Rust reqwest documentation: +reqwest crate. +
  • + +
    +
    \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql b/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql new file mode 100644 index 00000000000..4a464d90bbe --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql @@ -0,0 +1,42 @@ +/** + * @name Failure to use HTTPS URLs + * @description Non-HTTPS connections can be intercepted by third parties. + * @kind path-problem + * @problem.severity warning + * @security-severity 8.1 + * @precision high + * @id rust/non-https-url + * @tags security + * external/cwe/cwe-319 + * external/cwe/cwe-345 + */ + +import rust +import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.TaintTracking +import codeql.rust.security.UseOfHttpExtensions + +/** + * A taint configuration for HTTP URL strings that flow to URL-using sinks. + */ +module UseOfHttpConfig implements DataFlow::ConfigSig { + import UseOfHttp + + predicate isSource(DataFlow::Node node) { node instanceof Source } + + predicate isSink(DataFlow::Node node) { node instanceof Sink } + + predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + + predicate observeDiffInformedIncrementalMode() { any() } +} + +module UseOfHttpFlow = TaintTracking::Global; + +import UseOfHttpFlow::PathGraph + +from UseOfHttpFlow::PathNode sourceNode, UseOfHttpFlow::PathNode sinkNode +where UseOfHttpFlow::flowPath(sourceNode, sinkNode) +select sinkNode.getNode(), sourceNode, sinkNode, + "This URL may be constructed with the HTTP protocol, from $@.", sourceNode.getNode(), + "this HTTP URL" diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs b/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs new file mode 100644 index 00000000000..ada466cae5c --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs @@ -0,0 +1,10 @@ +// BAD: Using HTTP URL which can be intercepted +use reqwest; + +fn main() { + let url = "http://example.com/sensitive-data"; + + // This makes an insecure HTTP request that can be intercepted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); +} \ No newline at end of file diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs b/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs new file mode 100644 index 00000000000..22b94235fa1 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs @@ -0,0 +1,10 @@ +// GOOD: Using HTTPS URL which provides encryption +use reqwest; + +fn main() { + let url = "https://example.com/sensitive-data"; + + // This makes a secure HTTPS request that is encrypted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); +} \ No newline at end of file diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 7a1de4f1314..d49e1fdde5d 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -27,6 +27,7 @@ private import codeql.rust.security.LogInjectionExtensions private import codeql.rust.security.SqlInjectionExtensions private import codeql.rust.security.TaintedPathExtensions private import codeql.rust.security.UncontrolledAllocationSizeExtensions +private import codeql.rust.security.UseOfHttpExtensions private import codeql.rust.security.WeakSensitiveDataHashingExtensions private import codeql.rust.security.HardcodedCryptographicValueExtensions diff --git a/rust/ql/test/query-tests/security/CWE-319/Cargo.lock b/rust/ql/test/query-tests/security/CWE-319/Cargo.lock new file mode 100644 index 00000000000..ad4b5cebd22 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/Cargo.lock @@ -0,0 +1,1574 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.5+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a37813727b78798e53c2bec3f5e8fe12a6d6f8389bf9ca7802add4c9905ad8" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.0", +] + +[[package]] +name = "test" +version = "0.0.1" +dependencies = [ + "reqwest", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.5+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.0+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected new file mode 100644 index 00000000000..53cc8606cc8 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -0,0 +1,78 @@ +#select +| main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | +| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | +| main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | +| main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | +| main.rs:60:21:60:42 | ...::get | main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:60:21:60:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:59:15:59:49 | "http://example.com/sensitive-... | this HTTP URL | +edges +| main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:22:9:22:16 | base_url | main.rs:24:28:24:53 | MacroExpr | provenance | | +| main.rs:22:20:22:39 | "http://example.com" | main.rs:22:9:22:16 | base_url | provenance | | +| main.rs:24:9:24:16 | full_url | main.rs:25:45:25:52 | full_url | provenance | | +| main.rs:24:20:24:26 | res | main.rs:24:28:24:53 | { ... } | provenance | | +| main.rs:24:28:24:53 | ...::format(...) | main.rs:24:20:24:26 | res | provenance | | +| main.rs:24:28:24:53 | ...::must_use(...) | main.rs:24:9:24:16 | full_url | provenance | | +| main.rs:24:28:24:53 | MacroExpr | main.rs:24:28:24:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:24:28:24:53 | { ... } | main.rs:24:28:24:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:25:44:25:52 | &full_url [&ref] | main.rs:25:21:25:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:25:45:25:52 | full_url | main.rs:25:44:25:52 | &full_url [&ref] | provenance | | +| main.rs:33:9:33:16 | protocol | main.rs:35:32:35:53 | MacroExpr | provenance | | +| main.rs:33:20:33:28 | "http://" | main.rs:33:9:33:16 | protocol | provenance | | +| main.rs:35:9:35:20 | insecure_url | main.rs:36:54:36:65 | insecure_url | provenance | | +| main.rs:35:24:35:30 | res | main.rs:35:32:35:53 | { ... } | provenance | | +| main.rs:35:32:35:53 | ...::format(...) | main.rs:35:24:35:30 | res | provenance | | +| main.rs:35:32:35:53 | ...::must_use(...) | main.rs:35:9:35:20 | insecure_url | provenance | | +| main.rs:35:32:35:53 | MacroExpr | main.rs:35:32:35:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | +| main.rs:59:9:59:11 | url | main.rs:60:44:60:46 | url | provenance | | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:59:9:59:11 | url | provenance | | +| main.rs:60:44:60:46 | url | main.rs:60:21:60:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +models +| 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | +| 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 3 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | +nodes +| main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | +| main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | +| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | +| main.rs:13:45:13:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | +| main.rs:22:9:22:16 | base_url | semmle.label | base_url | +| main.rs:22:20:22:39 | "http://example.com" | semmle.label | "http://example.com" | +| main.rs:24:9:24:16 | full_url | semmle.label | full_url | +| main.rs:24:20:24:26 | res | semmle.label | res | +| main.rs:24:28:24:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:24:28:24:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:24:28:24:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:24:28:24:53 | { ... } | semmle.label | { ... } | +| main.rs:25:21:25:42 | ...::get | semmle.label | ...::get | +| main.rs:25:44:25:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | +| main.rs:25:45:25:52 | full_url | semmle.label | full_url | +| main.rs:33:9:33:16 | protocol | semmle.label | protocol | +| main.rs:33:20:33:28 | "http://" | semmle.label | "http://" | +| main.rs:35:9:35:20 | insecure_url | semmle.label | insecure_url | +| main.rs:35:24:35:30 | res | semmle.label | res | +| main.rs:35:32:35:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:35:32:35:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:35:32:35:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:35:32:35:53 | { ... } | semmle.label | { ... } | +| main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | +| main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | +| main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | +| main.rs:59:9:59:11 | url | semmle.label | url | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | +| main.rs:60:44:60:46 | url | semmle.label | url | +subpaths +testFailures +| main.rs:22:20:22:39 | "http://example.com" | Unexpected result: Source | +| main.rs:22:42:22:71 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:25:21:25:42 | ...::get | Unexpected result: Alert | +| main.rs:33:20:33:28 | "http://" | Unexpected result: Source | +| main.rs:33:31:33:60 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:36:30:36:51 | ...::get | Unexpected result: Alert | +| main.rs:59:15:59:49 | "http://example.com/sensitive-... | Unexpected result: Source | +| main.rs:59:52:59:81 | //... | Missing result: Alert[rust/non-https-url] | +| main.rs:60:21:60:42 | ...::get | Unexpected result: Alert | diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref new file mode 100644 index 00000000000..90b53330019 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.qlref @@ -0,0 +1,4 @@ +query: queries/security/CWE-319/UseOfHttp.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs new file mode 100644 index 00000000000..ae58967a49b --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -0,0 +1,65 @@ +use reqwest; +use std::env; + +fn main() { + test_direct_literals(); + test_dynamic_urls(); + test_localhost_exemptions(); +} + +fn test_direct_literals() { + // BAD: Direct HTTP URLs that should be flagged + let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] + + // GOOD: HTTPS URLs that should not be flagged + let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); + let _response4 = reqwest::blocking::get("https://api.example.com/data").unwrap(); +} + +fn test_dynamic_urls() { + // BAD: HTTP URLs constructed dynamically + let base_url = "http://example.com"; // $ Alert[rust/non-https-url] + let endpoint = "/api/users"; + let full_url = format!("{}{}", base_url, endpoint); + let _response = reqwest::blocking::get(&full_url).unwrap(); + + // GOOD: HTTPS URLs constructed dynamically + let secure_base = "https://example.com"; + let secure_full = format!("{}{}", secure_base, endpoint); + let _secure_response = reqwest::blocking::get(&secure_full).unwrap(); + + // BAD: HTTP protocol string + let protocol = "http://"; // $ Alert[rust/non-https-url] + let host = "api.example.com"; + let insecure_url = format!("{}{}", protocol, host); + let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); + + // GOOD: HTTPS protocol string + let secure_protocol = "https://"; + let secure_url = format!("{}{}", secure_protocol, host); + let _secure_response2 = reqwest::blocking::get(&secure_url).unwrap(); +} + +fn test_localhost_exemptions() { + // GOOD: localhost URLs should not be flagged (local development) + let _local1 = reqwest::blocking::get("http://localhost:8080/api").unwrap(); + let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); + let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); + let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + + // Test IPv6 localhost variants + let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); + let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); +} + +// Additional test cases that mirror the Bad/Good examples +fn test_examples() { + // From UseOfHttpBad.rs - BAD case + let url = "http://example.com/sensitive-data"; // $ Alert[rust/non-https-url] + let _response = reqwest::blocking::get(url).unwrap(); + + // From UseOfHttpGood.rs - GOOD case + let secure_url = "https://example.com/sensitive-data"; + let _secure_response = reqwest::blocking::get(secure_url).unwrap(); +} \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-319/options.yml b/rust/ql/test/query-tests/security/CWE-319/options.yml new file mode 100644 index 00000000000..aa57719603d --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-319/options.yml @@ -0,0 +1,3 @@ +qltest_cargo_check: true +qltest_dependencies: + - reqwest = { version = "0.12.9", features = ["blocking"] } \ No newline at end of file From a8d4d6b5630f7bd4804c51aefd8b0f84ef00ffe1 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:02:03 -0400 Subject: [PATCH 09/90] Apply naming standards + changenote --- .../2025-09-15-grape-framework-support.md | 4 ++ ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 44 +++++++++---------- .../frameworks/grape/Grape.expected | 2 +- .../library-tests/frameworks/grape/Grape.ql | 4 +- 4 files changed, 29 insertions(+), 25 deletions(-) create mode 100644 ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md diff --git a/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md b/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md new file mode 100644 index 00000000000..258da40d36c --- /dev/null +++ b/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Initial modeling for the Ruby Grape framework in `Grape.qll` have been added to detect API endpoints, parameters, and headers within Grape API classes. \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index fbab28180b8..72dd1e13b9b 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -23,9 +23,9 @@ module Grape { * A Grape API class which sits at the top of the class hierarchy. * In other words, it does not subclass any other Grape API class in source code. */ - class RootAPI extends GrapeAPIClass { - RootAPI() { - not exists(GrapeAPIClass parent | this != parent and this = parent.getADescendent()) + class RootApi extends GrapeApiClass { + RootApi() { + not exists(GrapeApiClass parent | this != parent and this = parent.getADescendent()) } } } @@ -43,17 +43,17 @@ module Grape { * end * ``` */ -class GrapeAPIClass extends DataFlow::ClassNode { - GrapeAPIClass() { - this = grapeAPIBaseClass().getADescendentModule() and - not exists(DataFlow::ModuleNode m | m = grapeAPIBaseClass().asModule() | this = m) +class GrapeApiClass extends DataFlow::ClassNode { + GrapeApiClass() { + this = grapeApiBaseClass().getADescendentModule() and + not exists(DataFlow::ModuleNode m | m = grapeApiBaseClass().asModule() | this = m) } /** * Gets a `GrapeEndpoint` defined in this class. */ GrapeEndpoint getAnEndpoint() { - result.getAPIClass() = this + result.getApiClass() = this } /** @@ -68,19 +68,19 @@ class GrapeAPIClass extends DataFlow::ClassNode { } } -private DataFlow::ConstRef grapeAPIBaseClass() { +private DataFlow::ConstRef grapeApiBaseClass() { result = DataFlow::getConstant("Grape").getConstant("API") } -private API::Node grapeAPIInstance() { - result = any(GrapeAPIClass cls).getSelf().track() +private API::Node grapeApiInstance() { + result = any(GrapeApiClass cls).getSelf().track() } /** * A Grape API endpoint (get, post, put, delete, etc.) call within a `Grape::API` class. */ class GrapeEndpoint extends DataFlow::CallNode { - private GrapeAPIClass apiClass; + private GrapeApiClass apiClass; GrapeEndpoint() { this = apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) @@ -96,7 +96,7 @@ class GrapeEndpoint extends DataFlow::CallNode { /** * Gets the API class containing this endpoint. */ - GrapeAPIClass getAPIClass() { result = apiClass } + GrapeApiClass getApiClass() { result = apiClass } /** * Gets the block containing the endpoint logic. @@ -131,7 +131,7 @@ class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { private class GrapeParamsCall extends ParamsCallImpl { GrapeParamsCall() { // Simplified approach: find params calls that are descendants of Grape API class methods - exists(GrapeAPIClass api | + exists(GrapeApiClass api | this.getMethodName() = "params" and this.getParent+() = api.getADeclaration() ) @@ -163,7 +163,7 @@ private class GrapeHeadersCall extends MethodCall { ) or // Also handle cases where headers is called on an instance of a Grape API class - this = grapeAPIInstance().getAMethodCall("headers").asExpr().getExpr() + this = grapeApiInstance().getAMethodCall("headers").asExpr().getExpr() } } @@ -206,7 +206,7 @@ private class GrapeRequestCall extends MethodCall { ) or // Also handle cases where request is called on an instance of a Grape API class - this = grapeAPIInstance().getAMethodCall("request").asExpr().getExpr() + this = grapeApiInstance().getAMethodCall("request").asExpr().getExpr() } } @@ -221,7 +221,7 @@ private class GrapeRouteParamCall extends MethodCall { ) or // Also handle cases where route_param is called on an instance of a Grape API class - this = grapeAPIInstance().getAMethodCall("route_param").asExpr().getExpr() + this = grapeApiInstance().getAMethodCall("route_param").asExpr().getExpr() } } @@ -231,7 +231,7 @@ private class GrapeRouteParamCall extends MethodCall { */ private class GrapeHeadersBlockCall extends MethodCall { GrapeHeadersBlockCall() { - exists(GrapeAPIClass api | + exists(GrapeApiClass api | this.getParent+() = api.getADeclaration() and this.getMethodName() = "headers" and exists(this.getBlock()) @@ -245,7 +245,7 @@ private class GrapeHeadersBlockCall extends MethodCall { */ private class GrapeCookiesBlockCall extends MethodCall { GrapeCookiesBlockCall() { - exists(GrapeAPIClass api | + exists(GrapeApiClass api | this.getParent+() = api.getADeclaration() and this.getMethodName() = "cookies" and exists(this.getBlock()) @@ -280,7 +280,7 @@ private class GrapeCookiesCall extends MethodCall { ) or // Also handle cases where cookies is called on an instance of a Grape API class - this = grapeAPIInstance().getAMethodCall("cookies").asExpr().getExpr() + this = grapeApiInstance().getAMethodCall("cookies").asExpr().getExpr() } } @@ -289,7 +289,7 @@ private class GrapeCookiesCall extends MethodCall { * These methods become available in endpoint contexts through Grape's DSL. */ private class GrapeHelperMethod extends Method { - private GrapeAPIClass apiClass; + private GrapeApiClass apiClass; GrapeHelperMethod() { exists(DataFlow::CallNode helpersCall | @@ -301,7 +301,7 @@ private class GrapeHelperMethod extends Method { /** * Gets the API class that contains this helper method. */ - GrapeAPIClass getAPIClass() { result = apiClass } + GrapeApiClass getAPIClass() { result = apiClass } } /** diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected index c0bee75371c..af4d936e88d 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -1,4 +1,4 @@ -grapeAPIClasses +grapeApiClasses | app.rb:1:1:90:3 | MyAPI | | app.rb:92:1:96:3 | AdminAPI | grapeEndpoints diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index 63d59d0bdd7..ebfb304dbe7 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -3,9 +3,9 @@ import codeql.ruby.frameworks.Grape import codeql.ruby.Concepts import codeql.ruby.AST -query predicate grapeAPIClasses(GrapeAPIClass api) { any() } +query predicate grapeApiClasses(GrapeApiClass api) { any() } -query predicate grapeEndpoints(GrapeAPIClass api, GrapeEndpoint endpoint, string method, string path) { +query predicate grapeEndpoints(GrapeApiClass api, GrapeEndpoint endpoint, string method, string path) { endpoint = api.getAnEndpoint() and method = endpoint.getHttpMethod() and path = endpoint.getPath() From 19cb1874368723b7441b01bb07d6aaf16f8c009d Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:03:27 -0400 Subject: [PATCH 10/90] Update ruby/ql/lib/codeql/ruby/frameworks/Grape.qll Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 72dd1e13b9b..417d4ee4da4 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -136,7 +136,9 @@ private class GrapeParamsCall extends ParamsCallImpl { this.getParent+() = api.getADeclaration() ) } -}/** +} + +/** * A call to `headers` from within a Grape API endpoint or headers block. * Headers can also be a source of user input. */ From fc98cd8d08e9f1d258611757094f73b00095963e Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:11:33 -0400 Subject: [PATCH 11/90] Fix naming standards --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 72dd1e13b9b..7b963c92ee1 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -301,7 +301,7 @@ private class GrapeHelperMethod extends Method { /** * Gets the API class that contains this helper method. */ - GrapeApiClass getAPIClass() { result = apiClass } + GrapeApiClass getApiClass() { result = apiClass } } /** From 7b04cf1a73ddb561738e31ba5b31348ced20c626 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:15:44 +0100 Subject: [PATCH 12/90] Rust: Fix up the test annotations. --- .../security/CWE-319/UseOfHttp.expected | 10 ------- .../test/query-tests/security/CWE-319/main.rs | 30 +++++++++---------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index 53cc8606cc8..f2a2e7e05f4 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -66,13 +66,3 @@ nodes | main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | | main.rs:60:44:60:46 | url | semmle.label | url | subpaths -testFailures -| main.rs:22:20:22:39 | "http://example.com" | Unexpected result: Source | -| main.rs:22:42:22:71 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:25:21:25:42 | ...::get | Unexpected result: Alert | -| main.rs:33:20:33:28 | "http://" | Unexpected result: Source | -| main.rs:33:31:33:60 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:36:30:36:51 | ...::get | Unexpected result: Alert | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | Unexpected result: Source | -| main.rs:59:52:59:81 | //... | Missing result: Alert[rust/non-https-url] | -| main.rs:60:21:60:42 | ...::get | Unexpected result: Alert | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index ae58967a49b..52f744e39a1 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -11,30 +11,30 @@ fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] - - // GOOD: HTTPS URLs that should not be flagged + + // GOOD: HTTPS URLs that should not be flagged let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); let _response4 = reqwest::blocking::get("https://api.example.com/data").unwrap(); } fn test_dynamic_urls() { // BAD: HTTP URLs constructed dynamically - let base_url = "http://example.com"; // $ Alert[rust/non-https-url] + let base_url = "http://example.com"; // $ Source let endpoint = "/api/users"; let full_url = format!("{}{}", base_url, endpoint); - let _response = reqwest::blocking::get(&full_url).unwrap(); - + let _response = reqwest::blocking::get(&full_url).unwrap(); // $ Alert[rust/non-https-url] + // GOOD: HTTPS URLs constructed dynamically let secure_base = "https://example.com"; let secure_full = format!("{}{}", secure_base, endpoint); let _secure_response = reqwest::blocking::get(&secure_full).unwrap(); - + // BAD: HTTP protocol string - let protocol = "http://"; // $ Alert[rust/non-https-url] + let protocol = "http://"; // $ Source let host = "api.example.com"; let insecure_url = format!("{}{}", protocol, host); - let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); - + let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); // $ Alert[rust/non-https-url] + // GOOD: HTTPS protocol string let secure_protocol = "https://"; let secure_url = format!("{}{}", secure_protocol, host); @@ -47,7 +47,7 @@ fn test_localhost_exemptions() { let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); - + // Test IPv6 localhost variants let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); @@ -56,10 +56,10 @@ fn test_localhost_exemptions() { // Additional test cases that mirror the Bad/Good examples fn test_examples() { // From UseOfHttpBad.rs - BAD case - let url = "http://example.com/sensitive-data"; // $ Alert[rust/non-https-url] - let _response = reqwest::blocking::get(url).unwrap(); - - // From UseOfHttpGood.rs - GOOD case + let url = "http://example.com/sensitive-data"; // $ Source + let _response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + + // From UseOfHttpGood.rs - GOOD case let secure_url = "https://example.com/sensitive-data"; let _secure_response = reqwest::blocking::get(secure_url).unwrap(); -} \ No newline at end of file +} From 0924dec545a0eff7113574d629f4c5f2b99007be Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:21:57 +0100 Subject: [PATCH 13/90] Rust: Make the tests of the example code closer to the actual example code. --- .../security/CWE-319/UseOfHttp.expected | 16 ++++++++-------- .../test/query-tests/security/CWE-319/main.rs | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index f2a2e7e05f4..e8b7d301335 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -3,7 +3,7 @@ | main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | | main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | -| main.rs:60:21:60:42 | ...::get | main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:60:21:60:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:59:15:59:49 | "http://example.com/sensitive-... | this HTTP URL | +| main.rs:63:24:63:45 | ...::get | main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:63:24:63:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:19:60:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | @@ -27,9 +27,9 @@ edges | main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | | main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | -| main.rs:59:9:59:11 | url | main.rs:60:44:60:46 | url | provenance | | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | main.rs:59:9:59:11 | url | provenance | | -| main.rs:60:44:60:46 | url | main.rs:60:21:60:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:60:13:60:15 | url | main.rs:63:47:63:49 | url | provenance | | +| main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:60:13:60:15 | url | provenance | | +| main.rs:63:47:63:49 | url | main.rs:63:24:63:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | models | 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | | 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | @@ -61,8 +61,8 @@ nodes | main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | | main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | | main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | -| main.rs:59:9:59:11 | url | semmle.label | url | -| main.rs:59:15:59:49 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | -| main.rs:60:21:60:42 | ...::get | semmle.label | ...::get | -| main.rs:60:44:60:46 | url | semmle.label | url | +| main.rs:60:13:60:15 | url | semmle.label | url | +| main.rs:60:19:60:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:63:24:63:45 | ...::get | semmle.label | ...::get | +| main.rs:63:47:63:49 | url | semmle.label | url | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 52f744e39a1..cec94840f29 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -56,10 +56,20 @@ fn test_localhost_exemptions() { // Additional test cases that mirror the Bad/Good examples fn test_examples() { // From UseOfHttpBad.rs - BAD case - let url = "http://example.com/sensitive-data"; // $ Source - let _response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + { + let url = "http://example.com/sensitive-data"; // $ Source + + // This makes an insecure HTTP request that can be intercepted + let response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url] + println!("Response: {}", response.text().unwrap()); + } // From UseOfHttpGood.rs - GOOD case - let secure_url = "https://example.com/sensitive-data"; - let _secure_response = reqwest::blocking::get(secure_url).unwrap(); + { + let url = "https://example.com/sensitive-data"; + + // This makes a secure HTTPS request that is encrypted + let response = reqwest::blocking::get(url).unwrap(); + println!("Response: {}", response.text().unwrap()); + } } From 9c7fc583373c353f5bf6cf35d055af3b6f28ad0e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:06:05 +0100 Subject: [PATCH 14/90] Rust: Add tests for a few more edge cases. --- .../security/CWE-319/UseOfHttp.expected | 120 ++++++++++-------- .../test/query-tests/security/CWE-319/main.rs | 22 +++- 2 files changed, 79 insertions(+), 63 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index e8b7d301335..216d11b3606 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -1,35 +1,39 @@ #select | main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | -| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:73 | "http://api.example.com/data" | this HTTP URL | -| main.rs:25:21:25:42 | ...::get | main.rs:22:20:22:39 | "http://example.com" | main.rs:25:21:25:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:22:20:22:39 | "http://example.com" | this HTTP URL | -| main.rs:36:30:36:51 | ...::get | main.rs:33:20:33:28 | "http://" | main.rs:36:30:36:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:33:20:33:28 | "http://" | this HTTP URL | -| main.rs:63:24:63:45 | ...::get | main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:63:24:63:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:19:60:53 | "http://example.com/sensitive-... | this HTTP URL | +| main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | +| main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | +| main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | +| main.rs:53:19:53:40 | ...::get | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | this HTTP URL | +| main.rs:60:20:60:41 | ...::get | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | this HTTP URL | +| main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:13:45:13:73 | "http://api.example.com/data" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:22:9:22:16 | base_url | main.rs:24:28:24:53 | MacroExpr | provenance | | -| main.rs:22:20:22:39 | "http://example.com" | main.rs:22:9:22:16 | base_url | provenance | | -| main.rs:24:9:24:16 | full_url | main.rs:25:45:25:52 | full_url | provenance | | -| main.rs:24:20:24:26 | res | main.rs:24:28:24:53 | { ... } | provenance | | -| main.rs:24:28:24:53 | ...::format(...) | main.rs:24:20:24:26 | res | provenance | | -| main.rs:24:28:24:53 | ...::must_use(...) | main.rs:24:9:24:16 | full_url | provenance | | -| main.rs:24:28:24:53 | MacroExpr | main.rs:24:28:24:53 | ...::format(...) | provenance | MaD:2 | -| main.rs:24:28:24:53 | { ... } | main.rs:24:28:24:53 | ...::must_use(...) | provenance | MaD:3 | -| main.rs:25:44:25:52 | &full_url [&ref] | main.rs:25:21:25:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:25:45:25:52 | full_url | main.rs:25:44:25:52 | &full_url [&ref] | provenance | | -| main.rs:33:9:33:16 | protocol | main.rs:35:32:35:53 | MacroExpr | provenance | | -| main.rs:33:20:33:28 | "http://" | main.rs:33:9:33:16 | protocol | provenance | | -| main.rs:35:9:35:20 | insecure_url | main.rs:36:54:36:65 | insecure_url | provenance | | -| main.rs:35:24:35:30 | res | main.rs:35:32:35:53 | { ... } | provenance | | -| main.rs:35:32:35:53 | ...::format(...) | main.rs:35:24:35:30 | res | provenance | | -| main.rs:35:32:35:53 | ...::must_use(...) | main.rs:35:9:35:20 | insecure_url | provenance | | -| main.rs:35:32:35:53 | MacroExpr | main.rs:35:32:35:53 | ...::format(...) | provenance | MaD:2 | -| main.rs:35:32:35:53 | { ... } | main.rs:35:32:35:53 | ...::must_use(...) | provenance | MaD:3 | -| main.rs:36:53:36:65 | &insecure_url [&ref] | main.rs:36:30:36:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | -| main.rs:36:54:36:65 | insecure_url | main.rs:36:53:36:65 | &insecure_url [&ref] | provenance | | -| main.rs:60:13:60:15 | url | main.rs:63:47:63:49 | url | provenance | | -| main.rs:60:19:60:53 | "http://example.com/sensitive-... | main.rs:60:13:60:15 | url | provenance | | -| main.rs:63:47:63:49 | url | main.rs:63:24:63:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:23:9:23:16 | base_url | main.rs:25:28:25:53 | MacroExpr | provenance | | +| main.rs:23:20:23:39 | "http://example.com" | main.rs:23:9:23:16 | base_url | provenance | | +| main.rs:25:9:25:16 | full_url | main.rs:26:45:26:52 | full_url | provenance | | +| main.rs:25:20:25:26 | res | main.rs:25:28:25:53 | { ... } | provenance | | +| main.rs:25:28:25:53 | ...::format(...) | main.rs:25:20:25:26 | res | provenance | | +| main.rs:25:28:25:53 | ...::must_use(...) | main.rs:25:9:25:16 | full_url | provenance | | +| main.rs:25:28:25:53 | MacroExpr | main.rs:25:28:25:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:25:28:25:53 | { ... } | main.rs:25:28:25:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:26:44:26:52 | &full_url [&ref] | main.rs:26:21:26:42 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:26:45:26:52 | full_url | main.rs:26:44:26:52 | &full_url [&ref] | provenance | | +| main.rs:34:9:34:16 | protocol | main.rs:36:32:36:53 | MacroExpr | provenance | | +| main.rs:34:20:34:28 | "http://" | main.rs:34:9:34:16 | protocol | provenance | | +| main.rs:36:9:36:20 | insecure_url | main.rs:37:54:37:65 | insecure_url | provenance | | +| main.rs:36:24:36:30 | res | main.rs:36:32:36:53 | { ... } | provenance | | +| main.rs:36:32:36:53 | ...::format(...) | main.rs:36:24:36:30 | res | provenance | | +| main.rs:36:32:36:53 | ...::must_use(...) | main.rs:36:9:36:20 | insecure_url | provenance | | +| main.rs:36:32:36:53 | MacroExpr | main.rs:36:32:36:53 | ...::format(...) | provenance | MaD:2 | +| main.rs:36:32:36:53 | { ... } | main.rs:36:32:36:53 | ...::must_use(...) | provenance | MaD:3 | +| main.rs:37:53:37:65 | &insecure_url [&ref] | main.rs:37:30:37:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:37:54:37:65 | insecure_url | main.rs:37:53:37:65 | &insecure_url [&ref] | provenance | | +| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:68:13:68:15 | url | main.rs:71:47:71:49 | url | provenance | | +| main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:68:13:68:15 | url | provenance | | +| main.rs:71:47:71:49 | url | main.rs:71:24:71:45 | ...::get | provenance | MaD:1 Sink:MaD:1 | models | 1 | Sink: reqwest::blocking::get; Argument[0]; request-url | | 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | @@ -37,32 +41,36 @@ models nodes | main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | | main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | -| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | -| main.rs:13:45:13:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | -| main.rs:22:9:22:16 | base_url | semmle.label | base_url | -| main.rs:22:20:22:39 | "http://example.com" | semmle.label | "http://example.com" | -| main.rs:24:9:24:16 | full_url | semmle.label | full_url | -| main.rs:24:20:24:26 | res | semmle.label | res | -| main.rs:24:28:24:53 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:24:28:24:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:24:28:24:53 | MacroExpr | semmle.label | MacroExpr | -| main.rs:24:28:24:53 | { ... } | semmle.label | { ... } | -| main.rs:25:21:25:42 | ...::get | semmle.label | ...::get | -| main.rs:25:44:25:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | -| main.rs:25:45:25:52 | full_url | semmle.label | full_url | -| main.rs:33:9:33:16 | protocol | semmle.label | protocol | -| main.rs:33:20:33:28 | "http://" | semmle.label | "http://" | -| main.rs:35:9:35:20 | insecure_url | semmle.label | insecure_url | -| main.rs:35:24:35:30 | res | semmle.label | res | -| main.rs:35:32:35:53 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:35:32:35:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:35:32:35:53 | MacroExpr | semmle.label | MacroExpr | -| main.rs:35:32:35:53 | { ... } | semmle.label | { ... } | -| main.rs:36:30:36:51 | ...::get | semmle.label | ...::get | -| main.rs:36:53:36:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | -| main.rs:36:54:36:65 | insecure_url | semmle.label | insecure_url | -| main.rs:60:13:60:15 | url | semmle.label | url | -| main.rs:60:19:60:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | -| main.rs:63:24:63:45 | ...::get | semmle.label | ...::get | -| main.rs:63:47:63:49 | url | semmle.label | url | +| main.rs:14:22:14:43 | ...::get | semmle.label | ...::get | +| main.rs:14:45:14:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | +| main.rs:23:9:23:16 | base_url | semmle.label | base_url | +| main.rs:23:20:23:39 | "http://example.com" | semmle.label | "http://example.com" | +| main.rs:25:9:25:16 | full_url | semmle.label | full_url | +| main.rs:25:20:25:26 | res | semmle.label | res | +| main.rs:25:28:25:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:25:28:25:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:25:28:25:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:25:28:25:53 | { ... } | semmle.label | { ... } | +| main.rs:26:21:26:42 | ...::get | semmle.label | ...::get | +| main.rs:26:44:26:52 | &full_url [&ref] | semmle.label | &full_url [&ref] | +| main.rs:26:45:26:52 | full_url | semmle.label | full_url | +| main.rs:34:9:34:16 | protocol | semmle.label | protocol | +| main.rs:34:20:34:28 | "http://" | semmle.label | "http://" | +| main.rs:36:9:36:20 | insecure_url | semmle.label | insecure_url | +| main.rs:36:24:36:30 | res | semmle.label | res | +| main.rs:36:32:36:53 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:36:32:36:53 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:36:32:36:53 | MacroExpr | semmle.label | MacroExpr | +| main.rs:36:32:36:53 | { ... } | semmle.label | { ... } | +| main.rs:37:30:37:51 | ...::get | semmle.label | ...::get | +| main.rs:37:53:37:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | +| main.rs:37:54:37:65 | insecure_url | semmle.label | insecure_url | +| main.rs:53:19:53:40 | ...::get | semmle.label | ...::get | +| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | semmle.label | "http://172.31.255.255/bar" | +| main.rs:60:20:60:41 | ...::get | semmle.label | ...::get | +| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | semmle.label | "http://172.32.0.0/baz" | +| main.rs:68:13:68:15 | url | semmle.label | url | +| main.rs:68:19:68:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... | +| main.rs:71:24:71:45 | ...::get | semmle.label | ...::get | +| main.rs:71:47:71:49 | url | semmle.label | url | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index cec94840f29..0dd59ce0880 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -10,7 +10,8 @@ fn main() { fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] - let _response2 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ MISSING: Alert[rust/non-https-url] + let _response3 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] // GOOD: HTTPS URLs that should not be flagged let _response3 = reqwest::blocking::get("https://example.com/api").unwrap(); @@ -44,13 +45,20 @@ fn test_dynamic_urls() { fn test_localhost_exemptions() { // GOOD: localhost URLs should not be flagged (local development) let _local1 = reqwest::blocking::get("http://localhost:8080/api").unwrap(); - let _local2 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); - let _local3 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); - let _local4 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + let _local2 = reqwest::blocking::get("HTTP://LOCALHOST:8080/api").unwrap(); + let _local3 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap(); + let _local4 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); + let _local5 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); + let _local6 = reqwest::blocking::get("http://172.16.0.0/foo").unwrap(); + let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // $ SPURIOUS: Alert[rust/non-https-url] + + // GOOD: test IPv6 localhost variants + let _local8 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); + let _local9 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); + + // BAD: non-private IP address + let _local10 = reqwest::blocking::get("http://172.32.0.0/baz").unwrap(); // $ Alert[rust/non-https-url] - // Test IPv6 localhost variants - let _local5 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); - let _local6 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap(); } // Additional test cases that mirror the Bad/Good examples From 0f5aa857b874b22bfb53b67b08be2336e14af351 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:32:52 +0100 Subject: [PATCH 15/90] Rust: Remove unnecessary import. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 026880785b6..8001e6270dd 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -6,7 +6,6 @@ import rust private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.FlowSink -private import codeql.rust.elements.LiteralExprExt private import codeql.rust.Concepts /** From 0b900711bf1d3df6d5d16d7cd7688495b2ca60dd Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 16 Sep 2025 13:48:26 +0200 Subject: [PATCH 16/90] Update javascript/ql/lib/semmle/javascript/frameworks/Express.qll Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- javascript/ql/lib/semmle/javascript/frameworks/Express.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 41e4d1c860c..be3cb7b1ccb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -803,7 +803,7 @@ module Express { } /** - * An argument passed to the `json` or `json` method of an HTTP response object. + * An argument passed to the `json` or `jsonp` method of an HTTP response object. */ private class ResponseJsonCallArgument extends Http::ResponseSendArgument { ResponseJsonCall call; From 80ce55ab1072fb534776fc7b02a93ca6a2b18ce2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:58:23 +0100 Subject: [PATCH 17/90] Rust: Make the private address spaces URL more accurate. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 2 +- rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected | 4 ---- rust/ql/test/query-tests/security/CWE-319/main.rs | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 8001e6270dd..58466dd0a4f 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -38,7 +38,7 @@ module UseOfHttp { exists(string s | this.getTextValue() = s | // Match HTTP URLs that are not private/local s.regexpMatch("\"http://.*\"") and - not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.16\\.[0-9]+\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") ) } } diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index 216d11b3606..ef99b001fcf 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -3,7 +3,6 @@ | main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | | main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | -| main.rs:53:19:53:40 | ...::get | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:53:42:53:68 | "http://172.31.255.255/bar" | this HTTP URL | | main.rs:60:20:60:41 | ...::get | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | this HTTP URL | | main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges @@ -29,7 +28,6 @@ edges | main.rs:36:32:36:53 | { ... } | main.rs:36:32:36:53 | ...::must_use(...) | provenance | MaD:3 | | main.rs:37:53:37:65 | &insecure_url [&ref] | main.rs:37:30:37:51 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:37:54:37:65 | insecure_url | main.rs:37:53:37:65 | &insecure_url [&ref] | provenance | | -| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | main.rs:53:19:53:40 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:68:13:68:15 | url | main.rs:71:47:71:49 | url | provenance | | | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:68:13:68:15 | url | provenance | | @@ -65,8 +63,6 @@ nodes | main.rs:37:30:37:51 | ...::get | semmle.label | ...::get | | main.rs:37:53:37:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] | | main.rs:37:54:37:65 | insecure_url | semmle.label | insecure_url | -| main.rs:53:19:53:40 | ...::get | semmle.label | ...::get | -| main.rs:53:42:53:68 | "http://172.31.255.255/bar" | semmle.label | "http://172.31.255.255/bar" | | main.rs:60:20:60:41 | ...::get | semmle.label | ...::get | | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | semmle.label | "http://172.32.0.0/baz" | | main.rs:68:13:68:15 | url | semmle.label | url | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 0dd59ce0880..908e6c61c2c 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -50,7 +50,7 @@ fn test_localhost_exemptions() { let _local4 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap(); let _local5 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap(); let _local6 = reqwest::blocking::get("http://172.16.0.0/foo").unwrap(); - let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // $ SPURIOUS: Alert[rust/non-https-url] + let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap(); // GOOD: test IPv6 localhost variants let _local8 = reqwest::blocking::get("http://[::1]:8080/api").unwrap(); From 4b281fdf12fb8a64cd194aee324ded70855b4695 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:02:54 +0100 Subject: [PATCH 18/90] Rust: Use case insensitive regexps. --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 4 ++-- rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected | 4 ++++ rust/ql/test/query-tests/security/CWE-319/main.rs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 58466dd0a4f..5e0d534fb7d 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -37,8 +37,8 @@ module UseOfHttp { HttpStringLiteral() { exists(string s | this.getTextValue() = s | // Match HTTP URLs that are not private/local - s.regexpMatch("\"http://.*\"") and - not s.regexpMatch("\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + s.regexpMatch("(?i)\"http://.*\"") and + not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") ) } } diff --git a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected index ef99b001fcf..952bd741d1c 100644 --- a/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected +++ b/rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected @@ -1,5 +1,6 @@ #select | main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL | +| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | this HTTP URL | | main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL | | main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL | | main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL | @@ -7,6 +8,7 @@ | main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL | edges | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | provenance | MaD:1 Sink:MaD:1 | | main.rs:23:9:23:16 | base_url | main.rs:25:28:25:53 | MacroExpr | provenance | | | main.rs:23:20:23:39 | "http://example.com" | main.rs:23:9:23:16 | base_url | provenance | | @@ -39,6 +41,8 @@ models nodes | main.rs:12:22:12:43 | ...::get | semmle.label | ...::get | | main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" | +| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get | +| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | semmle.label | "HTTP://EXAMPLE.COM/API" | | main.rs:14:22:14:43 | ...::get | semmle.label | ...::get | | main.rs:14:45:14:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" | | main.rs:23:9:23:16 | base_url | semmle.label | base_url | diff --git a/rust/ql/test/query-tests/security/CWE-319/main.rs b/rust/ql/test/query-tests/security/CWE-319/main.rs index 908e6c61c2c..0a3539923da 100644 --- a/rust/ql/test/query-tests/security/CWE-319/main.rs +++ b/rust/ql/test/query-tests/security/CWE-319/main.rs @@ -10,7 +10,7 @@ fn main() { fn test_direct_literals() { // BAD: Direct HTTP URLs that should be flagged let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url] - let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ MISSING: Alert[rust/non-https-url] + let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ Alert[rust/non-https-url] let _response3 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url] // GOOD: HTTPS URLs that should not be flagged From 0eb602aad2991216268e79bbe5db05472f2156c0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:00:43 +0100 Subject: [PATCH 19/90] Rust: Update a redirected URL. --- .../src/queries/security/CWE-319/UseOfHttp.qhelp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index a8ca1d9c7c7..a1345b189bb 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -6,21 +6,21 @@

    Constructing URLs with the HTTP protocol can lead to unsecured connections.

    -

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the -code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, +

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the +code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, which may fail or fall back to insecure behavior when provided with HTTP URLs instead of HTTPS URLs.

    -

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. +

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL/TLS connections.

    -

    The following example shows two ways of making a network request using a URL. When the request is -made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted +

    The following example shows two ways of making a network request using a URL. When the request is +made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

    @@ -34,15 +34,15 @@ by attackers. When the request is made using an HTTPS URL, the connection is a s
  • OWASP: -Transport Layer Protection Cheat Sheet. +Transport Layer Security Cheat Sheet.
  • OWASP Top 10: A08:2021 - Software and Data Integrity Failures.
  • -
  • Rust reqwest documentation: +
  • Rust reqwest documentation: reqwest crate.
  • - \ No newline at end of file + From 31bf86fd1bcb60946c038d1329f132647bc60288 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:04:47 +0100 Subject: [PATCH 20/90] Rust: Improve the flow around the qhelp example. --- rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index a1345b189bb..e4e0fc5eaa9 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -19,13 +19,14 @@ Then, any connections that are made using that URL are secure SSL/TLS connection -

    The following example shows two ways of making a network request using a URL. When the request is +

    The following examples show two ways of making a network request using a URL. When the request is made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted -by attackers. When the request is made using an HTTPS URL, the connection is a secure SSL/TLS connection.

    +by attackers:

    -

    A better approach is to use HTTPS:

    +

    A better approach is to use HTTPS. When the request is made using an HTTPS URL, the connection +is a secure SSL/TLS connection:

    From ffd32efba274f0b1400d592562f24cae4a286ddf Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Tue, 16 Sep 2025 09:08:07 -0400 Subject: [PATCH 21/90] codeql query format --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 37 ++++++------------- .../library-tests/frameworks/grape/Grape.ql | 2 +- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index faf762f53a0..ea7bc8c576c 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -52,9 +52,7 @@ class GrapeApiClass extends DataFlow::ClassNode { /** * Gets a `GrapeEndpoint` defined in this class. */ - GrapeEndpoint getAnEndpoint() { - result.getApiClass() = this - } + GrapeEndpoint getAnEndpoint() { result.getApiClass() = this } /** * Gets a `self` that possibly refers to an instance of this class. @@ -72,9 +70,7 @@ private DataFlow::ConstRef grapeApiBaseClass() { result = DataFlow::getConstant("Grape").getConstant("API") } -private API::Node grapeApiInstance() { - result = any(GrapeApiClass cls).getSelf().track() -} +private API::Node grapeApiInstance() { result = any(GrapeApiClass cls).getSelf().track() } /** * A Grape API endpoint (get, post, put, delete, etc.) call within a `Grape::API` class. @@ -83,15 +79,14 @@ class GrapeEndpoint extends DataFlow::CallNode { private GrapeApiClass apiClass; GrapeEndpoint() { - this = apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) + this = + apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) } /** * Gets the HTTP method for this endpoint (e.g., "GET", "POST", etc.) */ - string getHttpMethod() { - result = this.getMethodName().toUpperCase() - } + string getHttpMethod() { result = this.getMethodName().toUpperCase() } /** * Gets the API class containing this endpoint. @@ -106,9 +101,7 @@ class GrapeEndpoint extends DataFlow::CallNode { /** * Gets the path pattern for this endpoint, if specified. */ - string getPath() { - result = this.getArgument(0).getConstantValue().getString() - } + string getPath() { result = this.getArgument(0).getConstantValue().getString() } } /** @@ -116,9 +109,7 @@ class GrapeEndpoint extends DataFlow::CallNode { * Grape parameters available via the `params` method within an endpoint. */ class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { - GrapeParamsSource() { - this.asExpr().getExpr() instanceof GrapeParamsCall - } + GrapeParamsSource() { this.asExpr().getExpr() instanceof GrapeParamsCall } override string getSourceType() { result = "Grape::API#params" } @@ -174,9 +165,7 @@ private class GrapeHeadersCall extends MethodCall { * The request object can contain user input. */ class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { - GrapeRequestSource() { - this.asExpr().getExpr() instanceof GrapeRequestCall - } + GrapeRequestSource() { this.asExpr().getExpr() instanceof GrapeRequestCall } override string getSourceType() { result = "Grape::API#request" } @@ -188,9 +177,7 @@ class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { * Route parameters are extracted from the URL path and can be a source of user input. */ class GrapeRouteParamSource extends Http::Server::RequestInputAccess::Range { - GrapeRouteParamSource() { - this.asExpr().getExpr() instanceof GrapeRouteParamCall - } + GrapeRouteParamSource() { this.asExpr().getExpr() instanceof GrapeRouteParamCall } override string getSourceType() { result = "Grape::API#route_param" } @@ -316,12 +303,10 @@ private class GrapeHelperMethodTaintStep extends AdditionalTaintStep { exists(GrapeHelperMethod helperMethod, MethodCall call, int i | // Find calls to helper methods from within Grape endpoints call.getMethodName() = helperMethod.getName() and - exists(GrapeEndpoint endpoint | - call.getParent+() = endpoint.getBody().asExpr().getExpr() - ) and + exists(GrapeEndpoint endpoint | call.getParent+() = endpoint.getBody().asExpr().getExpr()) and // Map argument to parameter nodeFrom.asExpr().getExpr() = call.getArgument(i) and nodeTo.asParameter() = helperMethod.getParameter(i) ) } -} \ No newline at end of file +} diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index ebfb304dbe7..c9aa7c29082 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -19,4 +19,4 @@ query predicate grapeRequest(GrapeRequestSource request) { any() } query predicate grapeRouteParam(GrapeRouteParamSource routeParam) { any() } -query predicate grapeCookies(GrapeCookiesSource cookies) { any() } \ No newline at end of file +query predicate grapeCookies(GrapeCookiesSource cookies) { any() } From 6f1fcbf41bf7484025a208af19a19630dc3a4df9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:08:22 +0100 Subject: [PATCH 22/90] Rust: Add IPv6 private address range (and explanatory comments). --- rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll index 5e0d534fb7d..bd91cde238f 100644 --- a/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll @@ -36,9 +36,12 @@ module UseOfHttp { class HttpStringLiteral extends StringLiteralExpr { HttpStringLiteral() { exists(string s | this.getTextValue() = s | - // Match HTTP URLs that are not private/local + // match HTTP URLs s.regexpMatch("(?i)\"http://.*\"") and - not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]).*\"") + // exclude private/local addresses: + // - IPv4: localhost / 127.0.0.1, 192.168.x.x, 10.x.x.x, 172.16.x.x -> 172.31.x.x + // - IPv6 (address inside []): ::1 (or 0:0:0:0:0:0:0:1), fc00::/7 (i.e. anything beginning `fcxx:` or `fdxx:`) + not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]|\\[f[cd][0-9a-f]{2}:.*\\]).*\"") ) } } From c5e3be2c4cc30b1d8b92dfde67097577d4867dc0 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:09:18 -0400 Subject: [PATCH 23/90] Grape - detect params calls inside helper methods - added unit tests for flow using inline format - removed grape from Arel tests (temporary) --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 28 ++++++- .../frameworks/grape/Flow.expected | 77 +++++++++++++++++++ .../library-tests/frameworks/grape/Flow.ql | 25 ++++++ .../frameworks/grape/Grape.expected | 16 ++++ .../library-tests/frameworks/grape/app.rb | 74 +++++++++++++++++- .../security/cwe-089/ArelInjection.rb | 64 +-------------- .../security/cwe-089/SqlInjection.expected | 66 ---------------- 7 files changed, 216 insertions(+), 134 deletions(-) create mode 100644 ruby/ql/test/library-tests/frameworks/grape/Flow.expected create mode 100644 ruby/ql/test/library-tests/frameworks/grape/Flow.ql diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index ea7bc8c576c..a1646b8654c 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -121,11 +121,18 @@ class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { */ private class GrapeParamsCall extends ParamsCallImpl { GrapeParamsCall() { - // Simplified approach: find params calls that are descendants of Grape API class methods + // Params calls within endpoint blocks exists(GrapeApiClass api | this.getMethodName() = "params" and this.getParent+() = api.getADeclaration() ) + or + // Params calls within helper methods (defined in helpers blocks) + exists(GrapeApiClass api, DataFlow::CallNode helpersCall | + helpersCall = api.getAModuleLevelCall("helpers") and + this.getMethodName() = "params" and + this.getParent+() = helpersCall.getBlock().asExpr().getExpr() + ) } } @@ -295,18 +302,31 @@ private class GrapeHelperMethod extends Method { /** * Additional taint step to model dataflow from method arguments to parameters - * for Grape helper methods defined in `helpers` blocks. + * and from return values back to call sites for Grape helper methods defined in `helpers` blocks. * This bridges the gap where standard dataflow doesn't recognize the Grape DSL semantics. */ private class GrapeHelperMethodTaintStep extends AdditionalTaintStep { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Map arguments to parameters for helper method calls exists(GrapeHelperMethod helperMethod, MethodCall call, int i | - // Find calls to helper methods from within Grape endpoints + // Find calls to helper methods from within Grape endpoints or other helper methods call.getMethodName() = helperMethod.getName() and - exists(GrapeEndpoint endpoint | call.getParent+() = endpoint.getBody().asExpr().getExpr()) and + exists(GrapeApiClass api | call.getParent+() = api.getADeclaration()) and // Map argument to parameter nodeFrom.asExpr().getExpr() = call.getArgument(i) and nodeTo.asParameter() = helperMethod.getParameter(i) ) + or + // Model implicit return values: the last expression in a helper method flows to the call site + exists(GrapeHelperMethod helperMethod, MethodCall helperCall, Expr lastExpr | + // Find calls to helper methods from within Grape endpoints or other helper methods + helperCall.getMethodName() = helperMethod.getName() and + exists(GrapeApiClass api | helperCall.getParent+() = api.getADeclaration()) and + // Get the last expression in the helper method (Ruby's implicit return) + lastExpr = helperMethod.getLastStmt() and + // Flow from the last expression in the helper method to the call site + nodeFrom.asExpr().getExpr() = lastExpr and + nodeTo.asExpr().getExpr() = helperCall + ) } } diff --git a/ruby/ql/test/library-tests/frameworks/grape/Flow.expected b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected new file mode 100644 index 00000000000..0fd19d4eace --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected @@ -0,0 +1,77 @@ +models +edges +| app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select | provenance | | +| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | AdditionalTaintStep | +| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | AdditionalTaintStep | +| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | AdditionalTaintStep | +| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | AdditionalTaintStep | +| app.rb:126:9:126:15 | user_id | app.rb:133:14:133:20 | user_id | provenance | | +| app.rb:126:19:126:24 | call to params | app.rb:126:19:126:34 | ...[...] | provenance | | +| app.rb:126:19:126:34 | ...[...] | app.rb:126:9:126:15 | user_id | provenance | | +| app.rb:127:9:127:16 | route_id | app.rb:134:14:134:21 | route_id | provenance | | +| app.rb:127:20:127:40 | call to route_param | app.rb:127:9:127:16 | route_id | provenance | | +| app.rb:128:9:128:12 | auth | app.rb:135:14:135:17 | auth | provenance | | +| app.rb:128:16:128:22 | call to headers | app.rb:128:16:128:38 | ...[...] | provenance | | +| app.rb:128:16:128:38 | ...[...] | app.rb:128:9:128:12 | auth | provenance | | +| app.rb:129:9:129:15 | session | app.rb:136:14:136:20 | session | provenance | | +| app.rb:129:19:129:25 | call to cookies | app.rb:129:19:129:38 | ...[...] | provenance | | +| app.rb:129:19:129:38 | ...[...] | app.rb:129:9:129:15 | session | provenance | | +| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | | +| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | | +| app.rb:149:9:149:17 | user_data | app.rb:151:14:151:22 | user_data | provenance | | +| app.rb:149:21:149:31 | call to user_params | app.rb:149:9:149:17 | user_data | provenance | | +| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | | +| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | | +| app.rb:159:13:159:19 | user_id | app.rb:160:18:160:24 | user_id | provenance | | +| app.rb:159:23:159:28 | call to params | app.rb:159:23:159:33 | ...[...] | provenance | | +| app.rb:159:23:159:33 | ...[...] | app.rb:159:13:159:19 | user_id | provenance | | +| app.rb:165:9:165:17 | user_data | app.rb:166:14:166:22 | user_data | provenance | | +| app.rb:165:21:165:31 | call to user_params | app.rb:165:9:165:17 | user_data | provenance | | +nodes +| app.rb:103:13:103:18 | call to params | semmle.label | call to params | +| app.rb:103:13:103:70 | call to select | semmle.label | call to select | +| app.rb:107:13:107:32 | call to source | semmle.label | call to source | +| app.rb:111:13:111:33 | call to source | semmle.label | call to source | +| app.rb:126:9:126:15 | user_id | semmle.label | user_id | +| app.rb:126:19:126:24 | call to params | semmle.label | call to params | +| app.rb:126:19:126:34 | ...[...] | semmle.label | ...[...] | +| app.rb:127:9:127:16 | route_id | semmle.label | route_id | +| app.rb:127:20:127:40 | call to route_param | semmle.label | call to route_param | +| app.rb:128:9:128:12 | auth | semmle.label | auth | +| app.rb:128:16:128:22 | call to headers | semmle.label | call to headers | +| app.rb:128:16:128:38 | ...[...] | semmle.label | ...[...] | +| app.rb:129:9:129:15 | session | semmle.label | session | +| app.rb:129:19:129:25 | call to cookies | semmle.label | call to cookies | +| app.rb:129:19:129:38 | ...[...] | semmle.label | ...[...] | +| app.rb:133:14:133:20 | user_id | semmle.label | user_id | +| app.rb:134:14:134:21 | route_id | semmle.label | route_id | +| app.rb:135:14:135:17 | auth | semmle.label | auth | +| app.rb:136:14:136:20 | session | semmle.label | session | +| app.rb:143:9:143:14 | result | semmle.label | result | +| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | +| app.rb:144:14:144:19 | result | semmle.label | result | +| app.rb:149:9:149:17 | user_data | semmle.label | user_data | +| app.rb:149:21:149:31 | call to user_params | semmle.label | call to user_params | +| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result | +| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper | +| app.rb:151:14:151:22 | user_data | semmle.label | user_data | +| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result | +| app.rb:159:13:159:19 | user_id | semmle.label | user_id | +| app.rb:159:23:159:28 | call to params | semmle.label | call to params | +| app.rb:159:23:159:33 | ...[...] | semmle.label | ...[...] | +| app.rb:160:18:160:24 | user_id | semmle.label | user_id | +| app.rb:165:9:165:17 | user_data | semmle.label | user_data | +| app.rb:165:21:165:31 | call to user_params | semmle.label | call to user_params | +| app.rb:166:14:166:22 | user_data | semmle.label | user_data | +subpaths +testFailures +#select +| app.rb:133:14:133:20 | user_id | app.rb:126:19:126:24 | call to params | app.rb:133:14:133:20 | user_id | $@ | app.rb:126:19:126:24 | call to params | call to params | +| app.rb:134:14:134:21 | route_id | app.rb:127:20:127:40 | call to route_param | app.rb:134:14:134:21 | route_id | $@ | app.rb:127:20:127:40 | call to route_param | call to route_param | +| app.rb:135:14:135:17 | auth | app.rb:128:16:128:22 | call to headers | app.rb:135:14:135:17 | auth | $@ | app.rb:128:16:128:22 | call to headers | call to headers | +| app.rb:136:14:136:20 | session | app.rb:129:19:129:25 | call to cookies | app.rb:136:14:136:20 | session | $@ | app.rb:129:19:129:25 | call to cookies | call to cookies | +| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | +| app.rb:151:14:151:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:151:14:151:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | +| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | +| app.rb:160:18:160:24 | user_id | app.rb:159:23:159:28 | call to params | app.rb:160:18:160:24 | user_id | $@ | app.rb:159:23:159:28 | call to params | call to params | +| app.rb:166:14:166:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:166:14:166:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | diff --git a/ruby/ql/test/library-tests/frameworks/grape/Flow.ql b/ruby/ql/test/library-tests/frameworks/grape/Flow.ql new file mode 100644 index 00000000000..baa3fa4307f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/Flow.ql @@ -0,0 +1,25 @@ +/** + * @kind path-problem + */ + +import ruby +import utils.test.InlineFlowTest +import PathGraph +import codeql.ruby.frameworks.Grape +import codeql.ruby.Concepts + +module GrapeConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source instanceof Http::Server::RequestInputAccess::Range + or + DefaultFlowConfig::isSource(source) + } + + predicate isSink(DataFlow::Node sink) { DefaultFlowConfig::isSink(sink) } +} + +import FlowTest + +from PathNode source, PathNode sink +where flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected index af4d936e88d..d39d9430f92 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -1,6 +1,7 @@ grapeApiClasses | app.rb:1:1:90:3 | MyAPI | | app.rb:92:1:96:3 | AdminAPI | +| app.rb:98:1:168:3 | UserAPI | grapeEndpoints | app.rb:1:1:90:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name | | app.rb:1:1:90:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages | @@ -13,6 +14,10 @@ grapeEndpoints | app.rb:1:1:90:3 | MyAPI | app.rb:78:3:82:5 | call to get | GET | /cookie_test | | app.rb:1:1:90:3 | MyAPI | app.rb:85:3:89:5 | call to get | GET | /header_test | | app.rb:92:1:96:3 | AdminAPI | app.rb:93:3:95:5 | call to get | GET | /admin | +| app.rb:98:1:168:3 | UserAPI | app.rb:124:5:138:7 | call to get | GET | /comprehensive_test/:user_id | +| app.rb:98:1:168:3 | UserAPI | app.rb:140:5:145:7 | call to get | GET | /helper_test/:user_id | +| app.rb:98:1:168:3 | UserAPI | app.rb:147:5:153:7 | call to post | POST | /users | +| app.rb:98:1:168:3 | UserAPI | app.rb:164:5:167:7 | call to post | POST | /users | grapeParams | app.rb:8:12:8:17 | call to params | | app.rb:14:3:16:5 | call to params | @@ -22,19 +27,30 @@ grapeParams | app.rb:36:5:36:10 | call to params | | app.rb:60:12:60:17 | call to params | | app.rb:94:5:94:10 | call to params | +| app.rb:103:13:103:18 | call to params | +| app.rb:126:19:126:24 | call to params | +| app.rb:142:19:142:24 | call to params | +| app.rb:159:23:159:28 | call to params | grapeHeaders | app.rb:9:18:9:24 | call to headers | | app.rb:46:5:46:11 | call to headers | | app.rb:66:3:69:5 | call to headers | | app.rb:86:12:86:18 | call to headers | | app.rb:87:14:87:20 | call to headers | +| app.rb:116:5:118:7 | call to headers | +| app.rb:128:16:128:22 | call to headers | grapeRequest | app.rb:25:12:25:18 | call to request | +| app.rb:130:21:130:27 | call to request | grapeRouteParam | app.rb:51:15:51:35 | call to route_param | | app.rb:52:15:52:36 | call to route_param | | app.rb:57:3:63:5 | call to route_param | +| app.rb:127:20:127:40 | call to route_param | +| app.rb:156:5:162:7 | call to route_param | grapeCookies | app.rb:72:3:75:5 | call to cookies | | app.rb:79:15:79:21 | call to cookies | | app.rb:80:16:80:22 | call to cookies | +| app.rb:120:5:122:7 | call to cookies | +| app.rb:129:19:129:25 | call to cookies | diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb index a034f325f7b..6fbb184cab9 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/app.rb +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -93,4 +93,76 @@ class AdminAPI < Grape::API get '/admin' do params[:token] end -end \ No newline at end of file +end + +class UserAPI < Grape::API + VALID_PARAMS = %w(name email password password_confirmation) + + helpers do + def user_params + params.select{|key,value| VALID_PARAMS.include?(key.to_s)} # Real helper implementation + end + + def vulnerable_helper(user_id) + source "paramHelper" # Test parameter passing to helper + end + + def simple_helper + source "simpleHelper" # Test simple helper return + end + end + + # Headers and cookies blocks for DSL testing + headers do + requires :Authorization, type: String + end + + cookies do + requires :session_id, type: String + end + + get '/comprehensive_test/:user_id' do + # Test all Grape input sources + user_id = params[:user_id] # params taint source + route_id = route_param(:user_id) # route_param taint source + auth = headers[:Authorization] # headers taint source + session = cookies[:session_id] # cookies taint source + body_data = request.body.read # request taint source + + # Test sinks for all sources + sink user_id # $ hasTaintFlow + sink route_id # $ hasTaintFlow + sink auth # $ hasTaintFlow + sink session # $ hasTaintFlow + # Note: request.body.read may not be detected by this flow test config + end + + get '/helper_test/:user_id' do + # Test helper method parameter passing dataflow + user_id = params[:user_id] + result = vulnerable_helper(user_id) + sink result # $ hasTaintFlow=paramHelper + end + + post '/users' do + # Test helper method return dataflow + user_data = user_params + simple_result = simple_helper + sink user_data # $ hasTaintFlow + sink simple_result # $ hasTaintFlow=simpleHelper + end + + # Test route_param block pattern + route_param :id do + get do + # params[:id] should be user input from the path + user_id = params[:id] + sink user_id # $ hasTaintFlow + end + end + + post '/users' do + user_data = user_params + sink user_data # $ hasTaintFlow + end +end diff --git a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb index 8c9c3bff4fb..1cd6782b241 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb @@ -6,66 +6,4 @@ class PotatoController < ActionController::Base sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") end -end - -class PotatoAPI < Grape::API - get '/unsafe_endpoint' do - name = params[:user_name] - # BAD: SQL statement constructed from user input - sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") - sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") - end -end - -class SimpleAPI < Grape::API - get '/test' do - x = params[:name] - Arel.sql("SELECT * FROM users WHERE name = #{x}") - end -end - - # Test helper method pattern in Grape helpers block - class TestAPI < Grape::API - helpers do - def vulnerable_helper(user_id) - # BAD: SQL statement constructed from user input passed as parameter - Arel.sql("SELECT * FROM users WHERE id = #{user_id}") - end - end - - # Headers and cookies blocks for DSL testing - headers do - requires :Authorization, type: String - end - - cookies do - requires :session_id, type: String - end - - get '/comprehensive_test/:user_id' do - # BAD: Comprehensive test using all Grape input sources in one SQL query - user_id = params[:user_id] # params taint source - route_id = route_param(:user_id) # route_param taint source - auth = headers[:Authorization] # headers taint source - session = cookies[:session_id] # cookies taint source - body_data = request.body.read # request taint source - - # All sources flow to SQL injection - Arel.sql("SELECT * FROM users WHERE id = #{user_id} AND route_id = #{route_id} AND auth = #{auth} AND session = #{session} AND data = #{body_data}") - end - - get '/helper_test' do - # BAD: Test helper method dataflow - user_id = params[:user_id] - vulnerable_helper(user_id) - end - - # Test route_param block pattern - route_param :id do - get do - # BAD: params[:id] should be user input from the path - user_id = params[:id] - Arel.sql("SELECT * FROM users WHERE id = #{user_id}") - end - end - end \ No newline at end of file +end \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 34128474cb9..069cb34810f 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -81,32 +81,6 @@ edges | ArelInjection.rb:4:5:4:8 | name | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:4:12:4:29 | ...[...] | provenance | | | ArelInjection.rb:4:12:4:29 | ...[...] | ArelInjection.rb:4:5:4:8 | name | provenance | | -| ArelInjection.rb:13:5:13:8 | name | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:13:5:13:8 | name | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:13:12:13:29 | ...[...] | provenance | | -| ArelInjection.rb:13:12:13:29 | ...[...] | ArelInjection.rb:13:5:13:8 | name | provenance | | -| ArelInjection.rb:22:5:22:5 | x | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:22:9:22:21 | ...[...] | provenance | | -| ArelInjection.rb:22:9:22:21 | ...[...] | ArelInjection.rb:22:5:22:5 | x | provenance | | -| ArelInjection.rb:30:29:30:35 | user_id | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:47:7:47:13 | user_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:47:17:47:32 | ...[...] | provenance | | -| ArelInjection.rb:47:17:47:32 | ...[...] | ArelInjection.rb:47:7:47:13 | user_id | provenance | | -| ArelInjection.rb:48:7:48:14 | route_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:48:7:48:14 | route_id | provenance | | -| ArelInjection.rb:49:7:49:10 | auth | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:49:14:49:36 | ...[...] | provenance | | -| ArelInjection.rb:49:14:49:36 | ...[...] | ArelInjection.rb:49:7:49:10 | auth | provenance | | -| ArelInjection.rb:50:7:50:13 | session | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:50:17:50:36 | ...[...] | provenance | | -| ArelInjection.rb:50:17:50:36 | ...[...] | ArelInjection.rb:50:7:50:13 | session | provenance | | -| ArelInjection.rb:59:7:59:13 | user_id | ArelInjection.rb:60:25:60:31 | user_id | provenance | | -| ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:59:17:59:32 | ...[...] | provenance | | -| ArelInjection.rb:59:17:59:32 | ...[...] | ArelInjection.rb:59:7:59:13 | user_id | provenance | | -| ArelInjection.rb:60:25:60:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep | -| ArelInjection.rb:67:9:67:15 | user_id | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:67:19:67:29 | ...[...] | provenance | | -| ArelInjection.rb:67:19:67:29 | ...[...] | ArelInjection.rb:67:9:67:15 | user_id | provenance | | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 : String | provenance | AdditionalTaintStep | | PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 : String | provenance | AdditionalTaintStep | @@ -235,37 +209,6 @@ nodes | ArelInjection.rb:4:12:4:29 | ...[...] | semmle.label | ...[...] | | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | -| ArelInjection.rb:13:5:13:8 | name | semmle.label | name | -| ArelInjection.rb:13:12:13:17 | call to params | semmle.label | call to params | -| ArelInjection.rb:13:12:13:29 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | -| ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | -| ArelInjection.rb:22:5:22:5 | x | semmle.label | x | -| ArelInjection.rb:22:9:22:14 | call to params | semmle.label | call to params | -| ArelInjection.rb:22:9:22:21 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | -| ArelInjection.rb:30:29:30:35 | user_id | semmle.label | user_id | -| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | -| ArelInjection.rb:47:7:47:13 | user_id | semmle.label | user_id | -| ArelInjection.rb:47:17:47:22 | call to params | semmle.label | call to params | -| ArelInjection.rb:47:17:47:32 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:48:7:48:14 | route_id | semmle.label | route_id | -| ArelInjection.rb:48:18:48:38 | call to route_param | semmle.label | call to route_param | -| ArelInjection.rb:49:7:49:10 | auth | semmle.label | auth | -| ArelInjection.rb:49:14:49:20 | call to headers | semmle.label | call to headers | -| ArelInjection.rb:49:14:49:36 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:50:7:50:13 | session | semmle.label | session | -| ArelInjection.rb:50:17:50:23 | call to cookies | semmle.label | call to cookies | -| ArelInjection.rb:50:17:50:36 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | -| ArelInjection.rb:59:7:59:13 | user_id | semmle.label | user_id | -| ArelInjection.rb:59:17:59:22 | call to params | semmle.label | call to params | -| ArelInjection.rb:59:17:59:32 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:60:25:60:31 | user_id | semmle.label | user_id | -| ArelInjection.rb:67:9:67:15 | user_id | semmle.label | user_id | -| ArelInjection.rb:67:19:67:24 | call to params | semmle.label | call to params | -| ArelInjection.rb:67:19:67:29 | ...[...] | semmle.label | ...[...] | -| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | | PgInjection.rb:6:5:6:8 | name | semmle.label | name | | PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params | | PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] | @@ -323,15 +266,6 @@ subpaths | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | ActiveRecordInjection.rb:222:29:222:34 | call to params | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:222:29:222:34 | call to params | user-provided value | | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | -| ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | -| ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value | -| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:22:9:22:14 | call to params | user-provided value | -| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:59:17:59:22 | call to params | user-provided value | -| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:47:17:47:22 | call to params | user-provided value | -| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:48:18:48:38 | call to route_param | user-provided value | -| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:49:14:49:20 | call to headers | user-provided value | -| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:50:17:50:23 | call to cookies | user-provided value | -| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:67:19:67:24 | call to params | user-provided value | | PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | From 95a84ad6559f4180039dac0dc07dcd1b4d7756ee Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 19 Sep 2025 15:06:46 +0000 Subject: [PATCH 24/90] Python: Fix false positive for unmatchable dollar/caret Our previous modelling did not account for the fact that a lookahead can potentially extend all the way to the end of the input (and similarly, that a lookbehind can extend all the way to the beginning). To fix this, I extended `firstPart` and `lastPart` to handle lookbehinds and lookaheads correctly, and added some test cases (all of which yield no new results). Fixes #20429. --- .../semmle/python/regexp/RegexTreeView.qll | 8 +-- .../python/regexp/internal/ParseRegExp.qll | 70 ++++++++++++------- ...atchable-dollar-and-caret-in-assertions.md | 5 ++ .../query-tests/Expressions/Regex/test.py | 10 ++- 4 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md diff --git a/python/ql/lib/semmle/python/regexp/RegexTreeView.qll b/python/ql/lib/semmle/python/regexp/RegexTreeView.qll index a2952a5680b..897c97bb783 100644 --- a/python/ql/lib/semmle/python/regexp/RegexTreeView.qll +++ b/python/ql/lib/semmle/python/regexp/RegexTreeView.qll @@ -964,7 +964,7 @@ module Impl implements RegexTreeViewSig { * ``` */ class RegExpPositiveLookahead extends RegExpLookahead { - RegExpPositiveLookahead() { re.positiveLookaheadAssertionGroup(start, end) } + RegExpPositiveLookahead() { re.positiveLookaheadAssertionGroup(start, end, _, _) } override string getPrimaryQLClass() { result = "RegExpPositiveLookahead" } } @@ -979,7 +979,7 @@ module Impl implements RegexTreeViewSig { * ``` */ additional class RegExpNegativeLookahead extends RegExpLookahead { - RegExpNegativeLookahead() { re.negativeLookaheadAssertionGroup(start, end) } + RegExpNegativeLookahead() { re.negativeLookaheadAssertionGroup(start, end, _, _) } override string getPrimaryQLClass() { result = "RegExpNegativeLookahead" } } @@ -1006,7 +1006,7 @@ module Impl implements RegexTreeViewSig { * ``` */ class RegExpPositiveLookbehind extends RegExpLookbehind { - RegExpPositiveLookbehind() { re.positiveLookbehindAssertionGroup(start, end) } + RegExpPositiveLookbehind() { re.positiveLookbehindAssertionGroup(start, end, _, _) } override string getPrimaryQLClass() { result = "RegExpPositiveLookbehind" } } @@ -1021,7 +1021,7 @@ module Impl implements RegexTreeViewSig { * ``` */ additional class RegExpNegativeLookbehind extends RegExpLookbehind { - RegExpNegativeLookbehind() { re.negativeLookbehindAssertionGroup(start, end) } + RegExpNegativeLookbehind() { re.negativeLookbehindAssertionGroup(start, end, _, _) } override string getPrimaryQLClass() { result = "RegExpNegativeLookbehind" } } diff --git a/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll b/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll index 7e23554e058..d91c4bbd78c 100644 --- a/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll +++ b/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll @@ -554,9 +554,9 @@ class RegExp extends Expr instanceof StringLiteral { or this.negativeAssertionGroup(start, end) or - this.positiveLookaheadAssertionGroup(start, end) + this.positiveLookaheadAssertionGroup(start, end, _, _) or - this.positiveLookbehindAssertionGroup(start, end) + this.positiveLookbehindAssertionGroup(start, end, _, _) } /** Holds if an empty group is found between `start` and `end`. */ @@ -572,7 +572,7 @@ class RegExp extends Expr instanceof StringLiteral { or this.negativeAssertionGroup(start, end) or - this.positiveLookaheadAssertionGroup(start, end) + this.positiveLookaheadAssertionGroup(start, end, _, _) } private predicate emptyMatchAtEndGroup(int start, int end) { @@ -580,7 +580,7 @@ class RegExp extends Expr instanceof StringLiteral { or this.negativeAssertionGroup(start, end) or - this.positiveLookbehindAssertionGroup(start, end) + this.positiveLookbehindAssertionGroup(start, end, _, _) } private predicate negativeAssertionGroup(int start, int end) { @@ -593,32 +593,40 @@ class RegExp extends Expr instanceof StringLiteral { ) } - /** Holds if a negative lookahead is found between `start` and `end` */ - predicate negativeLookaheadAssertionGroup(int start, int end) { - exists(int in_start | this.negative_lookahead_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) + /** + * Holds if a negative lookahead is found between `start` and `end`, with contents + * between `in_start` and `in_end`. + */ + predicate negativeLookaheadAssertionGroup(int start, int end, int in_start, int in_end) { + this.negative_lookahead_assertion_start(start, in_start) and + this.groupContents(start, end, in_start, in_end) } - /** Holds if a negative lookbehind is found between `start` and `end` */ - predicate negativeLookbehindAssertionGroup(int start, int end) { - exists(int in_start | this.negative_lookbehind_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) + /** + * Holds if a negative lookbehind is found between `start` and `end`, with contents + * between `in_start` and `in_end`. + */ + predicate negativeLookbehindAssertionGroup(int start, int end, int in_start, int in_end) { + this.negative_lookbehind_assertion_start(start, in_start) and + this.groupContents(start, end, in_start, in_end) } - /** Holds if a positive lookahead is found between `start` and `end` */ - predicate positiveLookaheadAssertionGroup(int start, int end) { - exists(int in_start | this.lookahead_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) + /** + * Holds if a positive lookahead is found between `start` and `end`, with contents + * between `in_start` and `in_end`. + */ + predicate positiveLookaheadAssertionGroup(int start, int end, int in_start, int in_end) { + this.lookahead_assertion_start(start, in_start) and + this.groupContents(start, end, in_start, in_end) } - /** Holds if a positive lookbehind is found between `start` and `end` */ - predicate positiveLookbehindAssertionGroup(int start, int end) { - exists(int in_start | this.lookbehind_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) + /** + * Holds if a positive lookbehind is found between `start` and `end`, with contents + * between `in_start` and `in_end`. + */ + predicate positiveLookbehindAssertionGroup(int start, int end, int in_start, int in_end) { + this.lookbehind_assertion_start(start, in_start) and + this.groupContents(start, end, in_start, in_end) } private predicate group_start(int start, int end) { @@ -1049,6 +1057,13 @@ class RegExp extends Expr instanceof StringLiteral { or this.alternationOption(x, y, start, end) ) + or + // Lookbehind assertions can potentially match the start of the string + ( + this.positiveLookbehindAssertionGroup(_, _, start, _) or + this.negativeLookbehindAssertionGroup(_, _, start, _) + ) and + this.item(start, end) } /** A part of the regex that may match the end of the string. */ @@ -1074,6 +1089,13 @@ class RegExp extends Expr instanceof StringLiteral { or this.alternationOption(x, y, start, end) ) + or + // Lookahead assertions can potentially match the end of the string + ( + this.positiveLookaheadAssertionGroup(_, _, _, end) or + this.negativeLookaheadAssertionGroup(_, _, _, end) + ) and + this.item(start, end) } /** diff --git a/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md b/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md new file mode 100644 index 00000000000..cf63dd9ed4d --- /dev/null +++ b/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + +- The queries that check for unmatchable `$` and `^` in regular expressions did not account correctly for occurrences inside lookahead and lookbehind assertions. These occurrences are now handled correctly, eliminating this source of false positives. diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index 6dadbccb4b6..717663e335c 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -150,4 +150,12 @@ re.compile(r"[\U00010000-\U0010FFFF]") re.compile(r"[\u0000-\uFFFF]") #Allow unicode names -re.compile(r"[\N{degree sign}\N{EM DASH}]") \ No newline at end of file +re.compile(r"[\N{degree sign}\N{EM DASH}]") + +#Lookahead assertions. None of these are unmatchable dollars: +re.compile(r"^(?=a$)[ab]") +re.compile(r"^(?!a$)[ab]") + +#Lookbehind assertions. None of these are unmatchable carets: +re.compile(r"(?<=^a)a") +re.compile(r"(? Date: Fri, 19 Sep 2025 15:39:12 +0000 Subject: [PATCH 25/90] Python: Update test output --- python/ql/test/library-tests/regex/FirstLast.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/test/library-tests/regex/FirstLast.expected b/python/ql/test/library-tests/regex/FirstLast.expected index b187033ee22..0abf9c790c2 100644 --- a/python/ql/test/library-tests/regex/FirstLast.expected +++ b/python/ql/test/library-tests/regex/FirstLast.expected @@ -4,6 +4,7 @@ | (?!not-this)^[A-Z_]+$ | first | 12 | 13 | | (?!not-this)^[A-Z_]+$ | first | 13 | 19 | | (?!not-this)^[A-Z_]+$ | first | 13 | 20 | +| (?!not-this)^[A-Z_]+$ | last | 3 | 11 | | (?!not-this)^[A-Z_]+$ | last | 13 | 19 | | (?!not-this)^[A-Z_]+$ | last | 13 | 20 | | (?!not-this)^[A-Z_]+$ | last | 20 | 21 | @@ -101,6 +102,7 @@ | ^[A-Z_]+$(? Date: Fri, 19 Sep 2025 16:49:54 +0100 Subject: [PATCH 26/90] Apply suggestions from code review Co-authored-by: Simon Friis Vindum --- rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp index e4e0fc5eaa9..088f202965a 100644 --- a/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp +++ b/rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp @@ -4,7 +4,7 @@ -

    Constructing URLs with the HTTP protocol can lead to unsecured connections.

    +

    Constructing URLs with the HTTP protocol can lead to insecure connections.

    Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections, @@ -14,7 +14,7 @@ which may fail or fall back to insecure behavior when provided with HTTP URLs in

    When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL. -Then, any connections that are made using that URL are secure SSL/TLS connections.

    +Then, any connections that are made using that URL are secure TLS connections.

    @@ -26,7 +26,7 @@ by attackers:

    A better approach is to use HTTPS. When the request is made using an HTTPS URL, the connection -is a secure SSL/TLS connection:

    +is a secure TLS connection:

    From 89e9ee43c00159a561bbad75b43296acefd87ef7 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 19 Sep 2025 18:28:45 -0400 Subject: [PATCH 27/90] Convert from GrapeHelperMethodTaintStep extends AdditionalTaintStep to a simplified GrapeHelperMethodTarget extends AdditionalCallTarget --- .../2025-09-15-grape-framework-support.md | 2 +- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 39 +++++++------------ .../frameworks/grape/Flow.expected | 36 +++++++++++++++-- .../library-tests/frameworks/grape/app.rb | 4 +- 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md b/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md index 258da40d36c..08ceed887f2 100644 --- a/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md +++ b/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md @@ -1,4 +1,4 @@ --- category: feature --- -* Initial modeling for the Ruby Grape framework in `Grape.qll` have been added to detect API endpoints, parameters, and headers within Grape API classes. \ No newline at end of file +* Initial modeling for the Ruby Grape framework in `Grape.qll` has been added to detect API endpoints, parameters, and headers within Grape API classes. \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index a1646b8654c..31632e01948 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -3,6 +3,7 @@ */ private import codeql.ruby.AST +private import codeql.ruby.CFG private import codeql.ruby.Concepts private import codeql.ruby.controlflow.CfgNodes private import codeql.ruby.DataFlow @@ -301,32 +302,20 @@ private class GrapeHelperMethod extends Method { } /** - * Additional taint step to model dataflow from method arguments to parameters - * and from return values back to call sites for Grape helper methods defined in `helpers` blocks. - * This bridges the gap where standard dataflow doesn't recognize the Grape DSL semantics. + * Additional call-target to resolve helper method calls defined in `helpers` blocks. + * + * This class is responsible for resolving calls to helper methods defined in + * `helpers` blocks, allowing the dataflow framework to accurately track + * the flow of information between these methods and their call sites. */ -private class GrapeHelperMethodTaintStep extends AdditionalTaintStep { - override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Map arguments to parameters for helper method calls - exists(GrapeHelperMethod helperMethod, MethodCall call, int i | - // Find calls to helper methods from within Grape endpoints or other helper methods - call.getMethodName() = helperMethod.getName() and - exists(GrapeApiClass api | call.getParent+() = api.getADeclaration()) and - // Map argument to parameter - nodeFrom.asExpr().getExpr() = call.getArgument(i) and - nodeTo.asParameter() = helperMethod.getParameter(i) - ) - or - // Model implicit return values: the last expression in a helper method flows to the call site - exists(GrapeHelperMethod helperMethod, MethodCall helperCall, Expr lastExpr | - // Find calls to helper methods from within Grape endpoints or other helper methods - helperCall.getMethodName() = helperMethod.getName() and - exists(GrapeApiClass api | helperCall.getParent+() = api.getADeclaration()) and - // Get the last expression in the helper method (Ruby's implicit return) - lastExpr = helperMethod.getLastStmt() and - // Flow from the last expression in the helper method to the call site - nodeFrom.asExpr().getExpr() = lastExpr and - nodeTo.asExpr().getExpr() = helperCall +private class GrapeHelperMethodTarget extends AdditionalCallTarget { + override DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallCfgNode call) { + // Find calls to helper methods from within Grape endpoints or other helper methods + exists(GrapeHelperMethod helperMethod, MethodCall mc | + result.asCfgScope() = helperMethod and + mc = call.getAstNode() and + mc.getMethodName() = helperMethod.getName() and + mc.getParent+() = helperMethod.getApiClass().getADeclaration() ) } } diff --git a/ruby/ql/test/library-tests/frameworks/grape/Flow.expected b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected index 0fd19d4eace..c104b36afb2 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Flow.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected @@ -1,10 +1,15 @@ models edges | app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select | provenance | | -| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | AdditionalTaintStep | -| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | AdditionalTaintStep | -| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | AdditionalTaintStep | -| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | AdditionalTaintStep | +| app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select : [collection] [element] | provenance | | +| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | | +| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | | +| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:149:21:149:31 | call to user_params : [collection] [element] | provenance | | +| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:165:21:165:31 | call to user_params : [collection] [element] | provenance | | +| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | | +| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | | +| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | | +| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | | | app.rb:126:9:126:15 | user_id | app.rb:133:14:133:20 | user_id | provenance | | | app.rb:126:19:126:24 | call to params | app.rb:126:19:126:34 | ...[...] | provenance | | | app.rb:126:19:126:34 | ...[...] | app.rb:126:9:126:15 | user_id | provenance | | @@ -17,20 +22,31 @@ edges | app.rb:129:19:129:25 | call to cookies | app.rb:129:19:129:38 | ...[...] | provenance | | | app.rb:129:19:129:38 | ...[...] | app.rb:129:9:129:15 | session | provenance | | | app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | | +| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | | +| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | | | app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | | | app.rb:149:9:149:17 | user_data | app.rb:151:14:151:22 | user_data | provenance | | +| app.rb:149:9:149:17 | user_data : [collection] [element] | app.rb:151:14:151:22 | user_data | provenance | | | app.rb:149:21:149:31 | call to user_params | app.rb:149:9:149:17 | user_data | provenance | | +| app.rb:149:21:149:31 | call to user_params : [collection] [element] | app.rb:149:9:149:17 | user_data : [collection] [element] | provenance | | | app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | | +| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | | +| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | | | app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | | | app.rb:159:13:159:19 | user_id | app.rb:160:18:160:24 | user_id | provenance | | | app.rb:159:23:159:28 | call to params | app.rb:159:23:159:33 | ...[...] | provenance | | | app.rb:159:23:159:33 | ...[...] | app.rb:159:13:159:19 | user_id | provenance | | | app.rb:165:9:165:17 | user_data | app.rb:166:14:166:22 | user_data | provenance | | +| app.rb:165:9:165:17 | user_data : [collection] [element] | app.rb:166:14:166:22 | user_data | provenance | | | app.rb:165:21:165:31 | call to user_params | app.rb:165:9:165:17 | user_data | provenance | | +| app.rb:165:21:165:31 | call to user_params : [collection] [element] | app.rb:165:9:165:17 | user_data : [collection] [element] | provenance | | nodes | app.rb:103:13:103:18 | call to params | semmle.label | call to params | | app.rb:103:13:103:70 | call to select | semmle.label | call to select | +| app.rb:103:13:103:70 | call to select : [collection] [element] | semmle.label | call to select : [collection] [element] | | app.rb:107:13:107:32 | call to source | semmle.label | call to source | +| app.rb:107:13:107:32 | call to source | semmle.label | call to source | +| app.rb:111:13:111:33 | call to source | semmle.label | call to source | | app.rb:111:13:111:33 | call to source | semmle.label | call to source | | app.rb:126:9:126:15 | user_id | semmle.label | user_id | | app.rb:126:19:126:24 | call to params | semmle.label | call to params | @@ -48,20 +64,30 @@ nodes | app.rb:135:14:135:17 | auth | semmle.label | auth | | app.rb:136:14:136:20 | session | semmle.label | session | | app.rb:143:9:143:14 | result | semmle.label | result | +| app.rb:143:9:143:14 | result | semmle.label | result | +| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | | app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | | app.rb:144:14:144:19 | result | semmle.label | result | +| app.rb:144:14:144:19 | result | semmle.label | result | | app.rb:149:9:149:17 | user_data | semmle.label | user_data | +| app.rb:149:9:149:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | | app.rb:149:21:149:31 | call to user_params | semmle.label | call to user_params | +| app.rb:149:21:149:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | +| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result | | app.rb:150:9:150:21 | simple_result | semmle.label | simple_result | | app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper | +| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper | | app.rb:151:14:151:22 | user_data | semmle.label | user_data | | app.rb:152:14:152:26 | simple_result | semmle.label | simple_result | +| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result | | app.rb:159:13:159:19 | user_id | semmle.label | user_id | | app.rb:159:23:159:28 | call to params | semmle.label | call to params | | app.rb:159:23:159:33 | ...[...] | semmle.label | ...[...] | | app.rb:160:18:160:24 | user_id | semmle.label | user_id | | app.rb:165:9:165:17 | user_data | semmle.label | user_data | +| app.rb:165:9:165:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | | app.rb:165:21:165:31 | call to user_params | semmle.label | call to user_params | +| app.rb:165:21:165:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | | app.rb:166:14:166:22 | user_data | semmle.label | user_data | subpaths testFailures @@ -71,7 +97,9 @@ testFailures | app.rb:135:14:135:17 | auth | app.rb:128:16:128:22 | call to headers | app.rb:135:14:135:17 | auth | $@ | app.rb:128:16:128:22 | call to headers | call to headers | | app.rb:136:14:136:20 | session | app.rb:129:19:129:25 | call to cookies | app.rb:136:14:136:20 | session | $@ | app.rb:129:19:129:25 | call to cookies | call to cookies | | app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | +| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | | app.rb:151:14:151:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:151:14:151:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | | app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | +| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | | app.rb:160:18:160:24 | user_id | app.rb:159:23:159:28 | call to params | app.rb:160:18:160:24 | user_id | $@ | app.rb:159:23:159:28 | call to params | call to params | | app.rb:166:14:166:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:166:14:166:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb index 6fbb184cab9..81f46482687 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/app.rb +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -141,7 +141,7 @@ class UserAPI < Grape::API # Test helper method parameter passing dataflow user_id = params[:user_id] result = vulnerable_helper(user_id) - sink result # $ hasTaintFlow=paramHelper + sink result # $ hasValueFlow=paramHelper end post '/users' do @@ -149,7 +149,7 @@ class UserAPI < Grape::API user_data = user_params simple_result = simple_helper sink user_data # $ hasTaintFlow - sink simple_result # $ hasTaintFlow=simpleHelper + sink simple_result # $ hasValueFlow=simpleHelper end # Test route_param block pattern From f4bbbc346fe5b270f6fbfc3ed351fdfdaee3fa46 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 19 Sep 2025 19:06:50 -0400 Subject: [PATCH 28/90] Refactor Grape framework to be encapsulated properly in Module --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 550 +++++++++--------- .../library-tests/frameworks/grape/Grape.ql | 14 +- 2 files changed, 285 insertions(+), 279 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 31632e01948..0999be94505 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -29,293 +29,299 @@ module Grape { not exists(GrapeApiClass parent | this != parent and this = parent.getADescendent()) } } -} -/** - * A class that extends `Grape::API`. - * For example, - * - * ```rb - * class FooAPI < Grape::API - * get '/users' do - * name = params[:name] - * User.where("name = #{name}") - * end - * end - * ``` - */ -class GrapeApiClass extends DataFlow::ClassNode { - GrapeApiClass() { - this = grapeApiBaseClass().getADescendentModule() and - not exists(DataFlow::ModuleNode m | m = grapeApiBaseClass().asModule() | this = m) + /** + * A class that extends `Grape::API`. + * For example, + * + * ```rb + * class FooAPI < Grape::API + * get '/users' do + * name = params[:name] + * User.where("name = #{name}") + * end + * end + * ``` + */ + class GrapeApiClass extends DataFlow::ClassNode { + GrapeApiClass() { + this = grapeApiBaseClass().getADescendentModule() and + not exists(DataFlow::ModuleNode m | m = grapeApiBaseClass().asModule() | this = m) + } + + /** + * Gets a `GrapeEndpoint` defined in this class. + */ + GrapeEndpoint getAnEndpoint() { result.getApiClass() = this } + + /** + * Gets a `self` that possibly refers to an instance of this class. + */ + DataFlow::LocalSourceNode getSelf() { + result = this.getAnInstanceSelf() + or + // Include the module-level `self` to recover some cases where a block at the module level + // is invoked with an instance as the `self`. + result = this.getModuleLevelSelf() + } + } + + private DataFlow::ConstRef grapeApiBaseClass() { + result = DataFlow::getConstant("Grape").getConstant("API") + } + + private API::Node grapeApiInstance() { result = any(GrapeApiClass cls).getSelf().track() } + + /** + * A Grape API endpoint (get, post, put, delete, etc.) call within a `Grape::API` class. + */ + class GrapeEndpoint extends DataFlow::CallNode { + private GrapeApiClass apiClass; + + GrapeEndpoint() { + this = + apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) + } + + /** + * Gets the HTTP method for this endpoint (e.g., "GET", "POST", etc.) + */ + string getHttpMethod() { result = this.getMethodName().toUpperCase() } + + /** + * Gets the API class containing this endpoint. + */ + GrapeApiClass getApiClass() { result = apiClass } + + /** + * Gets the block containing the endpoint logic. + */ + DataFlow::BlockNode getBody() { result = this.getBlock() } + + /** + * Gets the path pattern for this endpoint, if specified. + */ + string getPath() { result = this.getArgument(0).getConstantValue().getString() } } /** - * Gets a `GrapeEndpoint` defined in this class. + * A `RemoteFlowSource::Range` to represent accessing the + * Grape parameters available via the `params` method within an endpoint. */ - GrapeEndpoint getAnEndpoint() { result.getApiClass() = this } + class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { + GrapeParamsSource() { this.asExpr().getExpr() instanceof GrapeParamsCall } - /** - * Gets a `self` that possibly refers to an instance of this class. - */ - DataFlow::LocalSourceNode getSelf() { - result = this.getAnInstanceSelf() - or - // Include the module-level `self` to recover some cases where a block at the module level - // is invoked with an instance as the `self`. - result = this.getModuleLevelSelf() - } -} + override string getSourceType() { result = "Grape::API#params" } -private DataFlow::ConstRef grapeApiBaseClass() { - result = DataFlow::getConstant("Grape").getConstant("API") -} - -private API::Node grapeApiInstance() { result = any(GrapeApiClass cls).getSelf().track() } - -/** - * A Grape API endpoint (get, post, put, delete, etc.) call within a `Grape::API` class. - */ -class GrapeEndpoint extends DataFlow::CallNode { - private GrapeApiClass apiClass; - - GrapeEndpoint() { - this = - apiClass.getAModuleLevelCall(["get", "post", "put", "delete", "patch", "head", "options"]) + override Http::Server::RequestInputKind getKind() { + result = Http::Server::parameterInputKind() + } } /** - * Gets the HTTP method for this endpoint (e.g., "GET", "POST", etc.) + * A call to `params` from within a Grape API endpoint or helper method. */ - string getHttpMethod() { result = this.getMethodName().toUpperCase() } - - /** - * Gets the API class containing this endpoint. - */ - GrapeApiClass getApiClass() { result = apiClass } - - /** - * Gets the block containing the endpoint logic. - */ - DataFlow::BlockNode getBody() { result = this.getBlock() } - - /** - * Gets the path pattern for this endpoint, if specified. - */ - string getPath() { result = this.getArgument(0).getConstantValue().getString() } -} - -/** - * A `RemoteFlowSource::Range` to represent accessing the - * Grape parameters available via the `params` method within an endpoint. - */ -class GrapeParamsSource extends Http::Server::RequestInputAccess::Range { - GrapeParamsSource() { this.asExpr().getExpr() instanceof GrapeParamsCall } - - override string getSourceType() { result = "Grape::API#params" } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } -} - -/** - * A call to `params` from within a Grape API endpoint or helper method. - */ -private class GrapeParamsCall extends ParamsCallImpl { - GrapeParamsCall() { - // Params calls within endpoint blocks - exists(GrapeApiClass api | - this.getMethodName() = "params" and - this.getParent+() = api.getADeclaration() - ) - or - // Params calls within helper methods (defined in helpers blocks) - exists(GrapeApiClass api, DataFlow::CallNode helpersCall | - helpersCall = api.getAModuleLevelCall("helpers") and - this.getMethodName() = "params" and - this.getParent+() = helpersCall.getBlock().asExpr().getExpr() - ) - } -} - -/** - * A call to `headers` from within a Grape API endpoint or headers block. - * Headers can also be a source of user input. - */ -class GrapeHeadersSource extends Http::Server::RequestInputAccess::Range { - GrapeHeadersSource() { - this.asExpr().getExpr() instanceof GrapeHeadersCall - or - this.asExpr().getExpr() instanceof GrapeHeadersBlockCall - } - - override string getSourceType() { result = "Grape::API#headers" } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } -} - -/** - * A call to `headers` from within a Grape API endpoint. - */ -private class GrapeHeadersCall extends MethodCall { - GrapeHeadersCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "headers" - ) - or - // Also handle cases where headers is called on an instance of a Grape API class - this = grapeApiInstance().getAMethodCall("headers").asExpr().getExpr() - } -} - -/** - * A call to `request` from within a Grape API endpoint. - * The request object can contain user input. - */ -class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { - GrapeRequestSource() { this.asExpr().getExpr() instanceof GrapeRequestCall } - - override string getSourceType() { result = "Grape::API#request" } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } -} - -/** - * A call to `route_param` from within a Grape API endpoint. - * Route parameters are extracted from the URL path and can be a source of user input. - */ -class GrapeRouteParamSource extends Http::Server::RequestInputAccess::Range { - GrapeRouteParamSource() { this.asExpr().getExpr() instanceof GrapeRouteParamCall } - - override string getSourceType() { result = "Grape::API#route_param" } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() } -} - -/** - * A call to `request` from within a Grape API endpoint. - */ -private class GrapeRequestCall extends MethodCall { - GrapeRequestCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "request" - ) - or - // Also handle cases where request is called on an instance of a Grape API class - this = grapeApiInstance().getAMethodCall("request").asExpr().getExpr() - } -} - -/** - * A call to `route_param` from within a Grape API endpoint. - */ -private class GrapeRouteParamCall extends MethodCall { - GrapeRouteParamCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asExpr().getExpr() and - this.getMethodName() = "route_param" - ) - or - // Also handle cases where route_param is called on an instance of a Grape API class - this = grapeApiInstance().getAMethodCall("route_param").asExpr().getExpr() - } -} - -/** - * A call to `headers` block within a Grape API class. - * This is different from the headers() method call - this is the DSL block for defining header requirements. - */ -private class GrapeHeadersBlockCall extends MethodCall { - GrapeHeadersBlockCall() { - exists(GrapeApiClass api | - this.getParent+() = api.getADeclaration() and - this.getMethodName() = "headers" and - exists(this.getBlock()) - ) - } -} - -/** - * A call to `cookies` block within a Grape API class. - * This DSL block defines cookie requirements and those cookies are user-controlled. - */ -private class GrapeCookiesBlockCall extends MethodCall { - GrapeCookiesBlockCall() { - exists(GrapeApiClass api | - this.getParent+() = api.getADeclaration() and - this.getMethodName() = "cookies" and - exists(this.getBlock()) - ) - } -} - -/** - * A call to `cookies` method from within a Grape API endpoint or cookies block. - * Similar to headers, cookies can be accessed as a method and are user-controlled input. - */ -class GrapeCookiesSource extends Http::Server::RequestInputAccess::Range { - GrapeCookiesSource() { - this.asExpr().getExpr() instanceof GrapeCookiesCall - or - this.asExpr().getExpr() instanceof GrapeCookiesBlockCall - } - - override string getSourceType() { result = "Grape::API#cookies" } - - override Http::Server::RequestInputKind getKind() { result = Http::Server::cookieInputKind() } -} - -/** - * A call to `cookies` method from within a Grape API endpoint. - */ -private class GrapeCookiesCall extends MethodCall { - GrapeCookiesCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "cookies" - ) - or - // Also handle cases where cookies is called on an instance of a Grape API class - this = grapeApiInstance().getAMethodCall("cookies").asExpr().getExpr() - } -} - -/** - * A method defined within a `helpers` block in a Grape API class. - * These methods become available in endpoint contexts through Grape's DSL. - */ -private class GrapeHelperMethod extends Method { - private GrapeApiClass apiClass; - - GrapeHelperMethod() { - exists(DataFlow::CallNode helpersCall | - helpersCall = apiClass.getAModuleLevelCall("helpers") and - this.getParent+() = helpersCall.getBlock().asExpr().getExpr() - ) + private class GrapeParamsCall extends ParamsCallImpl { + GrapeParamsCall() { + // Params calls within endpoint blocks + exists(GrapeApiClass api | + this.getMethodName() = "params" and + this.getParent+() = api.getADeclaration() + ) + or + // Params calls within helper methods (defined in helpers blocks) + exists(GrapeApiClass api, DataFlow::CallNode helpersCall | + helpersCall = api.getAModuleLevelCall("helpers") and + this.getMethodName() = "params" and + this.getParent+() = helpersCall.getBlock().asExpr().getExpr() + ) + } } /** - * Gets the API class that contains this helper method. + * A call to `headers` from within a Grape API endpoint or headers block. + * Headers can also be a source of user input. */ - GrapeApiClass getApiClass() { result = apiClass } -} + class GrapeHeadersSource extends Http::Server::RequestInputAccess::Range { + GrapeHeadersSource() { + this.asExpr().getExpr() instanceof GrapeHeadersCall + or + this.asExpr().getExpr() instanceof GrapeHeadersBlockCall + } -/** - * Additional call-target to resolve helper method calls defined in `helpers` blocks. - * - * This class is responsible for resolving calls to helper methods defined in - * `helpers` blocks, allowing the dataflow framework to accurately track - * the flow of information between these methods and their call sites. - */ -private class GrapeHelperMethodTarget extends AdditionalCallTarget { - override DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallCfgNode call) { - // Find calls to helper methods from within Grape endpoints or other helper methods - exists(GrapeHelperMethod helperMethod, MethodCall mc | - result.asCfgScope() = helperMethod and - mc = call.getAstNode() and - mc.getMethodName() = helperMethod.getName() and - mc.getParent+() = helperMethod.getApiClass().getADeclaration() - ) + override string getSourceType() { result = "Grape::API#headers" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() } + } + + /** + * A call to `headers` from within a Grape API endpoint. + */ + private class GrapeHeadersCall extends MethodCall { + GrapeHeadersCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "headers" + ) + or + // Also handle cases where headers is called on an instance of a Grape API class + this = grapeApiInstance().getAMethodCall("headers").asExpr().getExpr() + } + } + + /** + * A call to `request` from within a Grape API endpoint. + * The request object can contain user input. + */ + class GrapeRequestSource extends Http::Server::RequestInputAccess::Range { + GrapeRequestSource() { this.asExpr().getExpr() instanceof GrapeRequestCall } + + override string getSourceType() { result = "Grape::API#request" } + + override Http::Server::RequestInputKind getKind() { + result = Http::Server::parameterInputKind() + } + } + + /** + * A call to `route_param` from within a Grape API endpoint. + * Route parameters are extracted from the URL path and can be a source of user input. + */ + class GrapeRouteParamSource extends Http::Server::RequestInputAccess::Range { + GrapeRouteParamSource() { this.asExpr().getExpr() instanceof GrapeRouteParamCall } + + override string getSourceType() { result = "Grape::API#route_param" } + + override Http::Server::RequestInputKind getKind() { + result = Http::Server::parameterInputKind() + } + } + + /** + * A call to `request` from within a Grape API endpoint. + */ + private class GrapeRequestCall extends MethodCall { + GrapeRequestCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "request" + ) + or + // Also handle cases where request is called on an instance of a Grape API class + this = grapeApiInstance().getAMethodCall("request").asExpr().getExpr() + } + } + + /** + * A call to `route_param` from within a Grape API endpoint. + */ + private class GrapeRouteParamCall extends MethodCall { + GrapeRouteParamCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asExpr().getExpr() and + this.getMethodName() = "route_param" + ) + or + // Also handle cases where route_param is called on an instance of a Grape API class + this = grapeApiInstance().getAMethodCall("route_param").asExpr().getExpr() + } + } + + /** + * A call to `headers` block within a Grape API class. + * This is different from the headers() method call - this is the DSL block for defining header requirements. + */ + private class GrapeHeadersBlockCall extends MethodCall { + GrapeHeadersBlockCall() { + exists(GrapeApiClass api | + this.getParent+() = api.getADeclaration() and + this.getMethodName() = "headers" and + exists(this.getBlock()) + ) + } + } + + /** + * A call to `cookies` block within a Grape API class. + * This DSL block defines cookie requirements and those cookies are user-controlled. + */ + private class GrapeCookiesBlockCall extends MethodCall { + GrapeCookiesBlockCall() { + exists(GrapeApiClass api | + this.getParent+() = api.getADeclaration() and + this.getMethodName() = "cookies" and + exists(this.getBlock()) + ) + } + } + + /** + * A call to `cookies` method from within a Grape API endpoint or cookies block. + * Similar to headers, cookies can be accessed as a method and are user-controlled input. + */ + class GrapeCookiesSource extends Http::Server::RequestInputAccess::Range { + GrapeCookiesSource() { + this.asExpr().getExpr() instanceof GrapeCookiesCall + or + this.asExpr().getExpr() instanceof GrapeCookiesBlockCall + } + + override string getSourceType() { result = "Grape::API#cookies" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::cookieInputKind() } + } + + /** + * A call to `cookies` method from within a Grape API endpoint. + */ + private class GrapeCookiesCall extends MethodCall { + GrapeCookiesCall() { + exists(GrapeEndpoint endpoint | + this.getParent+() = endpoint.getBody().asCallableAstNode() and + this.getMethodName() = "cookies" + ) + or + // Also handle cases where cookies is called on an instance of a Grape API class + this = grapeApiInstance().getAMethodCall("cookies").asExpr().getExpr() + } + } + + /** + * A method defined within a `helpers` block in a Grape API class. + * These methods become available in endpoint contexts through Grape's DSL. + */ + private class GrapeHelperMethod extends Method { + private GrapeApiClass apiClass; + + GrapeHelperMethod() { + exists(DataFlow::CallNode helpersCall | + helpersCall = apiClass.getAModuleLevelCall("helpers") and + this.getParent+() = helpersCall.getBlock().asExpr().getExpr() + ) + } + + /** + * Gets the API class that contains this helper method. + */ + GrapeApiClass getApiClass() { result = apiClass } + } + + /** + * Additional call-target to resolve helper method calls defined in `helpers` blocks. + * + * This class is responsible for resolving calls to helper methods defined in + * `helpers` blocks, allowing the dataflow framework to accurately track + * the flow of information between these methods and their call sites. + */ + private class GrapeHelperMethodTarget extends AdditionalCallTarget { + override DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallCfgNode call) { + // Find calls to helper methods from within Grape endpoints or other helper methods + exists(GrapeHelperMethod helperMethod, MethodCall mc | + result.asCfgScope() = helperMethod and + mc = call.getAstNode() and + mc.getMethodName() = helperMethod.getName() and + mc.getParent+() = helperMethod.getApiClass().getADeclaration() + ) + } } } diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index c9aa7c29082..c5f0798f7a6 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -3,20 +3,20 @@ import codeql.ruby.frameworks.Grape import codeql.ruby.Concepts import codeql.ruby.AST -query predicate grapeApiClasses(GrapeApiClass api) { any() } +query predicate grapeApiClasses(Grape::GrapeApiClass api) { any() } -query predicate grapeEndpoints(GrapeApiClass api, GrapeEndpoint endpoint, string method, string path) { +query predicate grapeEndpoints(Grape::GrapeApiClass api, Grape::GrapeEndpoint endpoint, string method, string path) { endpoint = api.getAnEndpoint() and method = endpoint.getHttpMethod() and path = endpoint.getPath() } -query predicate grapeParams(GrapeParamsSource params) { any() } +query predicate grapeParams(Grape::GrapeParamsSource params) { any() } -query predicate grapeHeaders(GrapeHeadersSource headers) { any() } +query predicate grapeHeaders(Grape::GrapeHeadersSource headers) { any() } -query predicate grapeRequest(GrapeRequestSource request) { any() } +query predicate grapeRequest(Grape::GrapeRequestSource request) { any() } -query predicate grapeRouteParam(GrapeRouteParamSource routeParam) { any() } +query predicate grapeRouteParam(Grape::GrapeRouteParamSource routeParam) { any() } -query predicate grapeCookies(GrapeCookiesSource cookies) { any() } +query predicate grapeCookies(Grape::GrapeCookiesSource cookies) { any() } From bdeeb3217ec087d58345cdfcf813d3a56a5050ad Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 19 Sep 2025 15:06:47 +0200 Subject: [PATCH 29/90] Rust: Add path resolution tests --- .../PathResolutionInlineExpectationsTest.qll | 12 +++++++---- .../library-tests/path-resolution/my2/mod.rs | 2 ++ .../path-resolution/my2/my3/mod.rs | 4 ++++ .../path-resolution/path-resolution.expected | 20 +++++++++++-------- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll b/rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll index 8d2fdb2d2eb..df668194c07 100644 --- a/rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll +++ b/rust/ql/lib/utils/test/PathResolutionInlineExpectationsTest.qll @@ -25,10 +25,14 @@ private module ResolveTest implements TestSig { private predicate item(ItemNode i, string value) { exists(string filepath, int line, boolean inMacro | itemAt(i, filepath, line, inMacro) | - commmentAt(value, filepath, line) - or - not commmentAt(_, filepath, line) and - value = i.getName() + if i instanceof SourceFile + then value = i.getFile().getBaseName() + else ( + commmentAt(value, filepath, line) + or + not commmentAt(_, filepath, line) and + value = i.getName() + ) ) } diff --git a/rust/ql/test/library-tests/path-resolution/my2/mod.rs b/rust/ql/test/library-tests/path-resolution/my2/mod.rs index 85edb683202..6b86c78237c 100644 --- a/rust/ql/test/library-tests/path-resolution/my2/mod.rs +++ b/rust/ql/test/library-tests/path-resolution/my2/mod.rs @@ -15,6 +15,8 @@ pub use nested2::nested7::nested8::{ // $ item=I118 use nested2::nested5::nested6::f as nested6_f; // $ item=I116 +use std::ops::Deref; // $ item=Deref + pub mod my3; #[path = "renamed.rs"] diff --git a/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs b/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs index b459ca05aa6..1a98df1b560 100644 --- a/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs +++ b/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs @@ -8,3 +8,7 @@ use super::super::h; // $ item=I25 use super::g; // $ item=I9 use super::nested6_f; // $ item=I116 + +use super::*; // $ item=mod.rs + +trait MyTrait: Deref {} // $ MISSING: item=Deref diff --git a/rust/ql/test/library-tests/path-resolution/path-resolution.expected b/rust/ql/test/library-tests/path-resolution/path-resolution.expected index a908ec1e5c1..1a925a31cce 100644 --- a/rust/ql/test/library-tests/path-resolution/path-resolution.expected +++ b/rust/ql/test/library-tests/path-resolution/path-resolution.expected @@ -33,8 +33,8 @@ mod | main.rs:712:1:764:1 | mod associated_types | | main.rs:770:1:789:1 | mod impl_with_attribute_macro | | my2/mod.rs:1:1:1:16 | mod nested2 | -| my2/mod.rs:18:1:18:12 | mod my3 | -| my2/mod.rs:20:1:21:10 | mod mymod | +| my2/mod.rs:20:1:20:12 | mod my3 | +| my2/mod.rs:22:1:23:10 | mod mymod | | my2/nested2.rs:1:1:11:1 | mod nested3 | | my2/nested2.rs:2:5:10:5 | mod nested4 | | my2/nested2.rs:13:1:19:1 | mod nested5 | @@ -406,7 +406,7 @@ resolvePath | main.rs:814:5:814:14 | ...::f | my2/nested2.rs:15:9:17:9 | fn f | | main.rs:815:5:815:11 | nested8 | my2/nested2.rs:22:5:26:5 | mod nested8 | | main.rs:815:5:815:14 | ...::f | my2/nested2.rs:23:9:25:9 | fn f | -| main.rs:816:5:816:7 | my3 | my2/mod.rs:18:1:18:12 | mod my3 | +| main.rs:816:5:816:7 | my3 | my2/mod.rs:20:1:20:12 | mod my3 | | main.rs:816:5:816:10 | ...::f | my2/my3/mod.rs:1:1:5:1 | fn f | | main.rs:817:5:817:12 | nested_f | my/my4/my5/mod.rs:1:1:3:1 | fn f | | main.rs:818:5:818:7 | m18 | main.rs:553:1:571:1 | mod m18 | @@ -440,17 +440,21 @@ resolvePath | my2/mod.rs:16:5:16:20 | ...::nested5 | my2/nested2.rs:13:1:19:1 | mod nested5 | | my2/mod.rs:16:5:16:29 | ...::nested6 | my2/nested2.rs:14:5:18:5 | mod nested6 | | my2/mod.rs:16:5:16:32 | ...::f | my2/nested2.rs:15:9:17:9 | fn f | -| my2/mod.rs:23:9:23:13 | mymod | my2/mod.rs:20:1:21:10 | mod mymod | -| my2/mod.rs:23:9:23:16 | ...::f | my2/renamed.rs:1:1:1:13 | fn f | +| my2/mod.rs:18:5:18:7 | std | {EXTERNAL LOCATION} | Crate(std@0.0.0) | +| my2/mod.rs:18:5:18:12 | ...::ops | {EXTERNAL LOCATION} | mod ops | +| my2/mod.rs:18:5:18:19 | ...::Deref | {EXTERNAL LOCATION} | trait Deref | +| my2/mod.rs:25:9:25:13 | mymod | my2/mod.rs:22:1:23:10 | mod mymod | +| my2/mod.rs:25:9:25:16 | ...::f | my2/renamed.rs:1:1:1:13 | fn f | | my2/my3/mod.rs:3:5:3:5 | g | my2/mod.rs:3:1:6:1 | fn g | | my2/my3/mod.rs:4:5:4:5 | h | main.rs:56:1:75:1 | fn h | -| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:23:34 | SourceFile | +| my2/my3/mod.rs:7:5:7:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:7:5:7:16 | ...::super | main.rs:1:1:826:2 | SourceFile | | my2/my3/mod.rs:7:5:7:19 | ...::h | main.rs:56:1:75:1 | fn h | -| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:23:34 | SourceFile | +| my2/my3/mod.rs:8:5:8:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:8:5:8:12 | ...::g | my2/mod.rs:3:1:6:1 | fn g | -| my2/my3/mod.rs:10:5:10:9 | super | my2/mod.rs:1:1:23:34 | SourceFile | +| my2/my3/mod.rs:10:5:10:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:10:5:10:20 | ...::nested6_f | my2/nested2.rs:15:9:17:9 | fn f | +| my2/my3/mod.rs:12:5:12:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested | | my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g | | my.rs:11:5:11:5 | g | my/nested.rs:19:1:22:1 | fn g | From 50bf9ae7563e671814820819269200980cb5a5b3 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Sun, 21 Sep 2025 20:44:46 -0400 Subject: [PATCH 30/90] Refactor RootApi class to use getAnImmediateDescendent for clarity --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 0999be94505..ce0b47502f9 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -26,7 +26,7 @@ module Grape { */ class RootApi extends GrapeApiClass { RootApi() { - not exists(GrapeApiClass parent | this != parent and this = parent.getADescendent()) + not this = any(GrapeApiClass parent).getAnImmediateDescendent() } } From 1bf6101967e860043695e2d93e10c34373ea8b39 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Sun, 21 Sep 2025 20:52:28 -0400 Subject: [PATCH 31/90] Remove redundant exclusion of base Grape::API module from GrapeApiClass - should not impact extracted application code --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index ce0b47502f9..4e178792572 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -45,8 +45,7 @@ module Grape { */ class GrapeApiClass extends DataFlow::ClassNode { GrapeApiClass() { - this = grapeApiBaseClass().getADescendentModule() and - not exists(DataFlow::ModuleNode m | m = grapeApiBaseClass().asModule() | this = m) + this = grapeApiBaseClass().getADescendentModule() } /** From b2cc01c490115f1c1078318e45d328a1ddbedc7c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Sep 2025 09:38:30 +0200 Subject: [PATCH 32/90] Rust: Visibility check for qualified path resolution --- .../lib/codeql/rust/internal/CachedStages.qll | 2 +- .../codeql/rust/internal/PathResolution.qll | 209 +++++++++++------- .../path-resolution/my2/my3/mod.rs | 2 +- .../path-resolution/path-resolution.expected | 1 + 4 files changed, 136 insertions(+), 78 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/CachedStages.qll b/rust/ql/lib/codeql/rust/internal/CachedStages.qll index cfd3d690522..132b9ec8f7e 100644 --- a/rust/ql/lib/codeql/rust/internal/CachedStages.qll +++ b/rust/ql/lib/codeql/rust/internal/CachedStages.qll @@ -117,7 +117,7 @@ module Stages { or exists(resolvePath(_)) or - exists(any(ItemNode i).getASuccessor(_, _)) + exists(any(ItemNode i).getASuccessor(_, _, _)) or exists(any(ImplOrTraitItemNode i).getASelfPath()) or diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 44e8b452255..785dc2e4319 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -6,6 +6,7 @@ private import rust private import codeql.rust.elements.internal.generated.ParentChild private import codeql.rust.internal.CachedStages private import codeql.rust.frameworks.stdlib.Builtins as Builtins +private import codeql.util.Option private newtype TNamespace = TTypeNamespace() or @@ -78,6 +79,10 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki ) } +private module UseOption = Option; + +private class UseOption = UseOption::Option; + /** * Holds if `n` is superseded by an attribute macro expansion. That is, `n` is * an item or a transitive child of an item with an attribute macro expansion. @@ -229,40 +234,51 @@ abstract class ItemNode extends Locatable { result = this.(SourceFileItemNode).getSuper() } - /** Gets a successor named `name` of the given `kind`, if any. */ + /** + * Gets a successor named `name` of the given `kind`, if any. + * + * `useOpt` represents the `use` statement that brought the item into scope, + * if any. + */ cached - ItemNode getASuccessor(string name, SuccessorKind kind) { + ItemNode getASuccessor(string name, SuccessorKind kind, UseOption useOpt) { Stages::PathResolutionStage::ref() and sourceFileEdge(this, name, result) and - kind.isBoth() + kind.isBoth() and + useOpt.isNone() or - result = getAChildSuccessor(this, name, kind) + result = getAChildSuccessor(this, name, kind) and + useOpt.isNone() or - fileImportEdge(this, name, result, kind) + fileImportEdge(this, name, result, kind, useOpt) or - useImportEdge(this, name, result, kind) + useImportEdge(this, name, result, kind) and + useOpt.isNone() or - crateDefEdge(this, name, result, kind) + crateDefEdge(this, name, result, kind, useOpt) or crateDependencyEdge(this, name, result) and - kind.isInternal() + kind.isInternal() and + useOpt.isNone() or externCrateEdge(this, name, result) and - kind.isInternal() + kind.isInternal() and + useOpt.isNone() or // items made available through `use` are available to nodes that contain the `use` - exists(UseItemNode use | - use = this.getASuccessor(_, _) and - result = use.getASuccessor(name, kind) - ) + useOpt.asSome() = + any(UseItemNode use_ | + use_ = this.getASuccessor(_, _, _) and + result = use_.getASuccessor(name, kind, _) + ) or - exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessor(name, kind) | - ec = this.getASuccessor(_, _) + exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessor(name, kind, useOpt) | + ec = this.getASuccessor(_, _, _) or // if the extern crate appears in the crate root, then the crate name is also added // to the 'extern prelude', see https://doc.rust-lang.org/reference/items/extern-crates.html exists(Crate c | - ec = c.getSourceFile().(ItemNode).getASuccessor(_, _) and + ec = c.getSourceFile().(ItemNode).getASuccessor(_, _, _) and this = c.getASourceFile() ) ) @@ -270,20 +286,20 @@ abstract class ItemNode extends Locatable { // a trait has access to the associated items of its supertraits this = any(TraitItemNodeImpl trait | - result = trait.resolveABoundCand().getASuccessor(name, kind) and + result = trait.resolveABoundCand().getASuccessor(name, kind, useOpt) and kind.isExternalOrBoth() and result instanceof AssocItemNode and not trait.hasAssocItem(name) ) or // items made available by an implementation where `this` is the implementing type - typeImplEdge(this, _, name, kind, result) + typeImplEdge(this, _, name, kind, result, useOpt) or // trait items with default implementations made available in an implementation exists(ImplItemNodeImpl impl, ItemNode trait | this = impl and trait = impl.resolveTraitTyCand() and - result = trait.getASuccessor(name, kind) and + result = trait.getASuccessor(name, kind, useOpt) and result.(AssocItemNode).hasImplementation() and kind.isExternalOrBoth() and not impl.hasAssocItem(name) @@ -291,42 +307,52 @@ abstract class ItemNode extends Locatable { or // type parameters have access to the associated items of its bounds result = - this.(TypeParamItemNodeImpl).resolveABoundCand().getASuccessor(name, kind).(AssocItemNode) and + this.(TypeParamItemNodeImpl) + .resolveABoundCand() + .getASuccessor(name, kind, useOpt) + .(AssocItemNode) and kind.isExternalOrBoth() or result = this.(ImplTraitTypeReprItemNodeImpl) .resolveABoundCand() - .getASuccessor(name, kind) + .getASuccessor(name, kind, useOpt) .(AssocItemNode) and kind.isExternalOrBoth() or - result = this.(TypeAliasItemNodeImpl).resolveAliasCand().getASuccessor(name, kind) and + result = this.(TypeAliasItemNodeImpl).resolveAliasCand().getASuccessor(name, kind, useOpt) and kind.isExternalOrBoth() or name = "super" and - if this instanceof Module or this instanceof SourceFile - then ( - kind.isBoth() and result = this.getImmediateParentModule() - ) else ( - kind.isInternal() and result = this.getImmediateParentModule().getImmediateParentModule() + useOpt.isNone() and + ( + if this instanceof Module or this instanceof SourceFile + then ( + kind.isBoth() and result = this.getImmediateParentModule() + ) else ( + kind.isInternal() and result = this.getImmediateParentModule().getImmediateParentModule() + ) ) or name = "self" and - if - this instanceof Module or - this instanceof Enum or - this instanceof Struct or - this instanceof Crate - then ( - kind.isBoth() and - result = this - ) else ( - kind.isInternal() and - result = this.getImmediateParentModule() + useOpt.isNone() and + ( + if + this instanceof Module or + this instanceof Enum or + this instanceof Struct or + this instanceof Crate + then ( + kind.isBoth() and + result = this + ) else ( + kind.isInternal() and + result = this.getImmediateParentModule() + ) ) or kind.isInternal() and + useOpt.isNone() and ( preludeEdge(this, name, result) or @@ -350,7 +376,7 @@ abstract class ItemNode extends Locatable { pragma[nomagic] ItemNode getASuccessor(string name) { exists(SuccessorKind kind | - result = this.getASuccessor(name, kind) and + result = this.getASuccessor(name, kind, _) and kind.isExternalOrBoth() ) } @@ -1266,10 +1292,12 @@ predicate fileImport(Module m, SourceFile f) { * in scope under the name `name`. */ pragma[nomagic] -private predicate fileImportEdge(Module mod, string name, ItemNode item, SuccessorKind kind) { +private predicate fileImportEdge( + Module mod, string name, ItemNode item, SuccessorKind kind, UseOption useOpt +) { exists(SourceFileItemNode f | fileImport(mod, f) and - item = f.getASuccessor(name, kind) + item = f.getASuccessor(name, kind, useOpt) ) } @@ -1277,8 +1305,10 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item, Success * Holds if crate `c` defines the item `i` named `name`. */ pragma[nomagic] -private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i, SuccessorKind kind) { - i = c.getSourceFile().getASuccessor(name, kind) and +private predicate crateDefEdge( + CrateItemNode c, string name, ItemNode i, SuccessorKind kind, UseOption useOpt +) { + i = c.getSourceFile().getASuccessor(name, kind, useOpt) and kind.isExternalOrBoth() } @@ -1421,8 +1451,10 @@ private predicate unqualifiedPathLookup(ItemNode encl, string name, Namespace ns } pragma[nomagic] -private ItemNode getASuccessor(ItemNode pred, string name, Namespace ns, SuccessorKind kind) { - result = pred.getASuccessor(name, kind) and +private ItemNode getASuccessor( + ItemNode pred, string name, Namespace ns, SuccessorKind kind, UseOption useOpt +) { + result = pred.getASuccessor(name, kind, useOpt) and ns = result.getNamespace() } @@ -1457,7 +1489,7 @@ private predicate keywordLookup(ItemNode encl, string name, RelevantPath p) { pragma[nomagic] private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKind kind) { exists(ItemNode encl, string name | - result = getASuccessor(encl, name, ns, kind) and + result = getASuccessor(encl, name, ns, kind, _) and kind.isInternalOrBoth() | unqualifiedPathLookup(encl, name, ns, p) @@ -1486,7 +1518,7 @@ module TraitIsVisible { // lookup in an outer scope, but only if the trait is not declared in inner scope exists(ItemNode mid | traitLookup(mid, element, trait) and - not trait = mid.getASuccessor(_, _) and + not trait = mid.getASuccessor(_, _, _) and encl = getOuterScope(mid) ) } @@ -1494,7 +1526,9 @@ module TraitIsVisible { /** Holds if the trait `trait` is visible at `element`. */ pragma[nomagic] predicate traitIsVisible(Element element, Trait trait) { - exists(ItemNode encl | traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _)) + exists(ItemNode encl | + traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _, _) + ) } } @@ -1523,12 +1557,42 @@ private ItemNode resolvePathCandQualifier(RelevantPath qualifier, RelevantPath p name = path.getText() } -pragma[nomagic] -private Crate getCrate0(Locatable l) { result.getASourceFile().getFile() = l.getFile() } - bindingset[l] pragma[inline_late] -private Crate getCrate(Locatable l) { result = getCrate0(l) } +private ModuleLikeNode getAnAncestorModule(Locatable l) { + exists(ItemNode encl | + encl.getADescendant() = l and + result = encl.getImmediateParentModule*() + ) +} + +bindingset[i] +pragma[inline_late] +private ModuleLikeNode getParent(ItemNode i) { result = i.getImmediateParent() } + +/** + * Holds if resolving a qualified path at `l` to the item `i` with successor kind + * `kind` respects visibility. + * + * This is the case when either `i` is externally visible (e.g. a `pub` function), + * or when `i` (or the `use` statement, `useOpt`, that brought `i` into scope) is + * in an ancestor module of `l`. + */ +bindingset[l, i, kind, useOpt] +pragma[inline_late] +private predicate checkQualifiedVisibility( + Locatable l, ItemNode i, SuccessorKind kind, UseOption useOpt +) { + kind.isExternalOrBoth() + or + exists(AstNode n | getAnAncestorModule(l) = getParent(n) | + n = useOpt.asSome() + or + useOpt.isNone() and + n = i + ) and + not i instanceof TypeParam +} /** * Gets the item that `path` resolves to in `ns` when `qualifier` is the @@ -1538,19 +1602,10 @@ pragma[nomagic] private ItemNode resolvePathCandQualified( RelevantPath qualifier, ItemNode q, RelevantPath path, Namespace ns ) { - exists(string name, SuccessorKind kind | + exists(string name, SuccessorKind kind, UseOption useOpt | q = resolvePathCandQualifier(qualifier, path, name) and - result = getASuccessor(q, name, ns, kind) - | - kind.isExternalOrBoth() - or - // Non-public items are visible to paths in descendant modules of the declaring - // module; the declaration may happen via a `use` statement, where the item - // being used is _not_ itself in an ancestor module, and we currently don't track - // that information in `getASuccessor`. So, for simplicity, we allow for non-public - // items when the path and the item are in the same crate. - getCrate(path) = getCrate(result) and - not result instanceof TypeParam + result = getASuccessor(q, name, ns, kind, useOpt) and + checkQualifiedVisibility(path, result, kind, useOpt) ) } @@ -1561,6 +1616,8 @@ private predicate pathUsesNamespace(Path p, Namespace n) { p = any(PathExpr pe).getPath() or p = any(TupleStructPat tsp).getPath() + or + p = any(Meta m).getPath() ) or n.isType() and @@ -1621,7 +1678,7 @@ private ItemNode resolvePathCand(RelevantPath path) { private Trait getResolvePathTraitUsed(RelevantPath path, AssocItemNode node) { exists(TypeItemNode type, ImplItemNodeImpl impl | node = resolvePathCandQualified(_, type, path, _) and - typeImplEdge(type, impl, _, _, node) and + typeImplEdge(type, impl, _, _, node, _) and result = impl.resolveTraitTyCand() ) } @@ -1668,18 +1725,17 @@ private predicate isUseTreeSubPathUnqualified(UseTree tree, RelevantPath path, s pragma[nomagic] private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) { - kind.isExternalOrBoth() and - ( + exists(UseOption useOpt | checkQualifiedVisibility(use, result, kind, useOpt) | exists(UseTree midTree, ItemNode mid, string name | mid = resolveUseTreeListItem(use, midTree) and tree = midTree.getUseTreeList().getAUseTree() and isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and - result = mid.getASuccessor(pragma[only_bind_into](name), kind) + result = mid.getASuccessor(pragma[only_bind_into](name), kind, useOpt) ) or exists(ItemNode q, string name | q = resolveUseTreeListItemQualifier(use, tree, path, name) and - result = q.getASuccessor(name, kind) + result = q.getASuccessor(name, kind, useOpt) ) ) } @@ -1711,10 +1767,10 @@ private predicate useImportEdge(Use use, string name, ItemNode item, SuccessorKi not tree.hasUseTreeList() and if tree.isGlob() then - exists(ItemNode encl, Namespace ns, SuccessorKind kind1 | + exists(ItemNode encl, Namespace ns, SuccessorKind kind1, UseOption useOpt | encl.getADescendant() = use and - item = getASuccessor(used, name, ns, kind1) and - kind1.isExternalOrBoth() and + item = getASuccessor(used, name, ns, kind1, useOpt) and + checkQualifiedVisibility(use, item, kind1, useOpt) and // glob imports can be shadowed not declares(encl, ns, name) and not name = ["super", "self"] @@ -1764,10 +1820,11 @@ private predicate externCrateEdge(ExternCrateItemNode ec, string name, CrateItem * makes `assoc` available as `name` at `kind`. */ private predicate typeImplEdge( - TypeItemNode typeItem, ImplItemNodeImpl impl, string name, SuccessorKind kind, AssocItemNode assoc + TypeItemNode typeItem, ImplItemNodeImpl impl, string name, SuccessorKind kind, + AssocItemNode assoc, UseOption useOpt ) { typeItem = impl.resolveSelfTyCand() and - assoc = impl.getASuccessor(name, kind) and + assoc = impl.getASuccessor(name, kind, useOpt) and kind.isExternalOrBoth() } @@ -1839,12 +1896,12 @@ private module Debug { ItemNode debugGetASuccessor(ItemNode i, string name, SuccessorKind kind) { i = getRelevantLocatable() and - result = i.getASuccessor(name, kind) + result = i.getASuccessor(name, kind, _) } predicate debugFileImportEdge(Module mod, string name, ItemNode item, SuccessorKind kind) { mod = getRelevantLocatable() and - fileImportEdge(mod, name, item, kind) + fileImportEdge(mod, name, item, kind, _) } predicate debugFileImport(Module m, SourceFile f) { diff --git a/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs b/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs index 1a98df1b560..169aeed6b28 100644 --- a/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs +++ b/rust/ql/test/library-tests/path-resolution/my2/my3/mod.rs @@ -11,4 +11,4 @@ use super::nested6_f; // $ item=I116 use super::*; // $ item=mod.rs -trait MyTrait: Deref {} // $ MISSING: item=Deref +trait MyTrait: Deref {} // $ item=Deref diff --git a/rust/ql/test/library-tests/path-resolution/path-resolution.expected b/rust/ql/test/library-tests/path-resolution/path-resolution.expected index 1a925a31cce..9315016fe6a 100644 --- a/rust/ql/test/library-tests/path-resolution/path-resolution.expected +++ b/rust/ql/test/library-tests/path-resolution/path-resolution.expected @@ -455,6 +455,7 @@ resolvePath | my2/my3/mod.rs:10:5:10:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | | my2/my3/mod.rs:10:5:10:20 | ...::nested6_f | my2/nested2.rs:15:9:17:9 | fn f | | my2/my3/mod.rs:12:5:12:9 | super | my2/mod.rs:1:1:25:34 | SourceFile | +| my2/my3/mod.rs:14:16:14:20 | Deref | {EXTERNAL LOCATION} | trait Deref | | my.rs:3:5:3:10 | nested | my.rs:1:1:1:15 | mod nested | | my.rs:3:5:3:13 | ...::g | my/nested.rs:19:1:22:1 | fn g | | my.rs:11:5:11:5 | g | my/nested.rs:19:1:22:1 | fn g | From b5b6f0600565148c64d278c2bec48ddd03926916 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Sep 2025 09:38:43 +0200 Subject: [PATCH 33/90] Rust: Fix bad join ``` Evaluated relational algebra for predicate _PathResolution::CrateItemNode.getName/0#dispred#91b4dd6b_PathResolution::SourceFileItemNode#bd8f490__#antijoin_rhs@e84aee8k with tuple counts: 35406180 ~0% {3} r1 = JOIN PathResolution::SourceFileItemNode#bd8f4905 WITH `PathResolution::CrateItemNode.getName/0#dispred#91b4dd6b` CARTESIAN PRODUCT OUTPUT Lhs.0, Rhs.1, Rhs.0 8455 ~2% {4} | JOIN WITH `PathResolution::declaresDirectly/3#7d0350fb_021#join_rhs` ON FIRST 2 OUTPUT Rhs.2, Lhs.0, Lhs.2, Lhs.1 3259 ~0% {3} | JOIN WITH num#PathResolution::TTypeNamespace#4897e416 ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.3 return r1 ``` --- rust/ql/lib/codeql/rust/internal/PathResolution.qll | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 785dc2e4319..a4b1e9bce98 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -1321,6 +1321,12 @@ private predicate crateDependency(SourceFileItemNode file, string name, CrateIte exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | file = c.getASourceFile()) } +pragma[nomagic] +private predicate hasDeclOrDep(SourceFileItemNode file, string name) { + declaresDirectly(file, TTypeNamespace(), name) or + crateDependency(file, name, _) +} + /** * Holds if `file` depends on crate `dep` named `name`. */ @@ -1334,8 +1340,7 @@ private predicate crateDependencyEdge(SourceFileItemNode file, string name, Crat // a given file to its crate (for example, if the file is `mod` imported inside a macro that the // extractor is unable to expand). name = dep.getName() and - not declaresDirectly(file, TTypeNamespace(), name) and - not crateDependency(file, name, _) + not hasDeclOrDep(file, name) } private predicate useTreeDeclares(UseTree tree, string name) { From 78641b4dde6d2fc3c1c8cd23bce229f73da3cd0e Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Sep 2025 09:37:03 +0200 Subject: [PATCH 34/90] Rust: Reduce size of `unqualifiedPathLookup` --- .../codeql/rust/internal/PathResolution.qll | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index a4b1e9bce98..efd614db63a 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -1401,11 +1401,20 @@ class RelevantPath extends Path { name = this.getText() } + /** + * Holds if this is an unqualified path with the textual value `name` and + * enclosing item `encl`. + */ + pragma[nomagic] + predicate isUnqualified(string name, ItemNode encl) { + this.isUnqualified(name) and + encl.getADescendant() = this + } + pragma[nomagic] predicate isCratePath(string name, ItemNode encl) { name = ["crate", "$crate"] and - this.isUnqualified(name) and - encl.getADescendant() = this + this.isUnqualified(name, encl) } pragma[nomagic] @@ -1432,26 +1441,26 @@ private ItemNode getOuterScope(ItemNode i) { } /** - * Holds if the unqualified path `p` references an item named `name`, and `name` - * may be looked up in the `ns` namespace inside enclosing item `encl`. + * Holds if _some_ unqualified path in `encl` references an item named `name`, + * and `name` may be looked up in the `ns` namespace inside `ancestor`. */ pragma[nomagic] -private predicate unqualifiedPathLookup(ItemNode encl, string name, Namespace ns, RelevantPath p) { +private predicate unqualifiedPathLookup(ItemNode ancestor, string name, Namespace ns, ItemNode encl) { // lookup in the immediately enclosing item - p.isUnqualified(name) and - encl.getADescendant() = p and + any(RelevantPath p).isUnqualified(name, encl) and + ancestor = encl and exists(ns) and not name = ["crate", "$crate", "super", "self"] or // lookup in an outer scope, but only if the item is not declared in inner scope exists(ItemNode mid | - unqualifiedPathLookup(mid, name, ns, p) and + unqualifiedPathLookup(mid, name, ns, encl) and not declares(mid, ns, name) and not ( name = "Self" and mid = any(ImplOrTraitItemNode i).getAnItemInSelfScope() ) and - encl = getOuterScope(mid) + ancestor = getOuterScope(mid) ) } @@ -1474,32 +1483,34 @@ private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) = /** * Holds if the unqualified path `p` references a keyword item named `name`, and - * `name` may be looked up inside enclosing item `encl`. + * `name` may be looked up inside `ancestor`. */ pragma[nomagic] -private predicate keywordLookup(ItemNode encl, string name, RelevantPath p) { +private predicate keywordLookup(ItemNode ancestor, string name, RelevantPath p) { // For `($)crate`, jump directly to the root module exists(ItemNode i | p.isCratePath(name, i) | - encl instanceof SourceFile and - encl = i + ancestor instanceof SourceFile and + ancestor = i or - sourceFileHasCratePathTc(encl, i) + sourceFileHasCratePathTc(ancestor, i) ) or name = ["super", "self"] and - p.isUnqualified(name) and - encl.getADescendant() = p + p.isUnqualified(name, ancestor) } pragma[nomagic] private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKind kind) { - exists(ItemNode encl, string name | - result = getASuccessor(encl, name, ns, kind, _) and + exists(ItemNode ancestor, string name | + result = getASuccessor(ancestor, pragma[only_bind_into](name), ns, kind, _) and kind.isInternalOrBoth() | - unqualifiedPathLookup(encl, name, ns, p) + exists(ItemNode encl | + unqualifiedPathLookup(ancestor, name, ns, encl) and + p.isUnqualified(pragma[only_bind_into](name), encl) + ) or - keywordLookup(encl, name, p) and exists(ns) + keywordLookup(ancestor, name, p) and exists(ns) ) } @@ -1880,10 +1891,13 @@ private module Debug { } predicate debugUnqualifiedPathLookup( - RelevantPath p, string name, Namespace ns, ItemNode encl, string path + RelevantPath p, string name, Namespace ns, ItemNode ancestor, string path ) { p = getRelevantLocatable() and - unqualifiedPathLookup(encl, name, ns, p) and + exists(ItemNode encl | + unqualifiedPathLookup(encl, name, ns, ancestor) and + p.isUnqualified(name, encl) + ) and path = p.toStringDebug() } From cd807533f26b24f841124b6a4f6632149abcd5f7 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 17 Sep 2025 10:55:47 +0200 Subject: [PATCH 35/90] Rust: Add tests for parameter in source model --- .../library-tests/dataflow/models/main.rs | 27 ++ .../dataflow/models/models.expected | 328 +++++++++--------- .../dataflow/models/models.ext.yml | 1 + 3 files changed, 192 insertions(+), 164 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index 0430b6f8dff..98a45655035 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -249,6 +249,33 @@ fn test_enum_method_source() { } } +mod source_into_function { + use super::sink; + + // has a source model + fn pass_source(_i: i64, f: impl FnOnce(i64) -> A) -> A { + f(42) + } + + fn test_source_into_function() { + let a = |a| sink(a); // $ MISSING: hasValueFlow=1 + pass_source(1, a); + + pass_source(2, |a| { + sink(a); // $ MISSING: hasValueFlow=2 + }); + + fn f(a: i64) { + sink(a) // $ MISSING: hasValueFlow=3 + } + pass_source(3, f); + + pass_source(4, async move |a| { + sink(a); // $ MISSING: hasValueFlow=4 + }); + } +} + // has a sink model fn enum_sink(e: MyFieldEnum) {} diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index db7489809b8..c04b66068db 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -230,70 +230,70 @@ edges | main.rs:247:9:247:37 | ...::C {...} [C] | main.rs:247:35:247:35 | i | provenance | | | main.rs:247:35:247:35 | i | main.rs:247:47:247:47 | i | provenance | | | main.rs:247:35:247:35 | i | main.rs:247:47:247:47 | i | provenance | | -| main.rs:256:9:256:9 | s | main.rs:257:41:257:41 | s | provenance | | -| main.rs:256:9:256:9 | s | main.rs:257:41:257:41 | s | provenance | | -| main.rs:256:13:256:22 | source(...) | main.rs:256:9:256:9 | s | provenance | | -| main.rs:256:13:256:22 | source(...) | main.rs:256:9:256:9 | s | provenance | | -| main.rs:257:15:257:43 | ...::C {...} [C] | main.rs:257:5:257:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 | -| main.rs:257:15:257:43 | ...::C {...} [C] | main.rs:257:5:257:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 | -| main.rs:257:41:257:41 | s | main.rs:257:15:257:43 | ...::C {...} [C] | provenance | | -| main.rs:257:41:257:41 | s | main.rs:257:15:257:43 | ...::C {...} [C] | provenance | | -| main.rs:262:9:262:9 | s | main.rs:263:39:263:39 | s | provenance | | -| main.rs:262:9:262:9 | s | main.rs:263:39:263:39 | s | provenance | | -| main.rs:262:13:262:22 | source(...) | main.rs:262:9:262:9 | s | provenance | | -| main.rs:262:13:262:22 | source(...) | main.rs:262:9:262:9 | s | provenance | | -| main.rs:263:9:263:9 | e [D] | main.rs:264:5:264:5 | e [D] | provenance | | -| main.rs:263:9:263:9 | e [D] | main.rs:264:5:264:5 | e [D] | provenance | | -| main.rs:263:13:263:41 | ...::D {...} [D] | main.rs:263:9:263:9 | e [D] | provenance | | -| main.rs:263:13:263:41 | ...::D {...} [D] | main.rs:263:9:263:9 | e [D] | provenance | | -| main.rs:263:39:263:39 | s | main.rs:263:13:263:41 | ...::D {...} [D] | provenance | | -| main.rs:263:39:263:39 | s | main.rs:263:13:263:41 | ...::D {...} [D] | provenance | | -| main.rs:264:5:264:5 | e [D] | main.rs:264:7:264:10 | sink | provenance | MaD:1 Sink:MaD:1 | -| main.rs:264:5:264:5 | e [D] | main.rs:264:7:264:10 | sink | provenance | MaD:1 Sink:MaD:1 | -| main.rs:273:9:273:9 | s | main.rs:274:10:274:10 | s | provenance | | -| main.rs:273:9:273:9 | s | main.rs:274:10:274:10 | s | provenance | | -| main.rs:273:13:273:25 | simple_source | main.rs:273:13:273:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | -| main.rs:273:13:273:25 | simple_source | main.rs:273:13:273:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | -| main.rs:273:13:273:29 | simple_source(...) | main.rs:273:9:273:9 | s | provenance | | -| main.rs:273:13:273:29 | simple_source(...) | main.rs:273:9:273:9 | s | provenance | | -| main.rs:281:9:281:9 | s | main.rs:282:17:282:17 | s | provenance | | -| main.rs:281:9:281:9 | s | main.rs:282:17:282:17 | s | provenance | | -| main.rs:281:13:281:22 | source(...) | main.rs:281:9:281:9 | s | provenance | | -| main.rs:281:13:281:22 | source(...) | main.rs:281:9:281:9 | s | provenance | | -| main.rs:282:17:282:17 | s | main.rs:282:5:282:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:282:17:282:17 | s | main.rs:282:5:282:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:290:5:290:14 | arg_source | main.rs:290:16:290:16 | [post] i | provenance | Src:MaD:5 MaD:5 | -| main.rs:290:5:290:14 | arg_source | main.rs:290:16:290:16 | [post] i | provenance | Src:MaD:5 MaD:5 | -| main.rs:290:16:290:16 | [post] i | main.rs:291:10:291:10 | i | provenance | | -| main.rs:290:16:290:16 | [post] i | main.rs:291:10:291:10 | i | provenance | | -| main.rs:343:9:343:10 | x1 | main.rs:344:10:344:11 | x1 | provenance | | -| main.rs:343:9:343:10 | x1 | main.rs:344:10:344:11 | x1 | provenance | | -| main.rs:343:14:343:23 | source(...) | main.rs:343:14:343:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:343:14:343:23 | source(...) | main.rs:343:14:343:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:343:14:343:30 | ... .max(...) | main.rs:343:9:343:10 | x1 | provenance | | -| main.rs:343:14:343:30 | ... .max(...) | main.rs:343:9:343:10 | x1 | provenance | | -| main.rs:346:9:346:10 | x2 [MyStruct.field1] | main.rs:354:10:354:11 | x2 [MyStruct.field1] | provenance | | -| main.rs:346:9:346:10 | x2 [MyStruct.field1] | main.rs:354:10:354:11 | x2 [MyStruct.field1] | provenance | | -| main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | main.rs:346:9:346:10 | x2 [MyStruct.field1] | provenance | | -| main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | main.rs:346:9:346:10 | x2 [MyStruct.field1] | provenance | | -| main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | -| main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | -| main.rs:347:17:347:26 | source(...) | main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:347:17:347:26 | source(...) | main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:354:10:354:11 | x2 [MyStruct.field1] | main.rs:354:10:354:18 | x2.field1 | provenance | | -| main.rs:354:10:354:11 | x2 [MyStruct.field1] | main.rs:354:10:354:18 | x2.field1 | provenance | | -| main.rs:359:9:359:10 | x4 | main.rs:360:10:360:11 | x4 | provenance | | -| main.rs:359:9:359:10 | x4 | main.rs:360:10:360:11 | x4 | provenance | | -| main.rs:359:14:359:23 | source(...) | main.rs:359:14:359:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:359:14:359:23 | source(...) | main.rs:359:14:359:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:359:14:359:30 | ... .max(...) | main.rs:359:9:359:10 | x4 | provenance | | -| main.rs:359:14:359:30 | ... .max(...) | main.rs:359:9:359:10 | x4 | provenance | | -| main.rs:362:9:362:10 | x5 | main.rs:363:10:363:11 | x5 | provenance | | -| main.rs:362:14:362:23 | source(...) | main.rs:362:14:362:30 | ... .lt(...) | provenance | MaD:9 | -| main.rs:362:14:362:30 | ... .lt(...) | main.rs:362:9:362:10 | x5 | provenance | | -| main.rs:365:9:365:10 | x6 | main.rs:366:10:366:11 | x6 | provenance | | -| main.rs:365:14:365:23 | source(...) | main.rs:365:14:365:27 | ... < ... | provenance | MaD:9 | -| main.rs:365:14:365:27 | ... < ... | main.rs:365:9:365:10 | x6 | provenance | | +| main.rs:283:9:283:9 | s | main.rs:284:41:284:41 | s | provenance | | +| main.rs:283:9:283:9 | s | main.rs:284:41:284:41 | s | provenance | | +| main.rs:283:13:283:22 | source(...) | main.rs:283:9:283:9 | s | provenance | | +| main.rs:283:13:283:22 | source(...) | main.rs:283:9:283:9 | s | provenance | | +| main.rs:284:15:284:43 | ...::C {...} [C] | main.rs:284:5:284:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 | +| main.rs:284:15:284:43 | ...::C {...} [C] | main.rs:284:5:284:13 | enum_sink | provenance | MaD:2 Sink:MaD:2 | +| main.rs:284:41:284:41 | s | main.rs:284:15:284:43 | ...::C {...} [C] | provenance | | +| main.rs:284:41:284:41 | s | main.rs:284:15:284:43 | ...::C {...} [C] | provenance | | +| main.rs:289:9:289:9 | s | main.rs:290:39:290:39 | s | provenance | | +| main.rs:289:9:289:9 | s | main.rs:290:39:290:39 | s | provenance | | +| main.rs:289:13:289:22 | source(...) | main.rs:289:9:289:9 | s | provenance | | +| main.rs:289:13:289:22 | source(...) | main.rs:289:9:289:9 | s | provenance | | +| main.rs:290:9:290:9 | e [D] | main.rs:291:5:291:5 | e [D] | provenance | | +| main.rs:290:9:290:9 | e [D] | main.rs:291:5:291:5 | e [D] | provenance | | +| main.rs:290:13:290:41 | ...::D {...} [D] | main.rs:290:9:290:9 | e [D] | provenance | | +| main.rs:290:13:290:41 | ...::D {...} [D] | main.rs:290:9:290:9 | e [D] | provenance | | +| main.rs:290:39:290:39 | s | main.rs:290:13:290:41 | ...::D {...} [D] | provenance | | +| main.rs:290:39:290:39 | s | main.rs:290:13:290:41 | ...::D {...} [D] | provenance | | +| main.rs:291:5:291:5 | e [D] | main.rs:291:7:291:10 | sink | provenance | MaD:1 Sink:MaD:1 | +| main.rs:291:5:291:5 | e [D] | main.rs:291:7:291:10 | sink | provenance | MaD:1 Sink:MaD:1 | +| main.rs:300:9:300:9 | s | main.rs:301:10:301:10 | s | provenance | | +| main.rs:300:9:300:9 | s | main.rs:301:10:301:10 | s | provenance | | +| main.rs:300:13:300:25 | simple_source | main.rs:300:13:300:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | +| main.rs:300:13:300:25 | simple_source | main.rs:300:13:300:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | +| main.rs:300:13:300:29 | simple_source(...) | main.rs:300:9:300:9 | s | provenance | | +| main.rs:300:13:300:29 | simple_source(...) | main.rs:300:9:300:9 | s | provenance | | +| main.rs:308:9:308:9 | s | main.rs:309:17:309:17 | s | provenance | | +| main.rs:308:9:308:9 | s | main.rs:309:17:309:17 | s | provenance | | +| main.rs:308:13:308:22 | source(...) | main.rs:308:9:308:9 | s | provenance | | +| main.rs:308:13:308:22 | source(...) | main.rs:308:9:308:9 | s | provenance | | +| main.rs:309:17:309:17 | s | main.rs:309:5:309:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:309:17:309:17 | s | main.rs:309:5:309:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:317:5:317:14 | arg_source | main.rs:317:16:317:16 | [post] i | provenance | Src:MaD:5 MaD:5 | +| main.rs:317:5:317:14 | arg_source | main.rs:317:16:317:16 | [post] i | provenance | Src:MaD:5 MaD:5 | +| main.rs:317:16:317:16 | [post] i | main.rs:318:10:318:10 | i | provenance | | +| main.rs:317:16:317:16 | [post] i | main.rs:318:10:318:10 | i | provenance | | +| main.rs:370:9:370:10 | x1 | main.rs:371:10:371:11 | x1 | provenance | | +| main.rs:370:9:370:10 | x1 | main.rs:371:10:371:11 | x1 | provenance | | +| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:370:14:370:30 | ... .max(...) | main.rs:370:9:370:10 | x1 | provenance | | +| main.rs:370:14:370:30 | ... .max(...) | main.rs:370:9:370:10 | x1 | provenance | | +| main.rs:373:9:373:10 | x2 [MyStruct.field1] | main.rs:381:10:381:11 | x2 [MyStruct.field1] | provenance | | +| main.rs:373:9:373:10 | x2 [MyStruct.field1] | main.rs:381:10:381:11 | x2 [MyStruct.field1] | provenance | | +| main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | main.rs:373:9:373:10 | x2 [MyStruct.field1] | provenance | | +| main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | main.rs:373:9:373:10 | x2 [MyStruct.field1] | provenance | | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | +| main.rs:374:17:374:26 | source(...) | main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | provenance | | +| main.rs:374:17:374:26 | source(...) | main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | provenance | | +| main.rs:381:10:381:11 | x2 [MyStruct.field1] | main.rs:381:10:381:18 | x2.field1 | provenance | | +| main.rs:381:10:381:11 | x2 [MyStruct.field1] | main.rs:381:10:381:18 | x2.field1 | provenance | | +| main.rs:386:9:386:10 | x4 | main.rs:387:10:387:11 | x4 | provenance | | +| main.rs:386:9:386:10 | x4 | main.rs:387:10:387:11 | x4 | provenance | | +| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:386:14:386:30 | ... .max(...) | main.rs:386:9:386:10 | x4 | provenance | | +| main.rs:386:14:386:30 | ... .max(...) | main.rs:386:9:386:10 | x4 | provenance | | +| main.rs:389:9:389:10 | x5 | main.rs:390:10:390:11 | x5 | provenance | | +| main.rs:389:14:389:23 | source(...) | main.rs:389:14:389:30 | ... .lt(...) | provenance | MaD:9 | +| main.rs:389:14:389:30 | ... .lt(...) | main.rs:389:9:389:10 | x5 | provenance | | +| main.rs:392:9:392:10 | x6 | main.rs:393:10:393:11 | x6 | provenance | | +| main.rs:392:14:392:23 | source(...) | main.rs:392:14:392:27 | ... < ... | provenance | MaD:9 | +| main.rs:392:14:392:27 | ... < ... | main.rs:392:9:392:10 | x6 | provenance | | nodes | main.rs:15:9:15:9 | s | semmle.label | s | | main.rs:15:9:15:9 | s | semmle.label | s | @@ -533,88 +533,88 @@ nodes | main.rs:247:35:247:35 | i | semmle.label | i | | main.rs:247:47:247:47 | i | semmle.label | i | | main.rs:247:47:247:47 | i | semmle.label | i | -| main.rs:256:9:256:9 | s | semmle.label | s | -| main.rs:256:9:256:9 | s | semmle.label | s | -| main.rs:256:13:256:22 | source(...) | semmle.label | source(...) | -| main.rs:256:13:256:22 | source(...) | semmle.label | source(...) | -| main.rs:257:5:257:13 | enum_sink | semmle.label | enum_sink | -| main.rs:257:5:257:13 | enum_sink | semmle.label | enum_sink | -| main.rs:257:15:257:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | -| main.rs:257:15:257:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | -| main.rs:257:41:257:41 | s | semmle.label | s | -| main.rs:257:41:257:41 | s | semmle.label | s | -| main.rs:262:9:262:9 | s | semmle.label | s | -| main.rs:262:9:262:9 | s | semmle.label | s | -| main.rs:262:13:262:22 | source(...) | semmle.label | source(...) | -| main.rs:262:13:262:22 | source(...) | semmle.label | source(...) | -| main.rs:263:9:263:9 | e [D] | semmle.label | e [D] | -| main.rs:263:9:263:9 | e [D] | semmle.label | e [D] | -| main.rs:263:13:263:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] | -| main.rs:263:13:263:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] | -| main.rs:263:39:263:39 | s | semmle.label | s | -| main.rs:263:39:263:39 | s | semmle.label | s | -| main.rs:264:5:264:5 | e [D] | semmle.label | e [D] | -| main.rs:264:5:264:5 | e [D] | semmle.label | e [D] | -| main.rs:264:7:264:10 | sink | semmle.label | sink | -| main.rs:264:7:264:10 | sink | semmle.label | sink | -| main.rs:273:9:273:9 | s | semmle.label | s | -| main.rs:273:9:273:9 | s | semmle.label | s | -| main.rs:273:13:273:25 | simple_source | semmle.label | simple_source | -| main.rs:273:13:273:25 | simple_source | semmle.label | simple_source | -| main.rs:273:13:273:29 | simple_source(...) | semmle.label | simple_source(...) | -| main.rs:273:13:273:29 | simple_source(...) | semmle.label | simple_source(...) | -| main.rs:274:10:274:10 | s | semmle.label | s | -| main.rs:274:10:274:10 | s | semmle.label | s | -| main.rs:281:9:281:9 | s | semmle.label | s | -| main.rs:281:9:281:9 | s | semmle.label | s | -| main.rs:281:13:281:22 | source(...) | semmle.label | source(...) | -| main.rs:281:13:281:22 | source(...) | semmle.label | source(...) | -| main.rs:282:5:282:15 | simple_sink | semmle.label | simple_sink | -| main.rs:282:5:282:15 | simple_sink | semmle.label | simple_sink | -| main.rs:282:17:282:17 | s | semmle.label | s | -| main.rs:282:17:282:17 | s | semmle.label | s | -| main.rs:290:5:290:14 | arg_source | semmle.label | arg_source | -| main.rs:290:5:290:14 | arg_source | semmle.label | arg_source | -| main.rs:290:16:290:16 | [post] i | semmle.label | [post] i | -| main.rs:290:16:290:16 | [post] i | semmle.label | [post] i | -| main.rs:291:10:291:10 | i | semmle.label | i | -| main.rs:291:10:291:10 | i | semmle.label | i | -| main.rs:343:9:343:10 | x1 | semmle.label | x1 | -| main.rs:343:9:343:10 | x1 | semmle.label | x1 | -| main.rs:343:14:343:23 | source(...) | semmle.label | source(...) | -| main.rs:343:14:343:23 | source(...) | semmle.label | source(...) | -| main.rs:343:14:343:30 | ... .max(...) | semmle.label | ... .max(...) | -| main.rs:343:14:343:30 | ... .max(...) | semmle.label | ... .max(...) | -| main.rs:344:10:344:11 | x1 | semmle.label | x1 | -| main.rs:344:10:344:11 | x1 | semmle.label | x1 | -| main.rs:346:9:346:10 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | -| main.rs:346:9:346:10 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | -| main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | semmle.label | ... .max(...) [MyStruct.field1] | -| main.rs:346:14:353:6 | ... .max(...) [MyStruct.field1] | semmle.label | ... .max(...) [MyStruct.field1] | -| main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] | -| main.rs:346:15:349:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] | -| main.rs:347:17:347:26 | source(...) | semmle.label | source(...) | -| main.rs:347:17:347:26 | source(...) | semmle.label | source(...) | -| main.rs:354:10:354:11 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | -| main.rs:354:10:354:11 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | -| main.rs:354:10:354:18 | x2.field1 | semmle.label | x2.field1 | -| main.rs:354:10:354:18 | x2.field1 | semmle.label | x2.field1 | -| main.rs:359:9:359:10 | x4 | semmle.label | x4 | -| main.rs:359:9:359:10 | x4 | semmle.label | x4 | -| main.rs:359:14:359:23 | source(...) | semmle.label | source(...) | -| main.rs:359:14:359:23 | source(...) | semmle.label | source(...) | -| main.rs:359:14:359:30 | ... .max(...) | semmle.label | ... .max(...) | -| main.rs:359:14:359:30 | ... .max(...) | semmle.label | ... .max(...) | -| main.rs:360:10:360:11 | x4 | semmle.label | x4 | -| main.rs:360:10:360:11 | x4 | semmle.label | x4 | -| main.rs:362:9:362:10 | x5 | semmle.label | x5 | -| main.rs:362:14:362:23 | source(...) | semmle.label | source(...) | -| main.rs:362:14:362:30 | ... .lt(...) | semmle.label | ... .lt(...) | -| main.rs:363:10:363:11 | x5 | semmle.label | x5 | -| main.rs:365:9:365:10 | x6 | semmle.label | x6 | -| main.rs:365:14:365:23 | source(...) | semmle.label | source(...) | -| main.rs:365:14:365:27 | ... < ... | semmle.label | ... < ... | -| main.rs:366:10:366:11 | x6 | semmle.label | x6 | +| main.rs:283:9:283:9 | s | semmle.label | s | +| main.rs:283:9:283:9 | s | semmle.label | s | +| main.rs:283:13:283:22 | source(...) | semmle.label | source(...) | +| main.rs:283:13:283:22 | source(...) | semmle.label | source(...) | +| main.rs:284:5:284:13 | enum_sink | semmle.label | enum_sink | +| main.rs:284:5:284:13 | enum_sink | semmle.label | enum_sink | +| main.rs:284:15:284:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | +| main.rs:284:15:284:43 | ...::C {...} [C] | semmle.label | ...::C {...} [C] | +| main.rs:284:41:284:41 | s | semmle.label | s | +| main.rs:284:41:284:41 | s | semmle.label | s | +| main.rs:289:9:289:9 | s | semmle.label | s | +| main.rs:289:9:289:9 | s | semmle.label | s | +| main.rs:289:13:289:22 | source(...) | semmle.label | source(...) | +| main.rs:289:13:289:22 | source(...) | semmle.label | source(...) | +| main.rs:290:9:290:9 | e [D] | semmle.label | e [D] | +| main.rs:290:9:290:9 | e [D] | semmle.label | e [D] | +| main.rs:290:13:290:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] | +| main.rs:290:13:290:41 | ...::D {...} [D] | semmle.label | ...::D {...} [D] | +| main.rs:290:39:290:39 | s | semmle.label | s | +| main.rs:290:39:290:39 | s | semmle.label | s | +| main.rs:291:5:291:5 | e [D] | semmle.label | e [D] | +| main.rs:291:5:291:5 | e [D] | semmle.label | e [D] | +| main.rs:291:7:291:10 | sink | semmle.label | sink | +| main.rs:291:7:291:10 | sink | semmle.label | sink | +| main.rs:300:9:300:9 | s | semmle.label | s | +| main.rs:300:9:300:9 | s | semmle.label | s | +| main.rs:300:13:300:25 | simple_source | semmle.label | simple_source | +| main.rs:300:13:300:25 | simple_source | semmle.label | simple_source | +| main.rs:300:13:300:29 | simple_source(...) | semmle.label | simple_source(...) | +| main.rs:300:13:300:29 | simple_source(...) | semmle.label | simple_source(...) | +| main.rs:301:10:301:10 | s | semmle.label | s | +| main.rs:301:10:301:10 | s | semmle.label | s | +| main.rs:308:9:308:9 | s | semmle.label | s | +| main.rs:308:9:308:9 | s | semmle.label | s | +| main.rs:308:13:308:22 | source(...) | semmle.label | source(...) | +| main.rs:308:13:308:22 | source(...) | semmle.label | source(...) | +| main.rs:309:5:309:15 | simple_sink | semmle.label | simple_sink | +| main.rs:309:5:309:15 | simple_sink | semmle.label | simple_sink | +| main.rs:309:17:309:17 | s | semmle.label | s | +| main.rs:309:17:309:17 | s | semmle.label | s | +| main.rs:317:5:317:14 | arg_source | semmle.label | arg_source | +| main.rs:317:5:317:14 | arg_source | semmle.label | arg_source | +| main.rs:317:16:317:16 | [post] i | semmle.label | [post] i | +| main.rs:317:16:317:16 | [post] i | semmle.label | [post] i | +| main.rs:318:10:318:10 | i | semmle.label | i | +| main.rs:318:10:318:10 | i | semmle.label | i | +| main.rs:370:9:370:10 | x1 | semmle.label | x1 | +| main.rs:370:9:370:10 | x1 | semmle.label | x1 | +| main.rs:370:14:370:23 | source(...) | semmle.label | source(...) | +| main.rs:370:14:370:23 | source(...) | semmle.label | source(...) | +| main.rs:370:14:370:30 | ... .max(...) | semmle.label | ... .max(...) | +| main.rs:370:14:370:30 | ... .max(...) | semmle.label | ... .max(...) | +| main.rs:371:10:371:11 | x1 | semmle.label | x1 | +| main.rs:371:10:371:11 | x1 | semmle.label | x1 | +| main.rs:373:9:373:10 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | +| main.rs:373:9:373:10 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | +| main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | semmle.label | ... .max(...) [MyStruct.field1] | +| main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | semmle.label | ... .max(...) [MyStruct.field1] | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] | +| main.rs:374:17:374:26 | source(...) | semmle.label | source(...) | +| main.rs:374:17:374:26 | source(...) | semmle.label | source(...) | +| main.rs:381:10:381:11 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | +| main.rs:381:10:381:11 | x2 [MyStruct.field1] | semmle.label | x2 [MyStruct.field1] | +| main.rs:381:10:381:18 | x2.field1 | semmle.label | x2.field1 | +| main.rs:381:10:381:18 | x2.field1 | semmle.label | x2.field1 | +| main.rs:386:9:386:10 | x4 | semmle.label | x4 | +| main.rs:386:9:386:10 | x4 | semmle.label | x4 | +| main.rs:386:14:386:23 | source(...) | semmle.label | source(...) | +| main.rs:386:14:386:23 | source(...) | semmle.label | source(...) | +| main.rs:386:14:386:30 | ... .max(...) | semmle.label | ... .max(...) | +| main.rs:386:14:386:30 | ... .max(...) | semmle.label | ... .max(...) | +| main.rs:387:10:387:11 | x4 | semmle.label | x4 | +| main.rs:387:10:387:11 | x4 | semmle.label | x4 | +| main.rs:389:9:389:10 | x5 | semmle.label | x5 | +| main.rs:389:14:389:23 | source(...) | semmle.label | source(...) | +| main.rs:389:14:389:30 | ... .lt(...) | semmle.label | ... .lt(...) | +| main.rs:390:10:390:11 | x5 | semmle.label | x5 | +| main.rs:392:9:392:10 | x6 | semmle.label | x6 | +| main.rs:392:14:392:23 | source(...) | semmle.label | source(...) | +| main.rs:392:14:392:27 | ... < ... | semmle.label | ... < ... | +| main.rs:393:10:393:11 | x6 | semmle.label | x6 | subpaths | main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | main.rs:197:17:197:42 | if ... {...} else {...} | main.rs:198:13:198:24 | apply(...) | | main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | main.rs:197:17:197:42 | if ... {...} else {...} | main.rs:198:13:198:24 | apply(...) | @@ -658,21 +658,21 @@ invalidSpecComponent | main.rs:239:47:239:47 | i | main.rs:236:13:236:23 | enum_source | main.rs:239:47:239:47 | i | $@ | main.rs:236:13:236:23 | enum_source | enum_source | | main.rs:247:47:247:47 | i | main.rs:245:15:245:20 | source | main.rs:247:47:247:47 | i | $@ | main.rs:245:15:245:20 | source | source | | main.rs:247:47:247:47 | i | main.rs:245:15:245:20 | source | main.rs:247:47:247:47 | i | $@ | main.rs:245:15:245:20 | source | source | -| main.rs:257:5:257:13 | enum_sink | main.rs:256:13:256:22 | source(...) | main.rs:257:5:257:13 | enum_sink | $@ | main.rs:256:13:256:22 | source(...) | source(...) | -| main.rs:257:5:257:13 | enum_sink | main.rs:256:13:256:22 | source(...) | main.rs:257:5:257:13 | enum_sink | $@ | main.rs:256:13:256:22 | source(...) | source(...) | -| main.rs:264:7:264:10 | sink | main.rs:262:13:262:22 | source(...) | main.rs:264:7:264:10 | sink | $@ | main.rs:262:13:262:22 | source(...) | source(...) | -| main.rs:264:7:264:10 | sink | main.rs:262:13:262:22 | source(...) | main.rs:264:7:264:10 | sink | $@ | main.rs:262:13:262:22 | source(...) | source(...) | -| main.rs:274:10:274:10 | s | main.rs:273:13:273:25 | simple_source | main.rs:274:10:274:10 | s | $@ | main.rs:273:13:273:25 | simple_source | simple_source | -| main.rs:274:10:274:10 | s | main.rs:273:13:273:25 | simple_source | main.rs:274:10:274:10 | s | $@ | main.rs:273:13:273:25 | simple_source | simple_source | -| main.rs:282:5:282:15 | simple_sink | main.rs:281:13:281:22 | source(...) | main.rs:282:5:282:15 | simple_sink | $@ | main.rs:281:13:281:22 | source(...) | source(...) | -| main.rs:282:5:282:15 | simple_sink | main.rs:281:13:281:22 | source(...) | main.rs:282:5:282:15 | simple_sink | $@ | main.rs:281:13:281:22 | source(...) | source(...) | -| main.rs:291:10:291:10 | i | main.rs:290:5:290:14 | arg_source | main.rs:291:10:291:10 | i | $@ | main.rs:290:5:290:14 | arg_source | arg_source | -| main.rs:291:10:291:10 | i | main.rs:290:5:290:14 | arg_source | main.rs:291:10:291:10 | i | $@ | main.rs:290:5:290:14 | arg_source | arg_source | -| main.rs:344:10:344:11 | x1 | main.rs:343:14:343:23 | source(...) | main.rs:344:10:344:11 | x1 | $@ | main.rs:343:14:343:23 | source(...) | source(...) | -| main.rs:344:10:344:11 | x1 | main.rs:343:14:343:23 | source(...) | main.rs:344:10:344:11 | x1 | $@ | main.rs:343:14:343:23 | source(...) | source(...) | -| main.rs:354:10:354:18 | x2.field1 | main.rs:347:17:347:26 | source(...) | main.rs:354:10:354:18 | x2.field1 | $@ | main.rs:347:17:347:26 | source(...) | source(...) | -| main.rs:354:10:354:18 | x2.field1 | main.rs:347:17:347:26 | source(...) | main.rs:354:10:354:18 | x2.field1 | $@ | main.rs:347:17:347:26 | source(...) | source(...) | -| main.rs:360:10:360:11 | x4 | main.rs:359:14:359:23 | source(...) | main.rs:360:10:360:11 | x4 | $@ | main.rs:359:14:359:23 | source(...) | source(...) | -| main.rs:360:10:360:11 | x4 | main.rs:359:14:359:23 | source(...) | main.rs:360:10:360:11 | x4 | $@ | main.rs:359:14:359:23 | source(...) | source(...) | -| main.rs:363:10:363:11 | x5 | main.rs:362:14:362:23 | source(...) | main.rs:363:10:363:11 | x5 | $@ | main.rs:362:14:362:23 | source(...) | source(...) | -| main.rs:366:10:366:11 | x6 | main.rs:365:14:365:23 | source(...) | main.rs:366:10:366:11 | x6 | $@ | main.rs:365:14:365:23 | source(...) | source(...) | +| main.rs:284:5:284:13 | enum_sink | main.rs:283:13:283:22 | source(...) | main.rs:284:5:284:13 | enum_sink | $@ | main.rs:283:13:283:22 | source(...) | source(...) | +| main.rs:284:5:284:13 | enum_sink | main.rs:283:13:283:22 | source(...) | main.rs:284:5:284:13 | enum_sink | $@ | main.rs:283:13:283:22 | source(...) | source(...) | +| main.rs:291:7:291:10 | sink | main.rs:289:13:289:22 | source(...) | main.rs:291:7:291:10 | sink | $@ | main.rs:289:13:289:22 | source(...) | source(...) | +| main.rs:291:7:291:10 | sink | main.rs:289:13:289:22 | source(...) | main.rs:291:7:291:10 | sink | $@ | main.rs:289:13:289:22 | source(...) | source(...) | +| main.rs:301:10:301:10 | s | main.rs:300:13:300:25 | simple_source | main.rs:301:10:301:10 | s | $@ | main.rs:300:13:300:25 | simple_source | simple_source | +| main.rs:301:10:301:10 | s | main.rs:300:13:300:25 | simple_source | main.rs:301:10:301:10 | s | $@ | main.rs:300:13:300:25 | simple_source | simple_source | +| main.rs:309:5:309:15 | simple_sink | main.rs:308:13:308:22 | source(...) | main.rs:309:5:309:15 | simple_sink | $@ | main.rs:308:13:308:22 | source(...) | source(...) | +| main.rs:309:5:309:15 | simple_sink | main.rs:308:13:308:22 | source(...) | main.rs:309:5:309:15 | simple_sink | $@ | main.rs:308:13:308:22 | source(...) | source(...) | +| main.rs:318:10:318:10 | i | main.rs:317:5:317:14 | arg_source | main.rs:318:10:318:10 | i | $@ | main.rs:317:5:317:14 | arg_source | arg_source | +| main.rs:318:10:318:10 | i | main.rs:317:5:317:14 | arg_source | main.rs:318:10:318:10 | i | $@ | main.rs:317:5:317:14 | arg_source | arg_source | +| main.rs:371:10:371:11 | x1 | main.rs:370:14:370:23 | source(...) | main.rs:371:10:371:11 | x1 | $@ | main.rs:370:14:370:23 | source(...) | source(...) | +| main.rs:371:10:371:11 | x1 | main.rs:370:14:370:23 | source(...) | main.rs:371:10:371:11 | x1 | $@ | main.rs:370:14:370:23 | source(...) | source(...) | +| main.rs:381:10:381:18 | x2.field1 | main.rs:374:17:374:26 | source(...) | main.rs:381:10:381:18 | x2.field1 | $@ | main.rs:374:17:374:26 | source(...) | source(...) | +| main.rs:381:10:381:18 | x2.field1 | main.rs:374:17:374:26 | source(...) | main.rs:381:10:381:18 | x2.field1 | $@ | main.rs:374:17:374:26 | source(...) | source(...) | +| main.rs:387:10:387:11 | x4 | main.rs:386:14:386:23 | source(...) | main.rs:387:10:387:11 | x4 | $@ | main.rs:386:14:386:23 | source(...) | source(...) | +| main.rs:387:10:387:11 | x4 | main.rs:386:14:386:23 | source(...) | main.rs:387:10:387:11 | x4 | $@ | main.rs:386:14:386:23 | source(...) | source(...) | +| main.rs:390:10:390:11 | x5 | main.rs:389:14:389:23 | source(...) | main.rs:390:10:390:11 | x5 | $@ | main.rs:389:14:389:23 | source(...) | source(...) | +| main.rs:393:10:393:11 | x6 | main.rs:392:14:392:23 | source(...) | main.rs:393:10:393:11 | x6 | $@ | main.rs:392:14:392:23 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/models/models.ext.yml b/rust/ql/test/library-tests/dataflow/models/models.ext.yml index eb51ac64f50..52342e88022 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.ext.yml +++ b/rust/ql/test/library-tests/dataflow/models/models.ext.yml @@ -7,6 +7,7 @@ extensions: - ["main::enum_source", "ReturnValue.Field[main::MyFieldEnum::D::field_d]", "test-source", "manual"] - ["::source", "ReturnValue.Field[main::MyFieldEnum::C::field_c]", "test-source", "manual"] - ["main::arg_source", "Argument[0]", "test-source", "manual"] + - ["main::source_into_function::pass_source", "Argument[1].Parameter[0]", "test-source", "manual"] - addsTo: pack: codeql/rust-all extensible: sinkModel From 05a58323c1eca9a8c929209a17965ecbb6a88b43 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 18 Sep 2025 10:02:25 +0200 Subject: [PATCH 36/90] Rust: Add Warp test to request forgery query tests --- .../query-tests/security/CWE-918/Cargo.lock | 73 +++++++++++++++++++ .../query-tests/security/CWE-918/options.yml | 1 + .../security/CWE-918/request_forgery_tests.rs | 20 +++++ 3 files changed, 94 insertions(+) diff --git a/rust/ql/test/query-tests/security/CWE-918/Cargo.lock b/rust/ql/test/query-tests/security/CWE-918/Cargo.lock index 83c077741bc..d00e99a2909 100644 --- a/rust/ql/test/query-tests/security/CWE-918/Cargo.lock +++ b/rust/ql/test/query-tests/security/CWE-918/Cargo.lock @@ -714,6 +714,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -851,6 +861,26 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1132,6 +1162,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -1337,6 +1373,7 @@ dependencies = [ "poem", "reqwest", "tokio", + "warp", ] [[package]] @@ -1501,6 +1538,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1547,6 +1585,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -1598,6 +1642,35 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d06d9202adc1f15d709c4f4a2069be5428aa912cc025d6f268ac441ab066b0" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/rust/ql/test/query-tests/security/CWE-918/options.yml b/rust/ql/test/query-tests/security/CWE-918/options.yml index 078784053e1..6c6a1517497 100644 --- a/rust/ql/test/query-tests/security/CWE-918/options.yml +++ b/rust/ql/test/query-tests/security/CWE-918/options.yml @@ -3,3 +3,4 @@ qltest_dependencies: - reqwest = { version = "0.12.23", features = ["blocking", "json"] } - tokio = { version = "1.0", features = ["full"] } - poem = { version = "3.1.12", features = ["server"] } + - warp = { version = "0.4.2", features = ["server"] } diff --git a/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs b/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs index d9f2e1ae5c4..ab99d73db43 100644 --- a/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs +++ b/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs @@ -54,6 +54,26 @@ mod poem_server { } } +mod warp_test { + use warp::Filter; + + #[tokio::main] + #[rustfmt::skip] + async fn test_warp() { + // A route with parameter and `and_then` + let map_route = + warp::path::param().and_then(async |a: String| // $ MISSING: Source=a + { + + let response = reqwest::get(&a).await; // $ MISSING: Alert[rust/request-forgery]=a + match response { + Ok(resp) => Ok(resp.text().await.unwrap_or_default()), + Err(_err) => Err(warp::reject::not_found()), + } + }); + } +} + /// Start the Poem web application pub fn start() { tokio::runtime::Runtime::new() From 014c27ee8a501f31dadb133f1df0ef80f3141b97 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 17 Sep 2025 11:13:16 +0200 Subject: [PATCH 37/90] Rust: Discard sources with spaces in inline flow tests --- rust/ql/lib/utils/test/InlineFlowTest.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/utils/test/InlineFlowTest.qll b/rust/ql/lib/utils/test/InlineFlowTest.qll index 80abf21e1f5..9ba92f7757b 100644 --- a/rust/ql/lib/utils/test/InlineFlowTest.qll +++ b/rust/ql/lib/utils/test/InlineFlowTest.qll @@ -34,10 +34,9 @@ private module FlowTestImpl implements InputSig { result = src.asExpr().(CallExprCfgNode).getArgument(0).toString() or sourceNode(src, _) and - exists(CallExprBase call | - call = src.(Node::FlowSummaryNode).getSourceElement().getCall() and - result = call.getArgList().getArg(0).toString() - ) + result = src.(Node::FlowSummaryNode).getSourceElement().getCall().getArg(0).toString() and + // Don't use the result if it contains spaces + not result.matches("% %") } bindingset[src, sink] From 265e8b3623d3554777821cc068f17db4626bb015 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 17 Sep 2025 13:56:48 +0200 Subject: [PATCH 38/90] Shared: Pass SummaryComponentStack to isSource and getSourceType --- .../rust/dataflow/internal/DataFlowImpl.qll | 3 +- .../dataflow/internal/FlowSummaryImpl.qll | 45 +- .../library-tests/dataflow/models/main.rs | 8 +- .../dataflow/models/models.expected | 163 ++-- .../dataflow/sources/InlineFlow.expected | 897 +++++++++--------- .../dataflow/sources/web_frameworks.rs | 8 +- .../security/CWE-918/RequestForgery.expected | 37 +- .../security/CWE-918/request_forgery_tests.rs | 4 +- .../dataflow/internal/FlowSummaryImpl.qll | 40 +- 9 files changed, 686 insertions(+), 519 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 1d7a3d49cf4..4c252dfcd0f 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -508,7 +508,8 @@ module RustDataFlow implements InputSig { */ predicate jumpStep(Node node1, Node node2) { FlowSummaryImpl::Private::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(), - node2.(FlowSummaryNode).getSummaryNode()) + node2.(FlowSummaryNode).getSummaryNode()) or + FlowSummaryImpl::Private::Steps::sourceJumpStep(node1.(FlowSummaryNode).getSummaryNode(), node2) } pragma[nomagic] diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll index 997f27e51e1..129bd468e01 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll @@ -6,7 +6,10 @@ private import rust private import codeql.dataflow.internal.FlowSummaryImpl private import codeql.dataflow.internal.AccessPathSyntax as AccessPath private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.internal.PathResolution private import codeql.rust.dataflow.FlowSummary +private import codeql.rust.dataflow.Ssa +private import codeql.rust.controlflow.CfgNodes private import Content module Input implements InputSig { @@ -133,16 +136,44 @@ private module StepsInput implements Impl::Private::StepsInputSig { result.asCallCfgNode().getCall().getStaticTarget() = sc } - RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { - sc = Impl::Private::SummaryComponent::return(_) and + /** Gets the argument of `source` described by `sc`, if any. */ + private Expr getSourceNodeArgument(Input::SourceBase source, Impl::Private::SummaryComponent sc) { + exists(ArgumentPosition pos | + sc = Impl::Private::SummaryComponent::argument(pos) and + result = pos.getArgument(source.getCall()) + ) + } + + /** Get the callable that `expr` refers to. */ + private Callable getCallable(Expr expr) { + result = resolvePath(expr.(PathExpr).getPath()).(Function) + or + result = expr.(ClosureExpr) + or + // The expression is an SSA read of an assignment of a closure + exists(Ssa::Definition def, ExprCfgNode value | + def.getARead().getAstNode() = expr and + def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(value) and + result = value.getExpr().(ClosureExpr) + ) + } + + RustDataFlow::DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { + result.asCfgScope() = source.getEnclosingCfgScope() + } + + RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { + s.head() = Impl::Private::SummaryComponent::return(_) and result.asExpr().getExpr() = source.getCall() or - exists(CallExprBase call, Expr arg, ArgumentPosition pos | - result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() = arg and - sc = Impl::Private::SummaryComponent::argument(pos) and - call = source.getCall() and - arg = pos.getArgument(call) + exists(ArgumentPosition pos, Expr arg | + s.head() = Impl::Private::SummaryComponent::parameter(pos) and + arg = getSourceNodeArgument(source, s.tail().head()) and + result.asParameter() = getCallable(arg).getParam(pos.getPosition()) ) + or + result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() = + getSourceNodeArgument(source, s.head()) } RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index 98a45655035..7daa883996f 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -258,20 +258,20 @@ mod source_into_function { } fn test_source_into_function() { - let a = |a| sink(a); // $ MISSING: hasValueFlow=1 + let a = |a| sink(a); // $ hasValueFlow=1 pass_source(1, a); pass_source(2, |a| { - sink(a); // $ MISSING: hasValueFlow=2 + sink(a); // $ hasValueFlow=2 }); fn f(a: i64) { - sink(a) // $ MISSING: hasValueFlow=3 + sink(a) // $ hasValueFlow=3 } pass_source(3, f); pass_source(4, async move |a| { - sink(a); // $ MISSING: hasValueFlow=4 + sink(a); // $ hasValueFlow=4 }); } } diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index c04b66068db..2918e5c3c39 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -6,22 +6,23 @@ models | 5 | Source: main::arg_source; Argument[0]; test-source | | 6 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | | 7 | Source: main::simple_source; ReturnValue; test-source | -| 8 | Summary: <_ as core::cmp::Ord>::max; Argument[self]; ReturnValue; value | -| 9 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | -| 10 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | -| 11 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | -| 12 | Summary: main::coerce; Argument[0]; ReturnValue; taint | -| 13 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | -| 14 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | -| 15 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | -| 16 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | -| 17 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | -| 18 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | -| 19 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | -| 20 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | -| 21 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | -| 22 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | -| 23 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | +| 8 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | +| 9 | Summary: <_ as core::cmp::Ord>::max; Argument[self]; ReturnValue; value | +| 10 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | +| 11 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | +| 12 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | +| 13 | Summary: main::coerce; Argument[0]; ReturnValue; taint | +| 14 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | +| 15 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | +| 16 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | +| 17 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | +| 18 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | +| 19 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | +| 20 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | +| 21 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | +| 22 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | +| 23 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | +| 24 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | edges | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | @@ -31,7 +32,7 @@ edges | main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL | | main.rs:25:9:25:9 | s | main.rs:26:17:26:17 | s | provenance | | | main.rs:25:13:25:22 | source(...) | main.rs:25:9:25:9 | s | provenance | | -| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:12 | +| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:13 | | main.rs:40:9:40:9 | s | main.rs:41:27:41:27 | s | provenance | | | main.rs:40:9:40:9 | s | main.rs:41:27:41:27 | s | provenance | | | main.rs:40:13:40:21 | source(...) | main.rs:40:9:40:9 | s | provenance | | @@ -42,8 +43,8 @@ edges | main.rs:41:14:41:28 | ...::A(...) [A] | main.rs:41:9:41:10 | e1 [A] | provenance | | | main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | | | main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | | -| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:18 | -| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:18 | +| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:19 | +| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:19 | | main.rs:53:9:53:9 | s | main.rs:54:26:54:26 | s | provenance | | | main.rs:53:9:53:9 | s | main.rs:54:26:54:26 | s | provenance | | | main.rs:53:13:53:21 | source(...) | main.rs:53:9:53:9 | s | provenance | | @@ -52,8 +53,8 @@ edges | main.rs:54:9:54:10 | e1 [B] | main.rs:55:11:55:12 | e1 [B] | provenance | | | main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:54:9:54:10 | e1 [B] | provenance | | | main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:54:9:54:10 | e1 [B] | provenance | | -| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:23 | -| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:23 | +| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:24 | +| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:24 | | main.rs:55:11:55:12 | e1 [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | | | main.rs:55:11:55:12 | e1 [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | | | main.rs:57:9:57:23 | ...::B(...) [B] | main.rs:57:22:57:22 | i | provenance | | @@ -70,8 +71,8 @@ edges | main.rs:73:14:73:42 | ...::C {...} [C] | main.rs:73:9:73:10 | e1 [C] | provenance | | | main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | | | main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | | -| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:17 | -| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:17 | +| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:18 | +| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:18 | | main.rs:85:9:85:9 | s | main.rs:86:28:86:28 | s | provenance | | | main.rs:85:9:85:9 | s | main.rs:86:28:86:28 | s | provenance | | | main.rs:85:13:85:21 | source(...) | main.rs:85:9:85:9 | s | provenance | | @@ -80,8 +81,8 @@ edges | main.rs:86:9:86:10 | e1 [D] | main.rs:87:11:87:12 | e1 [D] | provenance | | | main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:86:9:86:10 | e1 [D] | provenance | | | main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:86:9:86:10 | e1 [D] | provenance | | -| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:22 | -| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:22 | +| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:23 | +| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:23 | | main.rs:87:11:87:12 | e1 [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | | | main.rs:87:11:87:12 | e1 [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | | | main.rs:89:9:89:37 | ...::D {...} [D] | main.rs:89:35:89:35 | i | provenance | | @@ -98,8 +99,8 @@ edges | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | main.rs:105:9:105:17 | my_struct [MyStruct.field1] | provenance | | | main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:15 | -| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:15 | +| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:16 | +| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:16 | | main.rs:126:9:126:9 | s | main.rs:127:38:127:38 | s | provenance | | | main.rs:126:9:126:9 | s | main.rs:127:38:127:38 | s | provenance | | | main.rs:126:13:126:21 | source(...) | main.rs:126:9:126:9 | s | provenance | | @@ -108,16 +109,16 @@ edges | main.rs:127:9:127:17 | my_struct [MyStruct.field2] | main.rs:129:10:129:18 | my_struct [MyStruct.field2] | provenance | | | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | main.rs:127:9:127:17 | my_struct [MyStruct.field2] | provenance | | | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | main.rs:127:9:127:17 | my_struct [MyStruct.field2] | provenance | | -| main.rs:127:38:127:38 | s | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:20 | -| main.rs:127:38:127:38 | s | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:20 | +| main.rs:127:38:127:38 | s | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:21 | +| main.rs:127:38:127:38 | s | main.rs:127:21:127:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:21 | | main.rs:129:10:129:18 | my_struct [MyStruct.field2] | main.rs:129:10:129:25 | my_struct.field2 | provenance | | | main.rs:129:10:129:18 | my_struct [MyStruct.field2] | main.rs:129:10:129:25 | my_struct.field2 | provenance | | | main.rs:138:9:138:9 | s | main.rs:139:29:139:29 | s | provenance | | | main.rs:138:9:138:9 | s | main.rs:139:29:139:29 | s | provenance | | | main.rs:138:13:138:21 | source(...) | main.rs:138:9:138:9 | s | provenance | | | main.rs:138:13:138:21 | source(...) | main.rs:138:9:138:9 | s | provenance | | -| main.rs:139:28:139:30 | [...] [element] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:13 | -| main.rs:139:28:139:30 | [...] [element] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:13 | +| main.rs:139:28:139:30 | [...] [element] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:14 | +| main.rs:139:28:139:30 | [...] [element] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:14 | | main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [element] | provenance | | | main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [element] | provenance | | | main.rs:148:9:148:9 | s | main.rs:149:33:149:33 | s | provenance | | @@ -128,8 +129,8 @@ edges | main.rs:149:9:149:11 | arr [element] | main.rs:150:10:150:12 | arr [element] | provenance | | | main.rs:149:15:149:34 | set_array_element(...) [element] | main.rs:149:9:149:11 | arr [element] | provenance | | | main.rs:149:15:149:34 | set_array_element(...) [element] | main.rs:149:9:149:11 | arr [element] | provenance | | -| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [element] | provenance | MaD:19 | -| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [element] | provenance | MaD:19 | +| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [element] | provenance | MaD:20 | +| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [element] | provenance | MaD:20 | | main.rs:150:10:150:12 | arr [element] | main.rs:150:10:150:15 | arr[0] | provenance | | | main.rs:150:10:150:12 | arr [element] | main.rs:150:10:150:15 | arr[0] | provenance | | | main.rs:159:9:159:9 | s | main.rs:160:14:160:14 | s | provenance | | @@ -142,8 +143,8 @@ edges | main.rs:160:13:160:18 | TupleExpr [tuple.0] | main.rs:160:9:160:9 | t [tuple.0] | provenance | | | main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | | | main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | | -| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:16 | -| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:16 | +| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:17 | +| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:17 | | main.rs:172:9:172:9 | s | main.rs:173:31:173:31 | s | provenance | | | main.rs:172:9:172:9 | s | main.rs:173:31:173:31 | s | provenance | | | main.rs:172:13:172:22 | source(...) | main.rs:172:9:172:9 | s | provenance | | @@ -152,8 +153,8 @@ edges | main.rs:173:9:173:9 | t [tuple.1] | main.rs:175:10:175:10 | t [tuple.1] | provenance | | | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:173:9:173:9 | t [tuple.1] | provenance | | | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:173:9:173:9 | t [tuple.1] | provenance | | -| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:21 | -| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:21 | +| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:22 | +| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:22 | | main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | | | main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | | | main.rs:187:9:187:9 | s | main.rs:192:11:192:11 | s | provenance | | @@ -162,8 +163,8 @@ edges | main.rs:187:13:187:22 | source(...) | main.rs:187:9:187:9 | s | provenance | | | main.rs:188:14:188:14 | ... | main.rs:189:14:189:14 | n | provenance | | | main.rs:188:14:188:14 | ... | main.rs:189:14:189:14 | n | provenance | | -| main.rs:192:11:192:11 | s | main.rs:188:14:188:14 | ... | provenance | MaD:10 | -| main.rs:192:11:192:11 | s | main.rs:188:14:188:14 | ... | provenance | MaD:10 | +| main.rs:192:11:192:11 | s | main.rs:188:14:188:14 | ... | provenance | MaD:11 | +| main.rs:192:11:192:11 | s | main.rs:188:14:188:14 | ... | provenance | MaD:11 | | main.rs:196:13:196:22 | source(...) | main.rs:198:23:198:23 | f [captured s] | provenance | | | main.rs:196:13:196:22 | source(...) | main.rs:198:23:198:23 | f [captured s] | provenance | | | main.rs:197:40:197:40 | s | main.rs:197:17:197:42 | if ... {...} else {...} | provenance | | @@ -172,14 +173,14 @@ edges | main.rs:198:9:198:9 | t | main.rs:199:10:199:10 | t | provenance | | | main.rs:198:13:198:24 | apply(...) | main.rs:198:9:198:9 | t | provenance | | | main.rs:198:13:198:24 | apply(...) | main.rs:198:9:198:9 | t | provenance | | -| main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:10 | -| main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:10 | | main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:11 | | main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:11 | -| main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:10 | -| main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:10 | +| main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:12 | +| main.rs:198:23:198:23 | f [captured s] | main.rs:197:40:197:40 | s | provenance | MaD:12 | | main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:11 | | main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:11 | +| main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:12 | +| main.rs:198:23:198:23 | f [captured s] | main.rs:198:13:198:24 | apply(...) | provenance | MaD:12 | | main.rs:203:9:203:9 | s | main.rs:205:19:205:19 | s | provenance | | | main.rs:203:9:203:9 | s | main.rs:205:19:205:19 | s | provenance | | | main.rs:203:13:203:22 | source(...) | main.rs:203:9:203:9 | s | provenance | | @@ -190,10 +191,10 @@ edges | main.rs:205:9:205:9 | t | main.rs:206:10:206:10 | t | provenance | | | main.rs:205:13:205:23 | apply(...) | main.rs:205:9:205:9 | t | provenance | | | main.rs:205:13:205:23 | apply(...) | main.rs:205:9:205:9 | t | provenance | | -| main.rs:205:19:205:19 | s | main.rs:204:14:204:14 | ... | provenance | MaD:10 | -| main.rs:205:19:205:19 | s | main.rs:204:14:204:14 | ... | provenance | MaD:10 | -| main.rs:205:19:205:19 | s | main.rs:205:13:205:23 | apply(...) | provenance | MaD:10 | -| main.rs:205:19:205:19 | s | main.rs:205:13:205:23 | apply(...) | provenance | MaD:10 | +| main.rs:205:19:205:19 | s | main.rs:204:14:204:14 | ... | provenance | MaD:11 | +| main.rs:205:19:205:19 | s | main.rs:204:14:204:14 | ... | provenance | MaD:11 | +| main.rs:205:19:205:19 | s | main.rs:205:13:205:23 | apply(...) | provenance | MaD:11 | +| main.rs:205:19:205:19 | s | main.rs:205:13:205:23 | apply(...) | provenance | MaD:11 | | main.rs:215:9:215:9 | s | main.rs:216:30:216:30 | s | provenance | | | main.rs:215:9:215:9 | s | main.rs:216:30:216:30 | s | provenance | | | main.rs:215:13:215:22 | source(...) | main.rs:215:9:215:9 | s | provenance | | @@ -204,8 +205,8 @@ edges | main.rs:216:13:216:31 | get_async_number(...) [future] | main.rs:216:13:216:37 | await ... | provenance | | | main.rs:216:13:216:37 | await ... | main.rs:216:9:216:9 | t | provenance | | | main.rs:216:13:216:37 | await ... | main.rs:216:9:216:9 | t | provenance | | -| main.rs:216:30:216:30 | s | main.rs:216:13:216:31 | get_async_number(...) [future] | provenance | MaD:14 | -| main.rs:216:30:216:30 | s | main.rs:216:13:216:31 | get_async_number(...) [future] | provenance | MaD:14 | +| main.rs:216:30:216:30 | s | main.rs:216:13:216:31 | get_async_number(...) [future] | provenance | MaD:15 | +| main.rs:216:30:216:30 | s | main.rs:216:13:216:31 | get_async_number(...) [future] | provenance | MaD:15 | | main.rs:236:9:236:9 | s [D] | main.rs:237:11:237:11 | s [D] | provenance | | | main.rs:236:9:236:9 | s [D] | main.rs:237:11:237:11 | s [D] | provenance | | | main.rs:236:13:236:23 | enum_source | main.rs:236:13:236:27 | enum_source(...) [D] | provenance | Src:MaD:6 | @@ -230,6 +231,22 @@ edges | main.rs:247:9:247:37 | ...::C {...} [C] | main.rs:247:35:247:35 | i | provenance | | | main.rs:247:35:247:35 | i | main.rs:247:47:247:47 | i | provenance | | | main.rs:247:35:247:35 | i | main.rs:247:47:247:47 | i | provenance | | +| main.rs:261:18:261:18 | ... | main.rs:261:26:261:26 | a | provenance | | +| main.rs:261:18:261:18 | ... | main.rs:261:26:261:26 | a | provenance | | +| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:264:25:264:25 | ... | main.rs:265:18:265:18 | a | provenance | | +| main.rs:264:25:264:25 | ... | main.rs:265:18:265:18 | a | provenance | | +| main.rs:268:14:268:19 | ...: i64 | main.rs:269:18:269:18 | a | provenance | | +| main.rs:268:14:268:19 | ...: i64 | main.rs:269:18:269:18 | a | provenance | | +| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 MaD:8 | +| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 MaD:8 | +| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:273:36:273:36 | ... | main.rs:274:18:274:18 | a | provenance | | +| main.rs:273:36:273:36 | ... | main.rs:274:18:274:18 | a | provenance | | | main.rs:283:9:283:9 | s | main.rs:284:41:284:41 | s | provenance | | | main.rs:283:9:283:9 | s | main.rs:284:41:284:41 | s | provenance | | | main.rs:283:13:283:22 | source(...) | main.rs:283:9:283:9 | s | provenance | | @@ -268,31 +285,31 @@ edges | main.rs:317:16:317:16 | [post] i | main.rs:318:10:318:10 | i | provenance | | | main.rs:370:9:370:10 | x1 | main.rs:371:10:371:11 | x1 | provenance | | | main.rs:370:9:370:10 | x1 | main.rs:371:10:371:11 | x1 | provenance | | -| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:9 | +| main.rs:370:14:370:23 | source(...) | main.rs:370:14:370:30 | ... .max(...) | provenance | MaD:9 | | main.rs:370:14:370:30 | ... .max(...) | main.rs:370:9:370:10 | x1 | provenance | | | main.rs:370:14:370:30 | ... .max(...) | main.rs:370:9:370:10 | x1 | provenance | | | main.rs:373:9:373:10 | x2 [MyStruct.field1] | main.rs:381:10:381:11 | x2 [MyStruct.field1] | provenance | | | main.rs:373:9:373:10 | x2 [MyStruct.field1] | main.rs:381:10:381:11 | x2 [MyStruct.field1] | provenance | | | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | main.rs:373:9:373:10 | x2 [MyStruct.field1] | provenance | | | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | main.rs:373:9:373:10 | x2 [MyStruct.field1] | provenance | | -| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | -| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:8 | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:9 | +| main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | main.rs:373:14:380:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:9 | | main.rs:374:17:374:26 | source(...) | main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:374:17:374:26 | source(...) | main.rs:373:15:376:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:381:10:381:11 | x2 [MyStruct.field1] | main.rs:381:10:381:18 | x2.field1 | provenance | | | main.rs:381:10:381:11 | x2 [MyStruct.field1] | main.rs:381:10:381:18 | x2.field1 | provenance | | | main.rs:386:9:386:10 | x4 | main.rs:387:10:387:11 | x4 | provenance | | | main.rs:386:9:386:10 | x4 | main.rs:387:10:387:11 | x4 | provenance | | -| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:8 | -| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:8 | +| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:9 | +| main.rs:386:14:386:23 | source(...) | main.rs:386:14:386:30 | ... .max(...) | provenance | MaD:9 | | main.rs:386:14:386:30 | ... .max(...) | main.rs:386:9:386:10 | x4 | provenance | | | main.rs:386:14:386:30 | ... .max(...) | main.rs:386:9:386:10 | x4 | provenance | | | main.rs:389:9:389:10 | x5 | main.rs:390:10:390:11 | x5 | provenance | | -| main.rs:389:14:389:23 | source(...) | main.rs:389:14:389:30 | ... .lt(...) | provenance | MaD:9 | +| main.rs:389:14:389:23 | source(...) | main.rs:389:14:389:30 | ... .lt(...) | provenance | MaD:10 | | main.rs:389:14:389:30 | ... .lt(...) | main.rs:389:9:389:10 | x5 | provenance | | | main.rs:392:9:392:10 | x6 | main.rs:393:10:393:11 | x6 | provenance | | -| main.rs:392:14:392:23 | source(...) | main.rs:392:14:392:27 | ... < ... | provenance | MaD:9 | +| main.rs:392:14:392:23 | source(...) | main.rs:392:14:392:27 | ... < ... | provenance | MaD:10 | | main.rs:392:14:392:27 | ... < ... | main.rs:392:9:392:10 | x6 | provenance | | nodes | main.rs:15:9:15:9 | s | semmle.label | s | @@ -533,6 +550,30 @@ nodes | main.rs:247:35:247:35 | i | semmle.label | i | | main.rs:247:47:247:47 | i | semmle.label | i | | main.rs:247:47:247:47 | i | semmle.label | i | +| main.rs:261:18:261:18 | ... | semmle.label | ... | +| main.rs:261:18:261:18 | ... | semmle.label | ... | +| main.rs:261:26:261:26 | a | semmle.label | a | +| main.rs:261:26:261:26 | a | semmle.label | a | +| main.rs:262:9:262:19 | pass_source | semmle.label | pass_source | +| main.rs:262:9:262:19 | pass_source | semmle.label | pass_source | +| main.rs:264:9:264:19 | pass_source | semmle.label | pass_source | +| main.rs:264:9:264:19 | pass_source | semmle.label | pass_source | +| main.rs:264:25:264:25 | ... | semmle.label | ... | +| main.rs:264:25:264:25 | ... | semmle.label | ... | +| main.rs:265:18:265:18 | a | semmle.label | a | +| main.rs:265:18:265:18 | a | semmle.label | a | +| main.rs:268:14:268:19 | ...: i64 | semmle.label | ...: i64 | +| main.rs:268:14:268:19 | ...: i64 | semmle.label | ...: i64 | +| main.rs:269:18:269:18 | a | semmle.label | a | +| main.rs:269:18:269:18 | a | semmle.label | a | +| main.rs:271:9:271:19 | pass_source | semmle.label | pass_source | +| main.rs:271:9:271:19 | pass_source | semmle.label | pass_source | +| main.rs:273:9:273:19 | pass_source | semmle.label | pass_source | +| main.rs:273:9:273:19 | pass_source | semmle.label | pass_source | +| main.rs:273:36:273:36 | ... | semmle.label | ... | +| main.rs:273:36:273:36 | ... | semmle.label | ... | +| main.rs:274:18:274:18 | a | semmle.label | a | +| main.rs:274:18:274:18 | a | semmle.label | a | | main.rs:283:9:283:9 | s | semmle.label | s | | main.rs:283:9:283:9 | s | semmle.label | s | | main.rs:283:13:283:22 | source(...) | semmle.label | source(...) | @@ -658,6 +699,14 @@ invalidSpecComponent | main.rs:239:47:239:47 | i | main.rs:236:13:236:23 | enum_source | main.rs:239:47:239:47 | i | $@ | main.rs:236:13:236:23 | enum_source | enum_source | | main.rs:247:47:247:47 | i | main.rs:245:15:245:20 | source | main.rs:247:47:247:47 | i | $@ | main.rs:245:15:245:20 | source | source | | main.rs:247:47:247:47 | i | main.rs:245:15:245:20 | source | main.rs:247:47:247:47 | i | $@ | main.rs:245:15:245:20 | source | source | +| main.rs:261:26:261:26 | a | main.rs:262:9:262:19 | pass_source | main.rs:261:26:261:26 | a | $@ | main.rs:262:9:262:19 | pass_source | pass_source | +| main.rs:261:26:261:26 | a | main.rs:262:9:262:19 | pass_source | main.rs:261:26:261:26 | a | $@ | main.rs:262:9:262:19 | pass_source | pass_source | +| main.rs:265:18:265:18 | a | main.rs:264:9:264:19 | pass_source | main.rs:265:18:265:18 | a | $@ | main.rs:264:9:264:19 | pass_source | pass_source | +| main.rs:265:18:265:18 | a | main.rs:264:9:264:19 | pass_source | main.rs:265:18:265:18 | a | $@ | main.rs:264:9:264:19 | pass_source | pass_source | +| main.rs:269:18:269:18 | a | main.rs:271:9:271:19 | pass_source | main.rs:269:18:269:18 | a | $@ | main.rs:271:9:271:19 | pass_source | pass_source | +| main.rs:269:18:269:18 | a | main.rs:271:9:271:19 | pass_source | main.rs:269:18:269:18 | a | $@ | main.rs:271:9:271:19 | pass_source | pass_source | +| main.rs:274:18:274:18 | a | main.rs:273:9:273:19 | pass_source | main.rs:274:18:274:18 | a | $@ | main.rs:273:9:273:19 | pass_source | pass_source | +| main.rs:274:18:274:18 | a | main.rs:273:9:273:19 | pass_source | main.rs:274:18:274:18 | a | $@ | main.rs:273:9:273:19 | pass_source | pass_source | | main.rs:284:5:284:13 | enum_sink | main.rs:283:13:283:22 | source(...) | main.rs:284:5:284:13 | enum_sink | $@ | main.rs:283:13:283:22 | source(...) | source(...) | | main.rs:284:5:284:13 | enum_sink | main.rs:283:13:283:22 | source(...) | main.rs:284:5:284:13 | enum_sink | $@ | main.rs:283:13:283:22 | source(...) | source(...) | | main.rs:291:7:291:10 | sink | main.rs:289:13:289:22 | source(...) | main.rs:291:7:291:10 | sink | $@ | main.rs:289:13:289:22 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/sources/InlineFlow.expected b/rust/ql/test/library-tests/dataflow/sources/InlineFlow.expected index af0e73ca2c0..e0855a5d854 100644 --- a/rust/ql/test/library-tests/dataflow/sources/InlineFlow.expected +++ b/rust/ql/test/library-tests/dataflow/sources/InlineFlow.expected @@ -1,142 +1,145 @@ models -| 1 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 2 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 3 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 4 | Source: ::send_request; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 5 | Source: ::file_name; ReturnValue; file | -| 6 | Source: ::path; ReturnValue; file | -| 7 | Source: ::open; ReturnValue.Field[core::result::Result::Ok(0)]; file | -| 8 | Source: ::open; ReturnValue.Field[core::result::Result::Ok(0)]; file | -| 9 | Source: ::connect; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 10 | Source: ::connect_timeout; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 11 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 12 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 13 | Source: ::file_name; ReturnValue; file | -| 14 | Source: ::path; ReturnValue; file | -| 15 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 16 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 17 | Source: reqwest::get; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | -| 18 | Source: std::env::args; ReturnValue.Element; commandargs | -| 19 | Source: std::env::args_os; ReturnValue.Element; commandargs | -| 20 | Source: std::env::current_dir; ReturnValue.Field[core::result::Result::Ok(0)]; commandargs | -| 21 | Source: std::env::current_exe; ReturnValue.Field[core::result::Result::Ok(0)]; commandargs | -| 22 | Source: std::env::home_dir; ReturnValue.Field[core::option::Option::Some(0)]; commandargs | -| 23 | Source: std::env::var; ReturnValue.Field[core::result::Result::Ok(0)]; environment | -| 24 | Source: std::env::var_os; ReturnValue.Field[core::option::Option::Some(0)]; environment | -| 25 | Source: std::fs::read; ReturnValue.Field[core::result::Result::Ok(0)]; file | -| 26 | Source: std::fs::read; ReturnValue; file | -| 27 | Source: std::fs::read_link; ReturnValue.Field[core::result::Result::Ok(0)]; file | -| 28 | Source: std::fs::read_to_string; ReturnValue.Field[core::result::Result::Ok(0)]; file | -| 29 | Source: std::fs::read_to_string; ReturnValue; file | -| 30 | Source: std::io::stdio::stdin; ReturnValue; stdin | -| 31 | Source: tokio::fs::read::read; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 32 | Source: tokio::fs::read_link::read_link; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 33 | Source: tokio::fs::read_to_string::read_to_string; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | -| 34 | Source: tokio::io::stdin::stdin; ReturnValue; stdin | -| 35 | Summary: <_ as async_std::io::read::ReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | -| 36 | Summary: <_ as async_std::io::read::ReadExt>::read; Argument[self]; Argument[0].Reference; taint | -| 37 | Summary: <_ as core::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value | -| 38 | Summary: <_ as core::iter::traits::iterator::Iterator>::collect; Argument[self].Element; ReturnValue.Element; value | -| 39 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | -| 40 | Summary: <_ as futures_io::if_std::AsyncBufRead>::poll_fill_buf; Argument[self].Reference; ReturnValue.Field[core::task::poll::Poll::Ready(0)].Field[core::result::Result::Ok(0)]; taint | -| 41 | Summary: <_ as futures_util::io::AsyncBufReadExt>::fill_buf; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 42 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self].Reference; Argument[0].Reference; taint | -| 43 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self]; Argument[0].Reference; taint | -| 44 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self].Reference; Argument[1].Reference; taint | -| 45 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self]; Argument[1].Reference; taint | -| 46 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | -| 47 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self]; Argument[0].Reference; taint | -| 48 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self].Reference; Argument[0].Reference; taint | -| 49 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self]; Argument[0].Reference; taint | -| 50 | Summary: <_ as std::io::BufRead>::lines; Argument[self]; ReturnValue; taint | -| 51 | Summary: <_ as std::io::BufRead>::read_line; Argument[self]; Argument[0].Reference; taint | -| 52 | Summary: <_ as std::io::BufRead>::read_until; Argument[self]; Argument[1].Reference; taint | -| 53 | Summary: <_ as std::io::BufRead>::split; Argument[self]; ReturnValue; taint | -| 54 | Summary: <_ as std::io::Read>::bytes; Argument[self]; ReturnValue; taint | -| 55 | Summary: <_ as std::io::Read>::chain; Argument[0]; ReturnValue; taint | -| 56 | Summary: <_ as std::io::Read>::chain; Argument[self]; ReturnValue; taint | -| 57 | Summary: <_ as std::io::Read>::read; Argument[self]; Argument[0].Reference; taint | -| 58 | Summary: <_ as std::io::Read>::read_exact; Argument[self]; Argument[0].Reference; taint | -| 59 | Summary: <_ as std::io::Read>::read_to_end; Argument[self]; Argument[0].Reference; taint | -| 60 | Summary: <_ as std::io::Read>::read_to_string; Argument[self]; Argument[0].Reference; taint | -| 61 | Summary: <_ as std::io::Read>::take; Argument[self]; ReturnValue; taint | -| 62 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::fill_buf; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 63 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::lines; Argument[self]; ReturnValue; taint | -| 64 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::read_line; Argument[self]; Argument[0].Reference; taint | -| 65 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::read_until; Argument[self]; Argument[1].Reference; taint | -| 66 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::split; Argument[self]; ReturnValue; taint | -| 67 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read; Argument[self]; Argument[0].Reference; taint | -| 68 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_buf; Argument[self]; Argument[0].Reference; taint | -| 69 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_exact; Argument[self]; Argument[0].Reference; taint | -| 70 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_f32; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 71 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_i16; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 72 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_i64_le; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 73 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_to_end; Argument[self]; Argument[0].Reference; taint | -| 74 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_to_string; Argument[self]; Argument[0].Reference; taint | -| 75 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_u8; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 76 | Summary: ::as_bytes; Argument[self]; ReturnValue; value | -| 77 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 78 | Summary: ::expect; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | -| 79 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | -| 80 | Summary: ::new; Argument[0].Reference; ReturnValue; value | -| 81 | Summary: ::new; Argument[0]; ReturnValue.Field[core::pin::Pin::__pointer]; value | -| 82 | Summary: ::new; Argument[0]; ReturnValue; value | -| 83 | Summary: ::expect; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 84 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 85 | Summary: ::as_bytes; Argument[self]; ReturnValue; value | -| 86 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 87 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 88 | Summary: ::connect; Argument[1]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 89 | Summary: ::new; Argument[0]; ReturnValue; taint | -| 90 | Summary: ::bytes; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 91 | Summary: ::chunk; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | -| 92 | Summary: ::text; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | -| 93 | Summary: ::bytes; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 94 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 95 | Summary: ::text_with_charset; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 96 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | -| 97 | Summary: ::read; Argument[self]; Argument[0]; taint | -| 98 | Summary: ::read_to_end; Argument[self]; Argument[0].Reference; taint | -| 99 | Summary: ::read_to_end; Argument[self]; Argument[0]; taint | -| 100 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | -| 101 | Summary: ::read_to_string; Argument[self]; Argument[0]; taint | -| 102 | Summary: ::next; Argument[self]; ReturnValue.Field[core::option::Option::Some(0)].Field[core::result::Result::Ok(0)]; taint | -| 103 | Summary: ::fill_buf; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 104 | Summary: ::buffer; Argument[self]; ReturnValue; taint | -| 105 | Summary: ::new; Argument[0]; ReturnValue; taint | -| 106 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | -| 107 | Summary: ::read; Argument[self]; Argument[0]; taint | -| 108 | Summary: ::read_exact; Argument[self]; Argument[0].Reference; taint | -| 109 | Summary: ::read_exact; Argument[self]; Argument[0]; taint | -| 110 | Summary: ::read_to_end; Argument[self]; Argument[0].Reference; taint | -| 111 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | -| 112 | Summary: ::read_to_string; Argument[self]; Argument[0]; taint | -| 113 | Summary: ::lock; Argument[self]; ReturnValue; taint | -| 114 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | -| 115 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | -| 116 | Summary: ::as_path; Argument[self]; ReturnValue; value | -| 117 | Summary: ::buffer; Argument[self]; ReturnValue; taint | -| 118 | Summary: ::new; Argument[0]; ReturnValue; taint | -| 119 | Summary: ::next_line; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | -| 120 | Summary: ::next_segment; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | -| 121 | Summary: ::peek; Argument[self]; Argument[0].Reference; taint | -| 122 | Summary: ::try_read; Argument[self]; Argument[0].Reference; taint | -| 123 | Summary: ::try_read_buf; Argument[self]; Argument[0].Reference; taint | +| 1 | Source: <_ as warp::filter::Filter>::and_then; Argument[0].Parameter[0..7]; remote | +| 2 | Source: <_ as warp::filter::Filter>::map; Argument[0].Parameter[0..7]; remote | +| 3 | Source: <_ as warp::filter::Filter>::then; Argument[0].Parameter[0..7]; remote | +| 4 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 5 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 6 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 7 | Source: ::send_request; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 8 | Source: ::file_name; ReturnValue; file | +| 9 | Source: ::path; ReturnValue; file | +| 10 | Source: ::open; ReturnValue.Field[core::result::Result::Ok(0)]; file | +| 11 | Source: ::open; ReturnValue.Field[core::result::Result::Ok(0)]; file | +| 12 | Source: ::connect; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 13 | Source: ::connect_timeout; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 14 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 15 | Source: ::open; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 16 | Source: ::file_name; ReturnValue; file | +| 17 | Source: ::path; ReturnValue; file | +| 18 | Source: ::connect; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 19 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 20 | Source: reqwest::get; ReturnValue.Future.Field[core::result::Result::Ok(0)]; remote | +| 21 | Source: std::env::args; ReturnValue.Element; commandargs | +| 22 | Source: std::env::args_os; ReturnValue.Element; commandargs | +| 23 | Source: std::env::current_dir; ReturnValue.Field[core::result::Result::Ok(0)]; commandargs | +| 24 | Source: std::env::current_exe; ReturnValue.Field[core::result::Result::Ok(0)]; commandargs | +| 25 | Source: std::env::home_dir; ReturnValue.Field[core::option::Option::Some(0)]; commandargs | +| 26 | Source: std::env::var; ReturnValue.Field[core::result::Result::Ok(0)]; environment | +| 27 | Source: std::env::var_os; ReturnValue.Field[core::option::Option::Some(0)]; environment | +| 28 | Source: std::fs::read; ReturnValue.Field[core::result::Result::Ok(0)]; file | +| 29 | Source: std::fs::read; ReturnValue; file | +| 30 | Source: std::fs::read_link; ReturnValue.Field[core::result::Result::Ok(0)]; file | +| 31 | Source: std::fs::read_to_string; ReturnValue.Field[core::result::Result::Ok(0)]; file | +| 32 | Source: std::fs::read_to_string; ReturnValue; file | +| 33 | Source: std::io::stdio::stdin; ReturnValue; stdin | +| 34 | Source: tokio::fs::read::read; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 35 | Source: tokio::fs::read_link::read_link; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 36 | Source: tokio::fs::read_to_string::read_to_string; ReturnValue.Future.Field[core::result::Result::Ok(0)]; file | +| 37 | Source: tokio::io::stdin::stdin; ReturnValue; stdin | +| 38 | Summary: <_ as async_std::io::read::ReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | +| 39 | Summary: <_ as async_std::io::read::ReadExt>::read; Argument[self]; Argument[0].Reference; taint | +| 40 | Summary: <_ as core::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value | +| 41 | Summary: <_ as core::iter::traits::iterator::Iterator>::collect; Argument[self].Element; ReturnValue.Element; value | +| 42 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | +| 43 | Summary: <_ as futures_io::if_std::AsyncBufRead>::poll_fill_buf; Argument[self].Reference; ReturnValue.Field[core::task::poll::Poll::Ready(0)].Field[core::result::Result::Ok(0)]; taint | +| 44 | Summary: <_ as futures_util::io::AsyncBufReadExt>::fill_buf; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 45 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self].Reference; Argument[0].Reference; taint | +| 46 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_line; Argument[self]; Argument[0].Reference; taint | +| 47 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self].Reference; Argument[1].Reference; taint | +| 48 | Summary: <_ as futures_util::io::AsyncBufReadExt>::read_until; Argument[self]; Argument[1].Reference; taint | +| 49 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self].Reference; Argument[0].Reference; taint | +| 50 | Summary: <_ as futures_util::io::AsyncReadExt>::read; Argument[self]; Argument[0].Reference; taint | +| 51 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self].Reference; Argument[0].Reference; taint | +| 52 | Summary: <_ as futures_util::io::AsyncReadExt>::read_to_end; Argument[self]; Argument[0].Reference; taint | +| 53 | Summary: <_ as std::io::BufRead>::lines; Argument[self]; ReturnValue; taint | +| 54 | Summary: <_ as std::io::BufRead>::read_line; Argument[self]; Argument[0].Reference; taint | +| 55 | Summary: <_ as std::io::BufRead>::read_until; Argument[self]; Argument[1].Reference; taint | +| 56 | Summary: <_ as std::io::BufRead>::split; Argument[self]; ReturnValue; taint | +| 57 | Summary: <_ as std::io::Read>::bytes; Argument[self]; ReturnValue; taint | +| 58 | Summary: <_ as std::io::Read>::chain; Argument[0]; ReturnValue; taint | +| 59 | Summary: <_ as std::io::Read>::chain; Argument[self]; ReturnValue; taint | +| 60 | Summary: <_ as std::io::Read>::read; Argument[self]; Argument[0].Reference; taint | +| 61 | Summary: <_ as std::io::Read>::read_exact; Argument[self]; Argument[0].Reference; taint | +| 62 | Summary: <_ as std::io::Read>::read_to_end; Argument[self]; Argument[0].Reference; taint | +| 63 | Summary: <_ as std::io::Read>::read_to_string; Argument[self]; Argument[0].Reference; taint | +| 64 | Summary: <_ as std::io::Read>::take; Argument[self]; ReturnValue; taint | +| 65 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::fill_buf; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 66 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::lines; Argument[self]; ReturnValue; taint | +| 67 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::read_line; Argument[self]; Argument[0].Reference; taint | +| 68 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::read_until; Argument[self]; Argument[1].Reference; taint | +| 69 | Summary: <_ as tokio::io::util::async_buf_read_ext::AsyncBufReadExt>::split; Argument[self]; ReturnValue; taint | +| 70 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read; Argument[self]; Argument[0].Reference; taint | +| 71 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_buf; Argument[self]; Argument[0].Reference; taint | +| 72 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_exact; Argument[self]; Argument[0].Reference; taint | +| 73 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_f32; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 74 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_i16; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 75 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_i64_le; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 76 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_to_end; Argument[self]; Argument[0].Reference; taint | +| 77 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_to_string; Argument[self]; Argument[0].Reference; taint | +| 78 | Summary: <_ as tokio::io::util::async_read_ext::AsyncReadExt>::read_u8; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 79 | Summary: ::as_bytes; Argument[self]; ReturnValue; value | +| 80 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 81 | Summary: ::expect; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | +| 82 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | +| 83 | Summary: ::new; Argument[0].Reference; ReturnValue; value | +| 84 | Summary: ::new; Argument[0]; ReturnValue.Field[core::pin::Pin::__pointer]; value | +| 85 | Summary: ::new; Argument[0]; ReturnValue; value | +| 86 | Summary: ::expect; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 87 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 88 | Summary: ::as_bytes; Argument[self]; ReturnValue; value | +| 89 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 90 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 91 | Summary: ::connect; Argument[1]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 92 | Summary: ::new; Argument[0]; ReturnValue; taint | +| 93 | Summary: ::bytes; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 94 | Summary: ::chunk; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | +| 95 | Summary: ::text; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)]; taint | +| 96 | Summary: ::bytes; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 97 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 98 | Summary: ::text_with_charset; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 99 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | +| 100 | Summary: ::read; Argument[self]; Argument[0]; taint | +| 101 | Summary: ::read_to_end; Argument[self]; Argument[0].Reference; taint | +| 102 | Summary: ::read_to_end; Argument[self]; Argument[0]; taint | +| 103 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | +| 104 | Summary: ::read_to_string; Argument[self]; Argument[0]; taint | +| 105 | Summary: ::next; Argument[self]; ReturnValue.Field[core::option::Option::Some(0)].Field[core::result::Result::Ok(0)]; taint | +| 106 | Summary: ::fill_buf; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 107 | Summary: ::buffer; Argument[self]; ReturnValue; taint | +| 108 | Summary: ::new; Argument[0]; ReturnValue; taint | +| 109 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | +| 110 | Summary: ::read; Argument[self]; Argument[0]; taint | +| 111 | Summary: ::read_exact; Argument[self]; Argument[0].Reference; taint | +| 112 | Summary: ::read_exact; Argument[self]; Argument[0]; taint | +| 113 | Summary: ::read_to_end; Argument[self]; Argument[0].Reference; taint | +| 114 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | +| 115 | Summary: ::read_to_string; Argument[self]; Argument[0]; taint | +| 116 | Summary: ::lock; Argument[self]; ReturnValue; taint | +| 117 | Summary: ::read_to_string; Argument[self]; Argument[0].Reference; taint | +| 118 | Summary: ::read; Argument[self]; Argument[0].Reference; taint | +| 119 | Summary: ::as_path; Argument[self]; ReturnValue; value | +| 120 | Summary: ::buffer; Argument[self]; ReturnValue; taint | +| 121 | Summary: ::new; Argument[0]; ReturnValue; taint | +| 122 | Summary: ::next_line; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | +| 123 | Summary: ::next_segment; Argument[self]; ReturnValue.Future.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]; taint | +| 124 | Summary: ::peek; Argument[self]; Argument[0].Reference; taint | +| 125 | Summary: ::try_read; Argument[self]; Argument[0].Reference; taint | +| 126 | Summary: ::try_read_buf; Argument[self]; Argument[0].Reference; taint | edges -| test.rs:8:10:8:22 | ...::var | test.rs:8:10:8:30 | ...::var(...) | provenance | Src:MaD:23 | -| test.rs:9:10:9:25 | ...::var_os | test.rs:9:10:9:33 | ...::var_os(...) | provenance | Src:MaD:24 | +| test.rs:8:10:8:22 | ...::var | test.rs:8:10:8:30 | ...::var(...) | provenance | Src:MaD:26 | +| test.rs:9:10:9:25 | ...::var_os | test.rs:9:10:9:33 | ...::var_os(...) | provenance | Src:MaD:27 | | test.rs:11:9:11:12 | var1 | test.rs:14:10:14:13 | var1 | provenance | | -| test.rs:11:16:11:28 | ...::var | test.rs:11:16:11:36 | ...::var(...) [Ok] | provenance | Src:MaD:23 | -| test.rs:11:16:11:36 | ...::var(...) [Ok] | test.rs:11:16:11:59 | ... .expect(...) | provenance | MaD:83 | +| test.rs:11:16:11:28 | ...::var | test.rs:11:16:11:36 | ...::var(...) [Ok] | provenance | Src:MaD:26 | +| test.rs:11:16:11:36 | ...::var(...) [Ok] | test.rs:11:16:11:59 | ... .expect(...) | provenance | MaD:86 | | test.rs:11:16:11:59 | ... .expect(...) | test.rs:11:9:11:12 | var1 | provenance | | | test.rs:12:9:12:12 | var2 | test.rs:15:10:15:13 | var2 | provenance | | -| test.rs:12:16:12:31 | ...::var_os | test.rs:12:16:12:39 | ...::var_os(...) [Some] | provenance | Src:MaD:24 | -| test.rs:12:16:12:39 | ...::var_os(...) [Some] | test.rs:12:16:12:48 | ... .unwrap() | provenance | MaD:79 | +| test.rs:12:16:12:31 | ...::var_os | test.rs:12:16:12:39 | ...::var_os(...) [Some] | provenance | Src:MaD:27 | +| test.rs:12:16:12:39 | ...::var_os(...) [Some] | test.rs:12:16:12:48 | ... .unwrap() | provenance | MaD:82 | | test.rs:12:16:12:48 | ... .unwrap() | test.rs:12:9:12:12 | var2 | provenance | | | test.rs:29:9:29:12 | args [element] | test.rs:30:20:30:23 | args [element] | provenance | | | test.rs:29:9:29:12 | args [element] | test.rs:31:17:31:20 | args [element] | provenance | | -| test.rs:29:29:29:42 | ...::args | test.rs:29:29:29:44 | ...::args(...) [element] | provenance | Src:MaD:18 | -| test.rs:29:29:29:44 | ...::args(...) [element] | test.rs:29:29:29:54 | ... .collect() [element] | provenance | MaD:38 | +| test.rs:29:29:29:42 | ...::args | test.rs:29:29:29:44 | ...::args(...) [element] | provenance | Src:MaD:21 | +| test.rs:29:29:29:44 | ...::args(...) [element] | test.rs:29:29:29:54 | ... .collect() [element] | provenance | MaD:41 | | test.rs:29:29:29:54 | ... .collect() [element] | test.rs:29:9:29:12 | args [element] | provenance | | | test.rs:30:9:30:15 | my_path [&ref] | test.rs:36:10:36:16 | my_path | provenance | | | test.rs:30:19:30:26 | &... [&ref] | test.rs:30:9:30:15 | my_path [&ref] | provenance | | @@ -147,89 +150,89 @@ edges | test.rs:31:17:31:20 | args [element] | test.rs:31:17:31:23 | args[1] | provenance | | | test.rs:31:17:31:23 | args[1] | test.rs:31:16:31:23 | &... [&ref] | provenance | | | test.rs:32:9:32:12 | arg2 | test.rs:38:10:38:13 | arg2 | provenance | | -| test.rs:32:16:32:29 | ...::args | test.rs:32:16:32:31 | ...::args(...) [element] | provenance | Src:MaD:18 | -| test.rs:32:16:32:31 | ...::args(...) [element] | test.rs:32:16:32:38 | ... .nth(...) [Some] | provenance | MaD:39 | -| test.rs:32:16:32:38 | ... .nth(...) [Some] | test.rs:32:16:32:47 | ... .unwrap() | provenance | MaD:79 | +| test.rs:32:16:32:29 | ...::args | test.rs:32:16:32:31 | ...::args(...) [element] | provenance | Src:MaD:21 | +| test.rs:32:16:32:31 | ...::args(...) [element] | test.rs:32:16:32:38 | ... .nth(...) [Some] | provenance | MaD:42 | +| test.rs:32:16:32:38 | ... .nth(...) [Some] | test.rs:32:16:32:47 | ... .unwrap() | provenance | MaD:82 | | test.rs:32:16:32:47 | ... .unwrap() | test.rs:32:9:32:12 | arg2 | provenance | | | test.rs:33:9:33:12 | arg3 | test.rs:39:10:39:13 | arg3 | provenance | | -| test.rs:33:16:33:32 | ...::args_os | test.rs:33:16:33:34 | ...::args_os(...) [element] | provenance | Src:MaD:19 | -| test.rs:33:16:33:34 | ...::args_os(...) [element] | test.rs:33:16:33:41 | ... .nth(...) [Some] | provenance | MaD:39 | -| test.rs:33:16:33:41 | ... .nth(...) [Some] | test.rs:33:16:33:50 | ... .unwrap() | provenance | MaD:79 | +| test.rs:33:16:33:32 | ...::args_os | test.rs:33:16:33:34 | ...::args_os(...) [element] | provenance | Src:MaD:22 | +| test.rs:33:16:33:34 | ...::args_os(...) [element] | test.rs:33:16:33:41 | ... .nth(...) [Some] | provenance | MaD:42 | +| test.rs:33:16:33:41 | ... .nth(...) [Some] | test.rs:33:16:33:50 | ... .unwrap() | provenance | MaD:82 | | test.rs:33:16:33:50 | ... .unwrap() | test.rs:33:9:33:12 | arg3 | provenance | | | test.rs:34:9:34:12 | arg4 | test.rs:40:10:40:13 | arg4 | provenance | | -| test.rs:34:16:34:29 | ...::args | test.rs:34:16:34:31 | ...::args(...) [element] | provenance | Src:MaD:18 | -| test.rs:34:16:34:31 | ...::args(...) [element] | test.rs:34:16:34:38 | ... .nth(...) [Some] | provenance | MaD:39 | -| test.rs:34:16:34:38 | ... .nth(...) [Some] | test.rs:34:16:34:47 | ... .unwrap() | provenance | MaD:79 | -| test.rs:34:16:34:47 | ... .unwrap() | test.rs:34:16:34:64 | ... .parse() [Ok] | provenance | MaD:87 | -| test.rs:34:16:34:64 | ... .parse() [Ok] | test.rs:34:16:34:73 | ... .unwrap() | provenance | MaD:84 | +| test.rs:34:16:34:29 | ...::args | test.rs:34:16:34:31 | ...::args(...) [element] | provenance | Src:MaD:21 | +| test.rs:34:16:34:31 | ...::args(...) [element] | test.rs:34:16:34:38 | ... .nth(...) [Some] | provenance | MaD:42 | +| test.rs:34:16:34:38 | ... .nth(...) [Some] | test.rs:34:16:34:47 | ... .unwrap() | provenance | MaD:82 | +| test.rs:34:16:34:47 | ... .unwrap() | test.rs:34:16:34:64 | ... .parse() [Ok] | provenance | MaD:90 | +| test.rs:34:16:34:64 | ... .parse() [Ok] | test.rs:34:16:34:73 | ... .unwrap() | provenance | MaD:87 | | test.rs:34:16:34:73 | ... .unwrap() | test.rs:34:9:34:12 | arg4 | provenance | | | test.rs:42:9:42:11 | arg | test.rs:43:14:43:16 | arg | provenance | | -| test.rs:42:16:42:29 | ...::args | test.rs:42:16:42:31 | ...::args(...) [element] | provenance | Src:MaD:18 | +| test.rs:42:16:42:29 | ...::args | test.rs:42:16:42:31 | ...::args(...) [element] | provenance | Src:MaD:21 | | test.rs:42:16:42:31 | ...::args(...) [element] | test.rs:42:9:42:11 | arg | provenance | | | test.rs:46:9:46:11 | arg | test.rs:47:14:47:16 | arg | provenance | | -| test.rs:46:16:46:32 | ...::args_os | test.rs:46:16:46:34 | ...::args_os(...) [element] | provenance | Src:MaD:19 | +| test.rs:46:16:46:32 | ...::args_os | test.rs:46:16:46:34 | ...::args_os(...) [element] | provenance | Src:MaD:22 | | test.rs:46:16:46:34 | ...::args_os(...) [element] | test.rs:46:9:46:11 | arg | provenance | | | test.rs:52:9:52:11 | dir | test.rs:56:10:56:12 | dir | provenance | | -| test.rs:52:15:52:35 | ...::current_dir | test.rs:52:15:52:37 | ...::current_dir(...) [Ok] | provenance | Src:MaD:20 | -| test.rs:52:15:52:37 | ...::current_dir(...) [Ok] | test.rs:52:15:52:54 | ... .expect(...) | provenance | MaD:83 | +| test.rs:52:15:52:35 | ...::current_dir | test.rs:52:15:52:37 | ...::current_dir(...) [Ok] | provenance | Src:MaD:23 | +| test.rs:52:15:52:37 | ...::current_dir(...) [Ok] | test.rs:52:15:52:54 | ... .expect(...) | provenance | MaD:86 | | test.rs:52:15:52:54 | ... .expect(...) | test.rs:52:9:52:11 | dir | provenance | | | test.rs:53:9:53:11 | exe | test.rs:57:10:57:12 | exe | provenance | | -| test.rs:53:15:53:35 | ...::current_exe | test.rs:53:15:53:37 | ...::current_exe(...) [Ok] | provenance | Src:MaD:21 | -| test.rs:53:15:53:37 | ...::current_exe(...) [Ok] | test.rs:53:15:53:54 | ... .expect(...) | provenance | MaD:83 | +| test.rs:53:15:53:35 | ...::current_exe | test.rs:53:15:53:37 | ...::current_exe(...) [Ok] | provenance | Src:MaD:24 | +| test.rs:53:15:53:37 | ...::current_exe(...) [Ok] | test.rs:53:15:53:54 | ... .expect(...) | provenance | MaD:86 | | test.rs:53:15:53:54 | ... .expect(...) | test.rs:53:9:53:11 | exe | provenance | | | test.rs:54:9:54:12 | home | test.rs:58:10:58:13 | home | provenance | | -| test.rs:54:16:54:33 | ...::home_dir | test.rs:54:16:54:35 | ...::home_dir(...) [Some] | provenance | Src:MaD:22 | -| test.rs:54:16:54:35 | ...::home_dir(...) [Some] | test.rs:54:16:54:52 | ... .expect(...) | provenance | MaD:78 | +| test.rs:54:16:54:33 | ...::home_dir | test.rs:54:16:54:35 | ...::home_dir(...) [Some] | provenance | Src:MaD:25 | +| test.rs:54:16:54:35 | ...::home_dir(...) [Some] | test.rs:54:16:54:52 | ... .expect(...) | provenance | MaD:81 | | test.rs:54:16:54:52 | ... .expect(...) | test.rs:54:9:54:12 | home | provenance | | | test.rs:62:9:62:22 | remote_string1 | test.rs:63:10:63:23 | remote_string1 | provenance | | -| test.rs:62:26:62:47 | ...::get | test.rs:62:26:62:62 | ...::get(...) [Ok] | provenance | Src:MaD:16 | +| test.rs:62:26:62:47 | ...::get | test.rs:62:26:62:62 | ...::get(...) [Ok] | provenance | Src:MaD:19 | | test.rs:62:26:62:62 | ...::get(...) [Ok] | test.rs:62:26:62:63 | TryExpr | provenance | | -| test.rs:62:26:62:63 | TryExpr | test.rs:62:26:62:70 | ... .text() [Ok] | provenance | MaD:94 | +| test.rs:62:26:62:63 | TryExpr | test.rs:62:26:62:70 | ... .text() [Ok] | provenance | MaD:97 | | test.rs:62:26:62:70 | ... .text() [Ok] | test.rs:62:26:62:71 | TryExpr | provenance | | | test.rs:62:26:62:71 | TryExpr | test.rs:62:9:62:22 | remote_string1 | provenance | | | test.rs:65:9:65:22 | remote_string2 | test.rs:66:10:66:23 | remote_string2 | provenance | | -| test.rs:65:26:65:47 | ...::get | test.rs:65:26:65:62 | ...::get(...) [Ok] | provenance | Src:MaD:16 | -| test.rs:65:26:65:62 | ...::get(...) [Ok] | test.rs:65:26:65:71 | ... .unwrap() | provenance | MaD:84 | -| test.rs:65:26:65:71 | ... .unwrap() | test.rs:65:26:65:78 | ... .text() [Ok] | provenance | MaD:94 | -| test.rs:65:26:65:78 | ... .text() [Ok] | test.rs:65:26:65:87 | ... .unwrap() | provenance | MaD:84 | +| test.rs:65:26:65:47 | ...::get | test.rs:65:26:65:62 | ...::get(...) [Ok] | provenance | Src:MaD:19 | +| test.rs:65:26:65:62 | ...::get(...) [Ok] | test.rs:65:26:65:71 | ... .unwrap() | provenance | MaD:87 | +| test.rs:65:26:65:71 | ... .unwrap() | test.rs:65:26:65:78 | ... .text() [Ok] | provenance | MaD:97 | +| test.rs:65:26:65:78 | ... .text() [Ok] | test.rs:65:26:65:87 | ... .unwrap() | provenance | MaD:87 | | test.rs:65:26:65:87 | ... .unwrap() | test.rs:65:9:65:22 | remote_string2 | provenance | | | test.rs:68:9:68:22 | remote_string3 | test.rs:69:10:69:23 | remote_string3 | provenance | | -| test.rs:68:26:68:47 | ...::get | test.rs:68:26:68:62 | ...::get(...) [Ok] | provenance | Src:MaD:16 | -| test.rs:68:26:68:62 | ...::get(...) [Ok] | test.rs:68:26:68:71 | ... .unwrap() | provenance | MaD:84 | -| test.rs:68:26:68:71 | ... .unwrap() | test.rs:68:26:68:98 | ... .text_with_charset(...) [Ok] | provenance | MaD:95 | -| test.rs:68:26:68:98 | ... .text_with_charset(...) [Ok] | test.rs:68:26:68:107 | ... .unwrap() | provenance | MaD:84 | +| test.rs:68:26:68:47 | ...::get | test.rs:68:26:68:62 | ...::get(...) [Ok] | provenance | Src:MaD:19 | +| test.rs:68:26:68:62 | ...::get(...) [Ok] | test.rs:68:26:68:71 | ... .unwrap() | provenance | MaD:87 | +| test.rs:68:26:68:71 | ... .unwrap() | test.rs:68:26:68:98 | ... .text_with_charset(...) [Ok] | provenance | MaD:98 | +| test.rs:68:26:68:98 | ... .text_with_charset(...) [Ok] | test.rs:68:26:68:107 | ... .unwrap() | provenance | MaD:87 | | test.rs:68:26:68:107 | ... .unwrap() | test.rs:68:9:68:22 | remote_string3 | provenance | | | test.rs:71:9:71:22 | remote_string4 | test.rs:72:10:72:23 | remote_string4 | provenance | | -| test.rs:71:26:71:47 | ...::get | test.rs:71:26:71:62 | ...::get(...) [Ok] | provenance | Src:MaD:16 | -| test.rs:71:26:71:62 | ...::get(...) [Ok] | test.rs:71:26:71:71 | ... .unwrap() | provenance | MaD:84 | -| test.rs:71:26:71:71 | ... .unwrap() | test.rs:71:26:71:79 | ... .bytes() [Ok] | provenance | MaD:93 | -| test.rs:71:26:71:79 | ... .bytes() [Ok] | test.rs:71:26:71:88 | ... .unwrap() | provenance | MaD:84 | +| test.rs:71:26:71:47 | ...::get | test.rs:71:26:71:62 | ...::get(...) [Ok] | provenance | Src:MaD:19 | +| test.rs:71:26:71:62 | ...::get(...) [Ok] | test.rs:71:26:71:71 | ... .unwrap() | provenance | MaD:87 | +| test.rs:71:26:71:71 | ... .unwrap() | test.rs:71:26:71:79 | ... .bytes() [Ok] | provenance | MaD:96 | +| test.rs:71:26:71:79 | ... .bytes() [Ok] | test.rs:71:26:71:88 | ... .unwrap() | provenance | MaD:87 | | test.rs:71:26:71:88 | ... .unwrap() | test.rs:71:9:71:22 | remote_string4 | provenance | | | test.rs:74:9:74:22 | remote_string5 | test.rs:75:10:75:23 | remote_string5 | provenance | | -| test.rs:74:26:74:37 | ...::get | test.rs:74:26:74:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:17 | +| test.rs:74:26:74:37 | ...::get | test.rs:74:26:74:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:20 | | test.rs:74:26:74:52 | ...::get(...) [future, Ok] | test.rs:74:26:74:58 | await ... [Ok] | provenance | | | test.rs:74:26:74:58 | await ... [Ok] | test.rs:74:26:74:59 | TryExpr | provenance | | -| test.rs:74:26:74:59 | TryExpr | test.rs:74:26:74:66 | ... .text() [future, Ok] | provenance | MaD:92 | +| test.rs:74:26:74:59 | TryExpr | test.rs:74:26:74:66 | ... .text() [future, Ok] | provenance | MaD:95 | | test.rs:74:26:74:66 | ... .text() [future, Ok] | test.rs:74:26:74:72 | await ... [Ok] | provenance | | | test.rs:74:26:74:72 | await ... [Ok] | test.rs:74:26:74:73 | TryExpr | provenance | | | test.rs:74:26:74:73 | TryExpr | test.rs:74:9:74:22 | remote_string5 | provenance | | | test.rs:77:9:77:22 | remote_string6 | test.rs:78:10:78:23 | remote_string6 | provenance | | -| test.rs:77:26:77:37 | ...::get | test.rs:77:26:77:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:17 | +| test.rs:77:26:77:37 | ...::get | test.rs:77:26:77:52 | ...::get(...) [future, Ok] | provenance | Src:MaD:20 | | test.rs:77:26:77:52 | ...::get(...) [future, Ok] | test.rs:77:26:77:58 | await ... [Ok] | provenance | | | test.rs:77:26:77:58 | await ... [Ok] | test.rs:77:26:77:59 | TryExpr | provenance | | -| test.rs:77:26:77:59 | TryExpr | test.rs:77:26:77:67 | ... .bytes() [future, Ok] | provenance | MaD:90 | +| test.rs:77:26:77:59 | TryExpr | test.rs:77:26:77:67 | ... .bytes() [future, Ok] | provenance | MaD:93 | | test.rs:77:26:77:67 | ... .bytes() [future, Ok] | test.rs:77:26:77:73 | await ... [Ok] | provenance | | | test.rs:77:26:77:73 | await ... [Ok] | test.rs:77:26:77:74 | TryExpr | provenance | | | test.rs:77:26:77:74 | TryExpr | test.rs:77:9:77:22 | remote_string6 | provenance | | -| test.rs:80:9:80:20 | mut request1 | test.rs:81:10:81:25 | request1.chunk() [future, Ok, Some] | provenance | MaD:91 | -| test.rs:80:9:80:20 | mut request1 | test.rs:82:29:82:44 | request1.chunk() [future, Ok, Some] | provenance | MaD:91 | -| test.rs:80:24:80:35 | ...::get | test.rs:80:24:80:50 | ...::get(...) [future, Ok] | provenance | Src:MaD:17 | +| test.rs:80:9:80:20 | mut request1 | test.rs:81:10:81:25 | request1.chunk() [future, Ok, Some] | provenance | MaD:94 | +| test.rs:80:9:80:20 | mut request1 | test.rs:82:29:82:44 | request1.chunk() [future, Ok, Some] | provenance | MaD:94 | +| test.rs:80:24:80:35 | ...::get | test.rs:80:24:80:50 | ...::get(...) [future, Ok] | provenance | Src:MaD:20 | | test.rs:80:24:80:50 | ...::get(...) [future, Ok] | test.rs:80:24:80:56 | await ... [Ok] | provenance | | | test.rs:80:24:80:56 | await ... [Ok] | test.rs:80:24:80:57 | TryExpr | provenance | | | test.rs:80:24:80:57 | TryExpr | test.rs:80:9:80:20 | mut request1 | provenance | | | test.rs:81:10:81:25 | request1.chunk() [future, Ok, Some] | test.rs:81:10:81:31 | await ... [Ok, Some] | provenance | | | test.rs:81:10:81:31 | await ... [Ok, Some] | test.rs:81:10:81:32 | TryExpr [Some] | provenance | | -| test.rs:81:10:81:32 | TryExpr [Some] | test.rs:81:10:81:41 | ... .unwrap() | provenance | MaD:79 | +| test.rs:81:10:81:32 | TryExpr [Some] | test.rs:81:10:81:41 | ... .unwrap() | provenance | MaD:82 | | test.rs:82:15:82:25 | Some(...) [Some] | test.rs:82:20:82:24 | chunk | provenance | | | test.rs:82:20:82:24 | chunk | test.rs:83:14:83:18 | chunk | provenance | | | test.rs:82:29:82:44 | request1.chunk() [future, Ok, Some] | test.rs:82:29:82:50 | await ... [Ok, Some] | provenance | | @@ -240,129 +243,129 @@ edges | test.rs:114:24:114:51 | sender.send_request(...) [future, Ok] | test.rs:114:24:114:57 | await ... [Ok] | provenance | | | test.rs:114:24:114:57 | await ... [Ok] | test.rs:114:24:114:58 | TryExpr | provenance | | | test.rs:114:24:114:58 | TryExpr | test.rs:114:13:114:20 | response | provenance | | -| test.rs:114:31:114:42 | send_request | test.rs:114:24:114:51 | sender.send_request(...) [future, Ok] | provenance | Src:MaD:4 | +| test.rs:114:31:114:42 | send_request | test.rs:114:24:114:51 | sender.send_request(...) [future, Ok] | provenance | Src:MaD:7 | | test.rs:115:15:115:22 | response | test.rs:115:14:115:22 | &response | provenance | | | test.rs:121:9:121:20 | mut response | test.rs:122:11:122:18 | response | provenance | | | test.rs:121:24:121:51 | sender.send_request(...) [future, Ok] | test.rs:121:24:121:57 | await ... [Ok] | provenance | | | test.rs:121:24:121:57 | await ... [Ok] | test.rs:121:24:121:58 | TryExpr | provenance | | | test.rs:121:24:121:58 | TryExpr | test.rs:121:9:121:20 | mut response | provenance | | -| test.rs:121:31:121:42 | send_request | test.rs:121:24:121:51 | sender.send_request(...) [future, Ok] | provenance | Src:MaD:4 | +| test.rs:121:31:121:42 | send_request | test.rs:121:24:121:51 | sender.send_request(...) [future, Ok] | provenance | Src:MaD:7 | | test.rs:122:11:122:18 | response | test.rs:122:10:122:18 | &response | provenance | | -| test.rs:211:22:211:35 | ...::stdin | test.rs:211:22:211:37 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer | provenance | MaD:107 | -| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer [&ref] | provenance | MaD:106 | +| test.rs:211:22:211:35 | ...::stdin | test.rs:211:22:211:37 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer | provenance | MaD:110 | +| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:211:22:211:37 | ...::stdin(...) | test.rs:211:44:211:54 | [post] &mut buffer [&ref] | provenance | MaD:109 | | test.rs:211:44:211:54 | [post] &mut buffer | test.rs:212:15:212:20 | buffer | provenance | | | test.rs:211:44:211:54 | [post] &mut buffer [&ref] | test.rs:211:49:211:54 | [post] buffer | provenance | | | test.rs:211:49:211:54 | [post] buffer | test.rs:212:15:212:20 | buffer | provenance | | | test.rs:212:15:212:20 | buffer | test.rs:212:14:212:20 | &buffer | provenance | | -| test.rs:217:22:217:35 | ...::stdin | test.rs:217:22:217:37 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:217:22:217:37 | ...::stdin(...) | test.rs:217:51:217:61 | [post] &mut buffer [&ref] | provenance | MaD:59 | -| test.rs:217:22:217:37 | ...::stdin(...) | test.rs:217:51:217:61 | [post] &mut buffer [&ref] | provenance | MaD:110 | +| test.rs:217:22:217:35 | ...::stdin | test.rs:217:22:217:37 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:217:22:217:37 | ...::stdin(...) | test.rs:217:51:217:61 | [post] &mut buffer [&ref] | provenance | MaD:62 | +| test.rs:217:22:217:37 | ...::stdin(...) | test.rs:217:51:217:61 | [post] &mut buffer [&ref] | provenance | MaD:113 | | test.rs:217:51:217:61 | [post] &mut buffer [&ref] | test.rs:217:56:217:61 | [post] buffer | provenance | | | test.rs:217:56:217:61 | [post] buffer | test.rs:218:15:218:20 | buffer | provenance | | | test.rs:218:15:218:20 | buffer | test.rs:218:14:218:20 | &buffer | provenance | | -| test.rs:223:22:223:35 | ...::stdin | test.rs:223:22:223:37 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer | provenance | MaD:112 | -| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer [&ref] | provenance | MaD:60 | -| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer [&ref] | provenance | MaD:111 | +| test.rs:223:22:223:35 | ...::stdin | test.rs:223:22:223:37 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer | provenance | MaD:115 | +| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer [&ref] | provenance | MaD:63 | +| test.rs:223:22:223:37 | ...::stdin(...) | test.rs:223:54:223:64 | [post] &mut buffer [&ref] | provenance | MaD:114 | | test.rs:223:54:223:64 | [post] &mut buffer | test.rs:224:15:224:20 | buffer | provenance | | | test.rs:223:54:223:64 | [post] &mut buffer [&ref] | test.rs:223:59:223:64 | [post] buffer | provenance | | | test.rs:223:59:223:64 | [post] buffer | test.rs:224:15:224:20 | buffer | provenance | | | test.rs:224:15:224:20 | buffer | test.rs:224:14:224:20 | &buffer | provenance | | -| test.rs:229:22:229:35 | ...::stdin | test.rs:229:22:229:37 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:229:22:229:37 | ...::stdin(...) | test.rs:229:22:229:44 | ... .lock() | provenance | MaD:113 | -| test.rs:229:22:229:44 | ... .lock() | test.rs:229:61:229:71 | [post] &mut buffer [&ref] | provenance | MaD:60 | -| test.rs:229:22:229:44 | ... .lock() | test.rs:229:61:229:71 | [post] &mut buffer [&ref] | provenance | MaD:114 | +| test.rs:229:22:229:35 | ...::stdin | test.rs:229:22:229:37 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:229:22:229:37 | ...::stdin(...) | test.rs:229:22:229:44 | ... .lock() | provenance | MaD:116 | +| test.rs:229:22:229:44 | ... .lock() | test.rs:229:61:229:71 | [post] &mut buffer [&ref] | provenance | MaD:63 | +| test.rs:229:22:229:44 | ... .lock() | test.rs:229:61:229:71 | [post] &mut buffer [&ref] | provenance | MaD:117 | | test.rs:229:61:229:71 | [post] &mut buffer [&ref] | test.rs:229:66:229:71 | [post] buffer | provenance | | | test.rs:229:66:229:71 | [post] buffer | test.rs:230:15:230:20 | buffer | provenance | | | test.rs:230:15:230:20 | buffer | test.rs:230:14:230:20 | &buffer | provenance | | -| test.rs:235:9:235:22 | ...::stdin | test.rs:235:9:235:24 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer | provenance | MaD:109 | -| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer [&ref] | provenance | MaD:58 | -| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer [&ref] | provenance | MaD:108 | +| test.rs:235:9:235:22 | ...::stdin | test.rs:235:9:235:24 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer | provenance | MaD:112 | +| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer [&ref] | provenance | MaD:61 | +| test.rs:235:9:235:24 | ...::stdin(...) | test.rs:235:37:235:47 | [post] &mut buffer [&ref] | provenance | MaD:111 | | test.rs:235:37:235:47 | [post] &mut buffer | test.rs:236:15:236:20 | buffer | provenance | | | test.rs:235:37:235:47 | [post] &mut buffer [&ref] | test.rs:235:42:235:47 | [post] buffer | provenance | | | test.rs:235:42:235:47 | [post] buffer | test.rs:236:15:236:20 | buffer | provenance | | | test.rs:236:15:236:20 | buffer | test.rs:236:14:236:20 | &buffer | provenance | | -| test.rs:239:17:239:30 | ...::stdin | test.rs:239:17:239:32 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:239:17:239:32 | ...::stdin(...) | test.rs:239:17:239:40 | ... .bytes() | provenance | MaD:54 | +| test.rs:239:17:239:30 | ...::stdin | test.rs:239:17:239:32 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:239:17:239:32 | ...::stdin(...) | test.rs:239:17:239:40 | ... .bytes() | provenance | MaD:57 | | test.rs:239:17:239:40 | ... .bytes() | test.rs:240:14:240:17 | byte | provenance | | -| test.rs:246:13:246:22 | mut reader | test.rs:247:20:247:36 | reader.fill_buf() [Ok] | provenance | MaD:103 | +| test.rs:246:13:246:22 | mut reader | test.rs:247:20:247:36 | reader.fill_buf() [Ok] | provenance | MaD:106 | | test.rs:246:26:246:66 | ...::new(...) | test.rs:246:13:246:22 | mut reader | provenance | | -| test.rs:246:50:246:63 | ...::stdin | test.rs:246:50:246:65 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:246:50:246:65 | ...::stdin(...) | test.rs:246:26:246:66 | ...::new(...) | provenance | MaD:105 | +| test.rs:246:50:246:63 | ...::stdin | test.rs:246:50:246:65 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:246:50:246:65 | ...::stdin(...) | test.rs:246:26:246:66 | ...::new(...) | provenance | MaD:108 | | test.rs:247:13:247:16 | data | test.rs:248:15:248:18 | data | provenance | | | test.rs:247:20:247:36 | reader.fill_buf() [Ok] | test.rs:247:20:247:37 | TryExpr | provenance | | | test.rs:247:20:247:37 | TryExpr | test.rs:247:13:247:16 | data | provenance | | | test.rs:248:15:248:18 | data | test.rs:248:14:248:18 | &data | provenance | | -| test.rs:252:13:252:18 | reader | test.rs:253:20:253:34 | reader.buffer() | provenance | MaD:104 | +| test.rs:252:13:252:18 | reader | test.rs:253:20:253:34 | reader.buffer() | provenance | MaD:107 | | test.rs:252:22:252:62 | ...::new(...) | test.rs:252:13:252:18 | reader | provenance | | -| test.rs:252:46:252:59 | ...::stdin | test.rs:252:46:252:61 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:252:46:252:61 | ...::stdin(...) | test.rs:252:22:252:62 | ...::new(...) | provenance | MaD:105 | +| test.rs:252:46:252:59 | ...::stdin | test.rs:252:46:252:61 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:252:46:252:61 | ...::stdin(...) | test.rs:252:22:252:62 | ...::new(...) | provenance | MaD:108 | | test.rs:253:13:253:16 | data | test.rs:254:15:254:18 | data | provenance | | | test.rs:253:20:253:34 | reader.buffer() | test.rs:253:13:253:16 | data | provenance | | | test.rs:254:15:254:18 | data | test.rs:254:14:254:18 | &data | provenance | | -| test.rs:259:13:259:22 | mut reader | test.rs:260:26:260:36 | [post] &mut buffer [&ref] | provenance | MaD:51 | +| test.rs:259:13:259:22 | mut reader | test.rs:260:26:260:36 | [post] &mut buffer [&ref] | provenance | MaD:54 | | test.rs:259:26:259:66 | ...::new(...) | test.rs:259:13:259:22 | mut reader | provenance | | -| test.rs:259:50:259:63 | ...::stdin | test.rs:259:50:259:65 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:259:50:259:65 | ...::stdin(...) | test.rs:259:26:259:66 | ...::new(...) | provenance | MaD:105 | +| test.rs:259:50:259:63 | ...::stdin | test.rs:259:50:259:65 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:259:50:259:65 | ...::stdin(...) | test.rs:259:26:259:66 | ...::new(...) | provenance | MaD:108 | | test.rs:260:26:260:36 | [post] &mut buffer [&ref] | test.rs:260:31:260:36 | [post] buffer | provenance | | | test.rs:260:31:260:36 | [post] buffer | test.rs:261:15:261:20 | buffer | provenance | | | test.rs:261:15:261:20 | buffer | test.rs:261:14:261:20 | &buffer | provenance | | -| test.rs:266:13:266:22 | mut reader | test.rs:267:33:267:43 | [post] &mut buffer [&ref] | provenance | MaD:52 | +| test.rs:266:13:266:22 | mut reader | test.rs:267:33:267:43 | [post] &mut buffer [&ref] | provenance | MaD:55 | | test.rs:266:26:266:66 | ...::new(...) | test.rs:266:13:266:22 | mut reader | provenance | | -| test.rs:266:50:266:63 | ...::stdin | test.rs:266:50:266:65 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:266:50:266:65 | ...::stdin(...) | test.rs:266:26:266:66 | ...::new(...) | provenance | MaD:105 | +| test.rs:266:50:266:63 | ...::stdin | test.rs:266:50:266:65 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:266:50:266:65 | ...::stdin(...) | test.rs:266:26:266:66 | ...::new(...) | provenance | MaD:108 | | test.rs:267:33:267:43 | [post] &mut buffer [&ref] | test.rs:267:38:267:43 | [post] buffer | provenance | | | test.rs:267:38:267:43 | [post] buffer | test.rs:268:15:268:20 | buffer | provenance | | | test.rs:267:38:267:43 | [post] buffer | test.rs:269:14:269:22 | buffer[0] | provenance | | | test.rs:268:15:268:20 | buffer | test.rs:268:14:268:20 | &buffer | provenance | | -| test.rs:273:13:273:28 | mut reader_split | test.rs:274:14:274:32 | reader_split.next() [Some, Ok] | provenance | MaD:102 | -| test.rs:273:13:273:28 | mut reader_split | test.rs:275:33:275:51 | reader_split.next() [Some, Ok] | provenance | MaD:102 | -| test.rs:273:32:273:72 | ...::new(...) | test.rs:273:32:273:84 | ... .split(...) | provenance | MaD:53 | +| test.rs:273:13:273:28 | mut reader_split | test.rs:274:14:274:32 | reader_split.next() [Some, Ok] | provenance | MaD:105 | +| test.rs:273:13:273:28 | mut reader_split | test.rs:275:33:275:51 | reader_split.next() [Some, Ok] | provenance | MaD:105 | +| test.rs:273:32:273:72 | ...::new(...) | test.rs:273:32:273:84 | ... .split(...) | provenance | MaD:56 | | test.rs:273:32:273:84 | ... .split(...) | test.rs:273:13:273:28 | mut reader_split | provenance | | -| test.rs:273:56:273:69 | ...::stdin | test.rs:273:56:273:71 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:273:56:273:71 | ...::stdin(...) | test.rs:273:32:273:72 | ...::new(...) | provenance | MaD:105 | -| test.rs:274:14:274:32 | reader_split.next() [Some, Ok] | test.rs:274:14:274:41 | ... .unwrap() [Ok] | provenance | MaD:79 | -| test.rs:274:14:274:41 | ... .unwrap() [Ok] | test.rs:274:14:274:50 | ... .unwrap() | provenance | MaD:84 | +| test.rs:273:56:273:69 | ...::stdin | test.rs:273:56:273:71 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:273:56:273:71 | ...::stdin(...) | test.rs:273:32:273:72 | ...::new(...) | provenance | MaD:108 | +| test.rs:274:14:274:32 | reader_split.next() [Some, Ok] | test.rs:274:14:274:41 | ... .unwrap() [Ok] | provenance | MaD:82 | +| test.rs:274:14:274:41 | ... .unwrap() [Ok] | test.rs:274:14:274:50 | ... .unwrap() | provenance | MaD:87 | | test.rs:275:19:275:29 | Some(...) [Some, Ok] | test.rs:275:24:275:28 | chunk [Ok] | provenance | | -| test.rs:275:24:275:28 | chunk [Ok] | test.rs:276:18:276:31 | chunk.unwrap() | provenance | MaD:84 | +| test.rs:275:24:275:28 | chunk [Ok] | test.rs:276:18:276:31 | chunk.unwrap() | provenance | MaD:87 | | test.rs:275:33:275:51 | reader_split.next() [Some, Ok] | test.rs:275:19:275:29 | Some(...) [Some, Ok] | provenance | | -| test.rs:281:13:281:18 | reader | test.rs:282:21:282:34 | reader.lines() | provenance | MaD:50 | +| test.rs:281:13:281:18 | reader | test.rs:282:21:282:34 | reader.lines() | provenance | MaD:53 | | test.rs:281:22:281:62 | ...::new(...) | test.rs:281:13:281:18 | reader | provenance | | -| test.rs:281:46:281:59 | ...::stdin | test.rs:281:46:281:61 | ...::stdin(...) | provenance | Src:MaD:30 MaD:30 | -| test.rs:281:46:281:61 | ...::stdin(...) | test.rs:281:22:281:62 | ...::new(...) | provenance | MaD:105 | +| test.rs:281:46:281:59 | ...::stdin | test.rs:281:46:281:61 | ...::stdin(...) | provenance | Src:MaD:33 MaD:33 | +| test.rs:281:46:281:61 | ...::stdin(...) | test.rs:281:22:281:62 | ...::new(...) | provenance | MaD:108 | | test.rs:282:21:282:34 | reader.lines() | test.rs:283:18:283:21 | line | provenance | | -| test.rs:309:13:309:21 | mut stdin | test.rs:311:33:311:43 | [post] &mut buffer [&ref] | provenance | MaD:67 | -| test.rs:309:25:309:40 | ...::stdin | test.rs:309:25:309:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:309:13:309:21 | mut stdin | test.rs:311:33:311:43 | [post] &mut buffer [&ref] | provenance | MaD:70 | +| test.rs:309:25:309:40 | ...::stdin | test.rs:309:25:309:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:309:25:309:42 | ...::stdin(...) | test.rs:309:13:309:21 | mut stdin | provenance | | | test.rs:311:33:311:43 | [post] &mut buffer [&ref] | test.rs:311:38:311:43 | [post] buffer | provenance | | | test.rs:311:38:311:43 | [post] buffer | test.rs:312:15:312:20 | buffer | provenance | | | test.rs:312:15:312:20 | buffer | test.rs:312:14:312:20 | &buffer | provenance | | -| test.rs:316:13:316:21 | mut stdin | test.rs:318:40:318:50 | [post] &mut buffer [&ref] | provenance | MaD:73 | -| test.rs:316:25:316:40 | ...::stdin | test.rs:316:25:316:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:316:13:316:21 | mut stdin | test.rs:318:40:318:50 | [post] &mut buffer [&ref] | provenance | MaD:76 | +| test.rs:316:25:316:40 | ...::stdin | test.rs:316:25:316:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:316:25:316:42 | ...::stdin(...) | test.rs:316:13:316:21 | mut stdin | provenance | | | test.rs:318:40:318:50 | [post] &mut buffer [&ref] | test.rs:318:45:318:50 | [post] buffer | provenance | | | test.rs:318:45:318:50 | [post] buffer | test.rs:319:15:319:20 | buffer | provenance | | | test.rs:319:15:319:20 | buffer | test.rs:319:14:319:20 | &buffer | provenance | | -| test.rs:323:13:323:21 | mut stdin | test.rs:325:43:325:53 | [post] &mut buffer [&ref] | provenance | MaD:74 | -| test.rs:323:25:323:40 | ...::stdin | test.rs:323:25:323:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:323:13:323:21 | mut stdin | test.rs:325:43:325:53 | [post] &mut buffer [&ref] | provenance | MaD:77 | +| test.rs:323:25:323:40 | ...::stdin | test.rs:323:25:323:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:323:25:323:42 | ...::stdin(...) | test.rs:323:13:323:21 | mut stdin | provenance | | | test.rs:325:43:325:53 | [post] &mut buffer [&ref] | test.rs:325:48:325:53 | [post] buffer | provenance | | | test.rs:325:48:325:53 | [post] buffer | test.rs:326:15:326:20 | buffer | provenance | | | test.rs:326:15:326:20 | buffer | test.rs:326:14:326:20 | &buffer | provenance | | -| test.rs:330:13:330:21 | mut stdin | test.rs:332:26:332:36 | [post] &mut buffer [&ref] | provenance | MaD:69 | -| test.rs:330:25:330:40 | ...::stdin | test.rs:330:25:330:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:330:13:330:21 | mut stdin | test.rs:332:26:332:36 | [post] &mut buffer [&ref] | provenance | MaD:72 | +| test.rs:330:25:330:40 | ...::stdin | test.rs:330:25:330:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:330:25:330:42 | ...::stdin(...) | test.rs:330:13:330:21 | mut stdin | provenance | | | test.rs:332:26:332:36 | [post] &mut buffer [&ref] | test.rs:332:31:332:36 | [post] buffer | provenance | | | test.rs:332:31:332:36 | [post] buffer | test.rs:333:15:333:20 | buffer | provenance | | | test.rs:333:15:333:20 | buffer | test.rs:333:14:333:20 | &buffer | provenance | | -| test.rs:337:13:337:21 | mut stdin | test.rs:338:18:338:32 | stdin.read_u8() [future, Ok] | provenance | MaD:75 | -| test.rs:337:13:337:21 | mut stdin | test.rs:339:18:339:33 | stdin.read_i16() [future, Ok] | provenance | MaD:71 | -| test.rs:337:13:337:21 | mut stdin | test.rs:340:18:340:33 | stdin.read_f32() [future, Ok] | provenance | MaD:70 | -| test.rs:337:13:337:21 | mut stdin | test.rs:341:18:341:36 | stdin.read_i64_le() [future, Ok] | provenance | MaD:72 | -| test.rs:337:25:337:40 | ...::stdin | test.rs:337:25:337:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:337:13:337:21 | mut stdin | test.rs:338:18:338:32 | stdin.read_u8() [future, Ok] | provenance | MaD:78 | +| test.rs:337:13:337:21 | mut stdin | test.rs:339:18:339:33 | stdin.read_i16() [future, Ok] | provenance | MaD:74 | +| test.rs:337:13:337:21 | mut stdin | test.rs:340:18:340:33 | stdin.read_f32() [future, Ok] | provenance | MaD:73 | +| test.rs:337:13:337:21 | mut stdin | test.rs:341:18:341:36 | stdin.read_i64_le() [future, Ok] | provenance | MaD:75 | +| test.rs:337:25:337:40 | ...::stdin | test.rs:337:25:337:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:337:25:337:42 | ...::stdin(...) | test.rs:337:13:337:21 | mut stdin | provenance | | | test.rs:338:13:338:14 | v1 | test.rs:342:14:342:15 | v1 | provenance | | | test.rs:338:18:338:32 | stdin.read_u8() [future, Ok] | test.rs:338:18:338:38 | await ... [Ok] | provenance | | @@ -380,150 +383,150 @@ edges | test.rs:341:18:341:36 | stdin.read_i64_le() [future, Ok] | test.rs:341:18:341:42 | await ... [Ok] | provenance | | | test.rs:341:18:341:42 | await ... [Ok] | test.rs:341:18:341:43 | TryExpr | provenance | | | test.rs:341:18:341:43 | TryExpr | test.rs:341:13:341:14 | v4 | provenance | | -| test.rs:349:13:349:21 | mut stdin | test.rs:351:24:351:34 | [post] &mut buffer [&ref] | provenance | MaD:68 | -| test.rs:349:25:349:40 | ...::stdin | test.rs:349:25:349:42 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | +| test.rs:349:13:349:21 | mut stdin | test.rs:351:24:351:34 | [post] &mut buffer [&ref] | provenance | MaD:71 | +| test.rs:349:25:349:40 | ...::stdin | test.rs:349:25:349:42 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | | test.rs:349:25:349:42 | ...::stdin(...) | test.rs:349:13:349:21 | mut stdin | provenance | | | test.rs:351:24:351:34 | [post] &mut buffer [&ref] | test.rs:351:29:351:34 | [post] buffer | provenance | | | test.rs:351:29:351:34 | [post] buffer | test.rs:352:15:352:20 | buffer | provenance | | | test.rs:352:15:352:20 | buffer | test.rs:352:14:352:20 | &buffer | provenance | | -| test.rs:358:13:358:22 | mut reader | test.rs:359:20:359:36 | reader.fill_buf() [future, Ok] | provenance | MaD:62 | +| test.rs:358:13:358:22 | mut reader | test.rs:359:20:359:36 | reader.fill_buf() [future, Ok] | provenance | MaD:65 | | test.rs:358:26:358:70 | ...::new(...) | test.rs:358:13:358:22 | mut reader | provenance | | -| test.rs:358:52:358:67 | ...::stdin | test.rs:358:52:358:69 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:358:52:358:69 | ...::stdin(...) | test.rs:358:26:358:70 | ...::new(...) | provenance | MaD:118 | +| test.rs:358:52:358:67 | ...::stdin | test.rs:358:52:358:69 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:358:52:358:69 | ...::stdin(...) | test.rs:358:26:358:70 | ...::new(...) | provenance | MaD:121 | | test.rs:359:13:359:16 | data | test.rs:360:15:360:18 | data | provenance | | | test.rs:359:20:359:36 | reader.fill_buf() [future, Ok] | test.rs:359:20:359:42 | await ... [Ok] | provenance | | | test.rs:359:20:359:42 | await ... [Ok] | test.rs:359:20:359:43 | TryExpr | provenance | | | test.rs:359:20:359:43 | TryExpr | test.rs:359:13:359:16 | data | provenance | | | test.rs:360:15:360:18 | data | test.rs:360:14:360:18 | &data | provenance | | -| test.rs:364:13:364:18 | reader | test.rs:365:20:365:34 | reader.buffer() | provenance | MaD:117 | +| test.rs:364:13:364:18 | reader | test.rs:365:20:365:34 | reader.buffer() | provenance | MaD:120 | | test.rs:364:22:364:66 | ...::new(...) | test.rs:364:13:364:18 | reader | provenance | | -| test.rs:364:48:364:63 | ...::stdin | test.rs:364:48:364:65 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:364:48:364:65 | ...::stdin(...) | test.rs:364:22:364:66 | ...::new(...) | provenance | MaD:118 | +| test.rs:364:48:364:63 | ...::stdin | test.rs:364:48:364:65 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:364:48:364:65 | ...::stdin(...) | test.rs:364:22:364:66 | ...::new(...) | provenance | MaD:121 | | test.rs:365:13:365:16 | data | test.rs:366:15:366:18 | data | provenance | | | test.rs:365:20:365:34 | reader.buffer() | test.rs:365:13:365:16 | data | provenance | | | test.rs:366:15:366:18 | data | test.rs:366:14:366:18 | &data | provenance | | -| test.rs:371:13:371:22 | mut reader | test.rs:372:26:372:36 | [post] &mut buffer [&ref] | provenance | MaD:64 | +| test.rs:371:13:371:22 | mut reader | test.rs:372:26:372:36 | [post] &mut buffer [&ref] | provenance | MaD:67 | | test.rs:371:26:371:70 | ...::new(...) | test.rs:371:13:371:22 | mut reader | provenance | | -| test.rs:371:52:371:67 | ...::stdin | test.rs:371:52:371:69 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:371:52:371:69 | ...::stdin(...) | test.rs:371:26:371:70 | ...::new(...) | provenance | MaD:118 | +| test.rs:371:52:371:67 | ...::stdin | test.rs:371:52:371:69 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:371:52:371:69 | ...::stdin(...) | test.rs:371:26:371:70 | ...::new(...) | provenance | MaD:121 | | test.rs:372:26:372:36 | [post] &mut buffer [&ref] | test.rs:372:31:372:36 | [post] buffer | provenance | | | test.rs:372:31:372:36 | [post] buffer | test.rs:373:15:373:20 | buffer | provenance | | | test.rs:373:15:373:20 | buffer | test.rs:373:14:373:20 | &buffer | provenance | | -| test.rs:378:13:378:22 | mut reader | test.rs:379:33:379:43 | [post] &mut buffer [&ref] | provenance | MaD:65 | +| test.rs:378:13:378:22 | mut reader | test.rs:379:33:379:43 | [post] &mut buffer [&ref] | provenance | MaD:68 | | test.rs:378:26:378:70 | ...::new(...) | test.rs:378:13:378:22 | mut reader | provenance | | -| test.rs:378:52:378:67 | ...::stdin | test.rs:378:52:378:69 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:378:52:378:69 | ...::stdin(...) | test.rs:378:26:378:70 | ...::new(...) | provenance | MaD:118 | +| test.rs:378:52:378:67 | ...::stdin | test.rs:378:52:378:69 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:378:52:378:69 | ...::stdin(...) | test.rs:378:26:378:70 | ...::new(...) | provenance | MaD:121 | | test.rs:379:33:379:43 | [post] &mut buffer [&ref] | test.rs:379:38:379:43 | [post] buffer | provenance | | | test.rs:379:38:379:43 | [post] buffer | test.rs:380:15:380:20 | buffer | provenance | | | test.rs:379:38:379:43 | [post] buffer | test.rs:381:14:381:22 | buffer[0] | provenance | | | test.rs:380:15:380:20 | buffer | test.rs:380:14:380:20 | &buffer | provenance | | -| test.rs:385:13:385:28 | mut reader_split | test.rs:386:14:386:40 | reader_split.next_segment() [future, Ok, Some] | provenance | MaD:120 | -| test.rs:385:13:385:28 | mut reader_split | test.rs:387:33:387:59 | reader_split.next_segment() [future, Ok, Some] | provenance | MaD:120 | -| test.rs:385:32:385:76 | ...::new(...) | test.rs:385:32:385:88 | ... .split(...) | provenance | MaD:66 | +| test.rs:385:13:385:28 | mut reader_split | test.rs:386:14:386:40 | reader_split.next_segment() [future, Ok, Some] | provenance | MaD:123 | +| test.rs:385:13:385:28 | mut reader_split | test.rs:387:33:387:59 | reader_split.next_segment() [future, Ok, Some] | provenance | MaD:123 | +| test.rs:385:32:385:76 | ...::new(...) | test.rs:385:32:385:88 | ... .split(...) | provenance | MaD:69 | | test.rs:385:32:385:88 | ... .split(...) | test.rs:385:13:385:28 | mut reader_split | provenance | | -| test.rs:385:58:385:73 | ...::stdin | test.rs:385:58:385:75 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:385:58:385:75 | ...::stdin(...) | test.rs:385:32:385:76 | ...::new(...) | provenance | MaD:118 | +| test.rs:385:58:385:73 | ...::stdin | test.rs:385:58:385:75 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:385:58:385:75 | ...::stdin(...) | test.rs:385:32:385:76 | ...::new(...) | provenance | MaD:121 | | test.rs:386:14:386:40 | reader_split.next_segment() [future, Ok, Some] | test.rs:386:14:386:46 | await ... [Ok, Some] | provenance | | | test.rs:386:14:386:46 | await ... [Ok, Some] | test.rs:386:14:386:47 | TryExpr [Some] | provenance | | -| test.rs:386:14:386:47 | TryExpr [Some] | test.rs:386:14:386:56 | ... .unwrap() | provenance | MaD:79 | +| test.rs:386:14:386:47 | TryExpr [Some] | test.rs:386:14:386:56 | ... .unwrap() | provenance | MaD:82 | | test.rs:387:19:387:29 | Some(...) [Some] | test.rs:387:24:387:28 | chunk | provenance | | | test.rs:387:24:387:28 | chunk | test.rs:388:18:388:22 | chunk | provenance | | | test.rs:387:33:387:59 | reader_split.next_segment() [future, Ok, Some] | test.rs:387:33:387:65 | await ... [Ok, Some] | provenance | | | test.rs:387:33:387:65 | await ... [Ok, Some] | test.rs:387:33:387:66 | TryExpr [Some] | provenance | | | test.rs:387:33:387:66 | TryExpr [Some] | test.rs:387:19:387:29 | Some(...) [Some] | provenance | | -| test.rs:393:13:393:18 | reader | test.rs:394:25:394:38 | reader.lines() | provenance | MaD:63 | +| test.rs:393:13:393:18 | reader | test.rs:394:25:394:38 | reader.lines() | provenance | MaD:66 | | test.rs:393:22:393:66 | ...::new(...) | test.rs:393:13:393:18 | reader | provenance | | -| test.rs:393:48:393:63 | ...::stdin | test.rs:393:48:393:65 | ...::stdin(...) | provenance | Src:MaD:34 MaD:34 | -| test.rs:393:48:393:65 | ...::stdin(...) | test.rs:393:22:393:66 | ...::new(...) | provenance | MaD:118 | -| test.rs:394:13:394:21 | mut lines | test.rs:395:14:395:30 | lines.next_line() [future, Ok, Some] | provenance | MaD:119 | -| test.rs:394:13:394:21 | mut lines | test.rs:396:32:396:48 | lines.next_line() [future, Ok, Some] | provenance | MaD:119 | +| test.rs:393:48:393:63 | ...::stdin | test.rs:393:48:393:65 | ...::stdin(...) | provenance | Src:MaD:37 MaD:37 | +| test.rs:393:48:393:65 | ...::stdin(...) | test.rs:393:22:393:66 | ...::new(...) | provenance | MaD:121 | +| test.rs:394:13:394:21 | mut lines | test.rs:395:14:395:30 | lines.next_line() [future, Ok, Some] | provenance | MaD:122 | +| test.rs:394:13:394:21 | mut lines | test.rs:396:32:396:48 | lines.next_line() [future, Ok, Some] | provenance | MaD:122 | | test.rs:394:25:394:38 | reader.lines() | test.rs:394:13:394:21 | mut lines | provenance | | | test.rs:395:14:395:30 | lines.next_line() [future, Ok, Some] | test.rs:395:14:395:36 | await ... [Ok, Some] | provenance | | | test.rs:395:14:395:36 | await ... [Ok, Some] | test.rs:395:14:395:37 | TryExpr [Some] | provenance | | -| test.rs:395:14:395:37 | TryExpr [Some] | test.rs:395:14:395:46 | ... .unwrap() | provenance | MaD:79 | +| test.rs:395:14:395:37 | TryExpr [Some] | test.rs:395:14:395:46 | ... .unwrap() | provenance | MaD:82 | | test.rs:396:19:396:28 | Some(...) [Some] | test.rs:396:24:396:27 | line | provenance | | | test.rs:396:24:396:27 | line | test.rs:397:18:397:21 | line | provenance | | | test.rs:396:32:396:48 | lines.next_line() [future, Ok, Some] | test.rs:396:32:396:54 | await ... [Ok, Some] | provenance | | | test.rs:396:32:396:54 | await ... [Ok, Some] | test.rs:396:32:396:55 | TryExpr [Some] | provenance | | | test.rs:396:32:396:55 | TryExpr [Some] | test.rs:396:19:396:28 | Some(...) [Some] | provenance | | | test.rs:408:13:408:18 | buffer | test.rs:409:14:409:19 | buffer | provenance | | -| test.rs:408:31:408:43 | ...::read | test.rs:408:31:408:43 | ...::read [Ok] | provenance | Src:MaD:25 | -| test.rs:408:31:408:43 | ...::read | test.rs:408:31:408:55 | ...::read(...) [Ok] | provenance | Src:MaD:25 | -| test.rs:408:31:408:43 | ...::read [Ok] | test.rs:408:31:408:55 | ...::read(...) [Ok] | provenance | MaD:26 | +| test.rs:408:31:408:43 | ...::read | test.rs:408:31:408:43 | ...::read [Ok] | provenance | Src:MaD:28 | +| test.rs:408:31:408:43 | ...::read | test.rs:408:31:408:55 | ...::read(...) [Ok] | provenance | Src:MaD:28 | +| test.rs:408:31:408:43 | ...::read [Ok] | test.rs:408:31:408:55 | ...::read(...) [Ok] | provenance | MaD:29 | | test.rs:408:31:408:55 | ...::read(...) [Ok] | test.rs:408:31:408:56 | TryExpr | provenance | | | test.rs:408:31:408:56 | TryExpr | test.rs:408:13:408:18 | buffer | provenance | | | test.rs:413:13:413:18 | buffer | test.rs:414:14:414:19 | buffer | provenance | | -| test.rs:413:31:413:38 | ...::read | test.rs:413:31:413:38 | ...::read [Ok] | provenance | Src:MaD:25 | -| test.rs:413:31:413:38 | ...::read | test.rs:413:31:413:50 | ...::read(...) [Ok] | provenance | Src:MaD:25 | -| test.rs:413:31:413:38 | ...::read [Ok] | test.rs:413:31:413:50 | ...::read(...) [Ok] | provenance | MaD:26 | +| test.rs:413:31:413:38 | ...::read | test.rs:413:31:413:38 | ...::read [Ok] | provenance | Src:MaD:28 | +| test.rs:413:31:413:38 | ...::read | test.rs:413:31:413:50 | ...::read(...) [Ok] | provenance | Src:MaD:28 | +| test.rs:413:31:413:38 | ...::read [Ok] | test.rs:413:31:413:50 | ...::read(...) [Ok] | provenance | MaD:29 | | test.rs:413:31:413:50 | ...::read(...) [Ok] | test.rs:413:31:413:51 | TryExpr | provenance | | | test.rs:413:31:413:51 | TryExpr | test.rs:413:13:413:18 | buffer | provenance | | | test.rs:418:13:418:18 | buffer | test.rs:419:14:419:19 | buffer | provenance | | -| test.rs:418:22:418:39 | ...::read_to_string | test.rs:418:22:418:39 | ...::read_to_string [Ok] | provenance | Src:MaD:28 | -| test.rs:418:22:418:39 | ...::read_to_string | test.rs:418:22:418:51 | ...::read_to_string(...) [Ok] | provenance | Src:MaD:28 | -| test.rs:418:22:418:39 | ...::read_to_string [Ok] | test.rs:418:22:418:51 | ...::read_to_string(...) [Ok] | provenance | MaD:29 | +| test.rs:418:22:418:39 | ...::read_to_string | test.rs:418:22:418:39 | ...::read_to_string [Ok] | provenance | Src:MaD:31 | +| test.rs:418:22:418:39 | ...::read_to_string | test.rs:418:22:418:51 | ...::read_to_string(...) [Ok] | provenance | Src:MaD:31 | +| test.rs:418:22:418:39 | ...::read_to_string [Ok] | test.rs:418:22:418:51 | ...::read_to_string(...) [Ok] | provenance | MaD:32 | | test.rs:418:22:418:51 | ...::read_to_string(...) [Ok] | test.rs:418:22:418:52 | TryExpr | provenance | | | test.rs:418:22:418:52 | TryExpr | test.rs:418:13:418:18 | buffer | provenance | | | test.rs:425:13:425:16 | path | test.rs:426:14:426:17 | path | provenance | | -| test.rs:425:13:425:16 | path | test.rs:426:14:426:25 | path.clone() | provenance | MaD:37 | +| test.rs:425:13:425:16 | path | test.rs:426:14:426:25 | path.clone() | provenance | MaD:40 | | test.rs:425:13:425:16 | path | test.rs:427:14:427:17 | path | provenance | | -| test.rs:425:13:425:16 | path | test.rs:427:14:427:25 | path.clone() | provenance | MaD:37 | +| test.rs:425:13:425:16 | path | test.rs:427:14:427:25 | path.clone() | provenance | MaD:40 | | test.rs:425:13:425:16 | path | test.rs:437:14:437:17 | path | provenance | | | test.rs:425:20:425:27 | e.path() | test.rs:425:13:425:16 | path | provenance | | -| test.rs:425:22:425:25 | path | test.rs:425:20:425:27 | e.path() | provenance | Src:MaD:6 MaD:6 | -| test.rs:426:14:426:17 | path | test.rs:426:14:426:25 | path.clone() | provenance | MaD:37 | -| test.rs:427:14:427:17 | path | test.rs:427:14:427:25 | path.clone() | provenance | MaD:37 | -| test.rs:427:14:427:25 | path.clone() | test.rs:427:14:427:35 | ... .as_path() | provenance | MaD:116 | +| test.rs:425:22:425:25 | path | test.rs:425:20:425:27 | e.path() | provenance | Src:MaD:9 MaD:9 | +| test.rs:426:14:426:17 | path | test.rs:426:14:426:25 | path.clone() | provenance | MaD:40 | +| test.rs:427:14:427:17 | path | test.rs:427:14:427:25 | path.clone() | provenance | MaD:40 | +| test.rs:427:14:427:25 | path.clone() | test.rs:427:14:427:35 | ... .as_path() | provenance | MaD:119 | | test.rs:439:13:439:21 | file_name | test.rs:440:14:440:22 | file_name | provenance | | -| test.rs:439:13:439:21 | file_name | test.rs:440:14:440:30 | file_name.clone() | provenance | MaD:37 | +| test.rs:439:13:439:21 | file_name | test.rs:440:14:440:30 | file_name.clone() | provenance | MaD:40 | | test.rs:439:13:439:21 | file_name | test.rs:445:14:445:22 | file_name | provenance | | | test.rs:439:25:439:37 | e.file_name() | test.rs:439:13:439:21 | file_name | provenance | | -| test.rs:439:27:439:35 | file_name | test.rs:439:25:439:37 | e.file_name() | provenance | Src:MaD:5 MaD:5 | -| test.rs:440:14:440:22 | file_name | test.rs:440:14:440:30 | file_name.clone() | provenance | MaD:37 | +| test.rs:439:27:439:35 | file_name | test.rs:439:25:439:37 | e.file_name() | provenance | Src:MaD:8 MaD:8 | +| test.rs:440:14:440:22 | file_name | test.rs:440:14:440:30 | file_name.clone() | provenance | MaD:40 | | test.rs:461:13:461:18 | target | test.rs:462:14:462:19 | target | provenance | | -| test.rs:461:22:461:34 | ...::read_link | test.rs:461:22:461:49 | ...::read_link(...) [Ok] | provenance | Src:MaD:27 | +| test.rs:461:22:461:34 | ...::read_link | test.rs:461:22:461:49 | ...::read_link(...) [Ok] | provenance | Src:MaD:30 | | test.rs:461:22:461:49 | ...::read_link(...) [Ok] | test.rs:461:22:461:50 | TryExpr | provenance | | | test.rs:461:22:461:50 | TryExpr | test.rs:461:13:461:18 | target | provenance | | | test.rs:470:13:470:18 | buffer | test.rs:471:14:471:19 | buffer | provenance | | -| test.rs:470:31:470:45 | ...::read | test.rs:470:31:470:57 | ...::read(...) [future, Ok] | provenance | Src:MaD:31 | +| test.rs:470:31:470:45 | ...::read | test.rs:470:31:470:57 | ...::read(...) [future, Ok] | provenance | Src:MaD:34 | | test.rs:470:31:470:57 | ...::read(...) [future, Ok] | test.rs:470:31:470:63 | await ... [Ok] | provenance | | | test.rs:470:31:470:63 | await ... [Ok] | test.rs:470:31:470:64 | TryExpr | provenance | | | test.rs:470:31:470:64 | TryExpr | test.rs:470:13:470:18 | buffer | provenance | | | test.rs:475:13:475:18 | buffer | test.rs:476:14:476:19 | buffer | provenance | | -| test.rs:475:31:475:45 | ...::read | test.rs:475:31:475:57 | ...::read(...) [future, Ok] | provenance | Src:MaD:31 | +| test.rs:475:31:475:45 | ...::read | test.rs:475:31:475:57 | ...::read(...) [future, Ok] | provenance | Src:MaD:34 | | test.rs:475:31:475:57 | ...::read(...) [future, Ok] | test.rs:475:31:475:63 | await ... [Ok] | provenance | | | test.rs:475:31:475:63 | await ... [Ok] | test.rs:475:31:475:64 | TryExpr | provenance | | | test.rs:475:31:475:64 | TryExpr | test.rs:475:13:475:18 | buffer | provenance | | | test.rs:480:13:480:18 | buffer | test.rs:481:14:481:19 | buffer | provenance | | -| test.rs:480:22:480:46 | ...::read_to_string | test.rs:480:22:480:58 | ...::read_to_string(...) [future, Ok] | provenance | Src:MaD:33 | +| test.rs:480:22:480:46 | ...::read_to_string | test.rs:480:22:480:58 | ...::read_to_string(...) [future, Ok] | provenance | Src:MaD:36 | | test.rs:480:22:480:58 | ...::read_to_string(...) [future, Ok] | test.rs:480:22:480:64 | await ... [Ok] | provenance | | | test.rs:480:22:480:64 | await ... [Ok] | test.rs:480:22:480:65 | TryExpr | provenance | | | test.rs:480:22:480:65 | TryExpr | test.rs:480:13:480:18 | buffer | provenance | | | test.rs:486:13:486:16 | path | test.rs:488:14:488:17 | path | provenance | | | test.rs:486:20:486:31 | entry.path() | test.rs:486:13:486:16 | path | provenance | | -| test.rs:486:26:486:29 | path | test.rs:486:20:486:31 | entry.path() | provenance | Src:MaD:14 MaD:14 | -| test.rs:486:26:486:29 | path | test.rs:486:20:486:31 | entry.path() | provenance | Src:MaD:14 MaD:14 | +| test.rs:486:26:486:29 | path | test.rs:486:20:486:31 | entry.path() | provenance | Src:MaD:17 MaD:17 | +| test.rs:486:26:486:29 | path | test.rs:486:20:486:31 | entry.path() | provenance | Src:MaD:17 MaD:17 | | test.rs:487:13:487:21 | file_name | test.rs:489:14:489:22 | file_name | provenance | | | test.rs:487:25:487:41 | entry.file_name() | test.rs:487:13:487:21 | file_name | provenance | | -| test.rs:487:31:487:39 | file_name | test.rs:487:25:487:41 | entry.file_name() | provenance | Src:MaD:13 MaD:13 | -| test.rs:487:31:487:39 | file_name | test.rs:487:25:487:41 | entry.file_name() | provenance | Src:MaD:13 MaD:13 | +| test.rs:487:31:487:39 | file_name | test.rs:487:25:487:41 | entry.file_name() | provenance | Src:MaD:16 MaD:16 | +| test.rs:487:31:487:39 | file_name | test.rs:487:25:487:41 | entry.file_name() | provenance | Src:MaD:16 MaD:16 | | test.rs:493:13:493:18 | target | test.rs:494:14:494:19 | target | provenance | | -| test.rs:493:22:493:41 | ...::read_link | test.rs:493:22:493:56 | ...::read_link(...) [future, Ok] | provenance | Src:MaD:32 | +| test.rs:493:22:493:41 | ...::read_link | test.rs:493:22:493:56 | ...::read_link(...) [future, Ok] | provenance | Src:MaD:35 | | test.rs:493:22:493:56 | ...::read_link(...) [future, Ok] | test.rs:493:22:493:62 | await ... [Ok] | provenance | | | test.rs:493:22:493:62 | await ... [Ok] | test.rs:493:22:493:63 | TryExpr | provenance | | | test.rs:493:22:493:63 | TryExpr | test.rs:493:13:493:18 | target | provenance | | -| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer | provenance | MaD:97 | -| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer [&ref] | provenance | MaD:96 | -| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer | provenance | MaD:99 | -| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer [&ref] | provenance | MaD:59 | -| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer [&ref] | provenance | MaD:98 | -| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer | provenance | MaD:101 | -| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer [&ref] | provenance | MaD:60 | -| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer [&ref] | provenance | MaD:100 | -| test.rs:503:9:503:16 | mut file | test.rs:525:25:525:35 | [post] &mut buffer [&ref] | provenance | MaD:58 | -| test.rs:503:9:503:16 | mut file | test.rs:529:17:529:28 | file.bytes() | provenance | MaD:54 | -| test.rs:503:20:503:38 | ...::open | test.rs:503:20:503:50 | ...::open(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer | provenance | MaD:100 | +| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:503:9:503:16 | mut file | test.rs:507:32:507:42 | [post] &mut buffer [&ref] | provenance | MaD:99 | +| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer | provenance | MaD:102 | +| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer [&ref] | provenance | MaD:62 | +| test.rs:503:9:503:16 | mut file | test.rs:513:39:513:49 | [post] &mut buffer [&ref] | provenance | MaD:101 | +| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer | provenance | MaD:104 | +| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer [&ref] | provenance | MaD:63 | +| test.rs:503:9:503:16 | mut file | test.rs:519:42:519:52 | [post] &mut buffer [&ref] | provenance | MaD:103 | +| test.rs:503:9:503:16 | mut file | test.rs:525:25:525:35 | [post] &mut buffer [&ref] | provenance | MaD:61 | +| test.rs:503:9:503:16 | mut file | test.rs:529:17:529:28 | file.bytes() | provenance | MaD:57 | +| test.rs:503:20:503:38 | ...::open | test.rs:503:20:503:50 | ...::open(...) [Ok] | provenance | Src:MaD:10 | | test.rs:503:20:503:50 | ...::open(...) [Ok] | test.rs:503:20:503:51 | TryExpr | provenance | | | test.rs:503:20:503:51 | TryExpr | test.rs:503:9:503:16 | mut file | provenance | | | test.rs:507:32:507:42 | [post] &mut buffer | test.rs:508:15:508:20 | buffer | provenance | | @@ -542,69 +545,69 @@ edges | test.rs:525:30:525:35 | [post] buffer | test.rs:526:15:526:20 | buffer | provenance | | | test.rs:526:15:526:20 | buffer | test.rs:526:14:526:20 | &buffer | provenance | | | test.rs:529:17:529:28 | file.bytes() | test.rs:530:14:530:17 | byte | provenance | | -| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer | provenance | MaD:97 | -| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer [&ref] | provenance | MaD:96 | -| test.rs:536:22:536:63 | ... .open(...) [Ok] | test.rs:536:22:536:72 | ... .unwrap() | provenance | MaD:84 | +| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer | provenance | MaD:100 | +| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:536:13:536:18 | mut f1 | test.rs:538:30:538:40 | [post] &mut buffer [&ref] | provenance | MaD:99 | +| test.rs:536:22:536:63 | ... .open(...) [Ok] | test.rs:536:22:536:72 | ... .unwrap() | provenance | MaD:87 | | test.rs:536:22:536:72 | ... .unwrap() | test.rs:536:13:536:18 | mut f1 | provenance | | -| test.rs:536:50:536:53 | open | test.rs:536:22:536:63 | ... .open(...) [Ok] | provenance | Src:MaD:8 | +| test.rs:536:50:536:53 | open | test.rs:536:22:536:63 | ... .open(...) [Ok] | provenance | Src:MaD:11 | | test.rs:538:30:538:40 | [post] &mut buffer | test.rs:539:15:539:20 | buffer | provenance | | | test.rs:538:30:538:40 | [post] &mut buffer [&ref] | test.rs:538:35:538:40 | [post] buffer | provenance | | | test.rs:538:35:538:40 | [post] buffer | test.rs:539:15:539:20 | buffer | provenance | | | test.rs:539:15:539:20 | buffer | test.rs:539:14:539:20 | &buffer | provenance | | -| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer | provenance | MaD:97 | -| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer [&ref] | provenance | MaD:96 | -| test.rs:543:22:543:80 | ... .open(...) [Ok] | test.rs:543:22:543:89 | ... .unwrap() | provenance | MaD:84 | +| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer | provenance | MaD:100 | +| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:543:13:543:18 | mut f2 | test.rs:545:30:545:40 | [post] &mut buffer [&ref] | provenance | MaD:99 | +| test.rs:543:22:543:80 | ... .open(...) [Ok] | test.rs:543:22:543:89 | ... .unwrap() | provenance | MaD:87 | | test.rs:543:22:543:89 | ... .unwrap() | test.rs:543:13:543:18 | mut f2 | provenance | | -| test.rs:543:67:543:70 | open | test.rs:543:22:543:80 | ... .open(...) [Ok] | provenance | Src:MaD:8 | +| test.rs:543:67:543:70 | open | test.rs:543:22:543:80 | ... .open(...) [Ok] | provenance | Src:MaD:11 | | test.rs:545:30:545:40 | [post] &mut buffer | test.rs:546:15:546:20 | buffer | provenance | | | test.rs:545:30:545:40 | [post] &mut buffer [&ref] | test.rs:545:35:545:40 | [post] buffer | provenance | | | test.rs:545:35:545:40 | [post] buffer | test.rs:546:15:546:20 | buffer | provenance | | | test.rs:546:15:546:20 | buffer | test.rs:546:14:546:20 | &buffer | provenance | | -| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer | provenance | MaD:97 | -| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer [&ref] | provenance | MaD:96 | -| test.rs:550:22:550:114 | ... .open(...) [Ok] | test.rs:550:22:550:123 | ... .unwrap() | provenance | MaD:84 | +| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer | provenance | MaD:100 | +| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:550:13:550:18 | mut f3 | test.rs:552:30:552:40 | [post] &mut buffer [&ref] | provenance | MaD:99 | +| test.rs:550:22:550:114 | ... .open(...) [Ok] | test.rs:550:22:550:123 | ... .unwrap() | provenance | MaD:87 | | test.rs:550:22:550:123 | ... .unwrap() | test.rs:550:13:550:18 | mut f3 | provenance | | -| test.rs:550:101:550:104 | open | test.rs:550:22:550:114 | ... .open(...) [Ok] | provenance | Src:MaD:8 | +| test.rs:550:101:550:104 | open | test.rs:550:22:550:114 | ... .open(...) [Ok] | provenance | Src:MaD:11 | | test.rs:552:30:552:40 | [post] &mut buffer | test.rs:553:15:553:20 | buffer | provenance | | | test.rs:552:30:552:40 | [post] &mut buffer [&ref] | test.rs:552:35:552:40 | [post] buffer | provenance | | | test.rs:552:35:552:40 | [post] buffer | test.rs:553:15:553:20 | buffer | provenance | | | test.rs:553:15:553:20 | buffer | test.rs:553:14:553:20 | &buffer | provenance | | -| test.rs:560:13:560:17 | file1 | test.rs:562:26:562:43 | file1.chain(...) | provenance | MaD:56 | -| test.rs:560:21:560:39 | ...::open | test.rs:560:21:560:51 | ...::open(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:560:13:560:17 | file1 | test.rs:562:26:562:43 | file1.chain(...) | provenance | MaD:59 | +| test.rs:560:21:560:39 | ...::open | test.rs:560:21:560:51 | ...::open(...) [Ok] | provenance | Src:MaD:10 | | test.rs:560:21:560:51 | ...::open(...) [Ok] | test.rs:560:21:560:52 | TryExpr | provenance | | | test.rs:560:21:560:52 | TryExpr | test.rs:560:13:560:17 | file1 | provenance | | | test.rs:561:13:561:17 | file2 | test.rs:562:38:562:42 | file2 | provenance | | -| test.rs:561:21:561:39 | ...::open | test.rs:561:21:561:59 | ...::open(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:561:21:561:39 | ...::open | test.rs:561:21:561:59 | ...::open(...) [Ok] | provenance | Src:MaD:10 | | test.rs:561:21:561:59 | ...::open(...) [Ok] | test.rs:561:21:561:60 | TryExpr | provenance | | | test.rs:561:21:561:60 | TryExpr | test.rs:561:13:561:17 | file2 | provenance | | -| test.rs:562:13:562:22 | mut reader | test.rs:563:31:563:41 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:562:13:562:22 | mut reader | test.rs:563:31:563:41 | [post] &mut buffer [&ref] | provenance | MaD:63 | | test.rs:562:26:562:43 | file1.chain(...) | test.rs:562:13:562:22 | mut reader | provenance | | -| test.rs:562:38:562:42 | file2 | test.rs:562:26:562:43 | file1.chain(...) | provenance | MaD:55 | +| test.rs:562:38:562:42 | file2 | test.rs:562:26:562:43 | file1.chain(...) | provenance | MaD:58 | | test.rs:563:31:563:41 | [post] &mut buffer [&ref] | test.rs:563:36:563:41 | [post] buffer | provenance | | | test.rs:563:36:563:41 | [post] buffer | test.rs:564:15:564:20 | buffer | provenance | | | test.rs:564:15:564:20 | buffer | test.rs:564:14:564:20 | &buffer | provenance | | -| test.rs:569:13:569:17 | file1 | test.rs:570:26:570:40 | file1.take(...) | provenance | MaD:61 | -| test.rs:569:21:569:39 | ...::open | test.rs:569:21:569:51 | ...::open(...) [Ok] | provenance | Src:MaD:7 | +| test.rs:569:13:569:17 | file1 | test.rs:570:26:570:40 | file1.take(...) | provenance | MaD:64 | +| test.rs:569:21:569:39 | ...::open | test.rs:569:21:569:51 | ...::open(...) [Ok] | provenance | Src:MaD:10 | | test.rs:569:21:569:51 | ...::open(...) [Ok] | test.rs:569:21:569:52 | TryExpr | provenance | | | test.rs:569:21:569:52 | TryExpr | test.rs:569:13:569:17 | file1 | provenance | | -| test.rs:570:13:570:22 | mut reader | test.rs:571:31:571:41 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:570:13:570:22 | mut reader | test.rs:571:31:571:41 | [post] &mut buffer [&ref] | provenance | MaD:63 | | test.rs:570:26:570:40 | file1.take(...) | test.rs:570:13:570:22 | mut reader | provenance | | | test.rs:571:31:571:41 | [post] &mut buffer [&ref] | test.rs:571:36:571:41 | [post] buffer | provenance | | | test.rs:571:36:571:41 | [post] buffer | test.rs:572:15:572:20 | buffer | provenance | | | test.rs:572:15:572:20 | buffer | test.rs:572:14:572:20 | &buffer | provenance | | -| test.rs:581:9:581:16 | mut file | test.rs:585:32:585:42 | [post] &mut buffer [&ref] | provenance | MaD:67 | -| test.rs:581:9:581:16 | mut file | test.rs:591:39:591:49 | [post] &mut buffer [&ref] | provenance | MaD:73 | -| test.rs:581:9:581:16 | mut file | test.rs:597:42:597:52 | [post] &mut buffer [&ref] | provenance | MaD:74 | -| test.rs:581:9:581:16 | mut file | test.rs:603:25:603:35 | [post] &mut buffer [&ref] | provenance | MaD:69 | -| test.rs:581:9:581:16 | mut file | test.rs:608:18:608:31 | file.read_u8() [future, Ok] | provenance | MaD:75 | -| test.rs:581:9:581:16 | mut file | test.rs:609:18:609:32 | file.read_i16() [future, Ok] | provenance | MaD:71 | -| test.rs:581:9:581:16 | mut file | test.rs:610:18:610:32 | file.read_f32() [future, Ok] | provenance | MaD:70 | -| test.rs:581:9:581:16 | mut file | test.rs:611:18:611:35 | file.read_i64_le() [future, Ok] | provenance | MaD:72 | -| test.rs:581:9:581:16 | mut file | test.rs:620:23:620:33 | [post] &mut buffer [&ref] | provenance | MaD:68 | -| test.rs:581:20:581:40 | ...::open | test.rs:581:20:581:52 | ...::open(...) [future, Ok] | provenance | Src:MaD:11 | +| test.rs:581:9:581:16 | mut file | test.rs:585:32:585:42 | [post] &mut buffer [&ref] | provenance | MaD:70 | +| test.rs:581:9:581:16 | mut file | test.rs:591:39:591:49 | [post] &mut buffer [&ref] | provenance | MaD:76 | +| test.rs:581:9:581:16 | mut file | test.rs:597:42:597:52 | [post] &mut buffer [&ref] | provenance | MaD:77 | +| test.rs:581:9:581:16 | mut file | test.rs:603:25:603:35 | [post] &mut buffer [&ref] | provenance | MaD:72 | +| test.rs:581:9:581:16 | mut file | test.rs:608:18:608:31 | file.read_u8() [future, Ok] | provenance | MaD:78 | +| test.rs:581:9:581:16 | mut file | test.rs:609:18:609:32 | file.read_i16() [future, Ok] | provenance | MaD:74 | +| test.rs:581:9:581:16 | mut file | test.rs:610:18:610:32 | file.read_f32() [future, Ok] | provenance | MaD:73 | +| test.rs:581:9:581:16 | mut file | test.rs:611:18:611:35 | file.read_i64_le() [future, Ok] | provenance | MaD:75 | +| test.rs:581:9:581:16 | mut file | test.rs:620:23:620:33 | [post] &mut buffer [&ref] | provenance | MaD:71 | +| test.rs:581:20:581:40 | ...::open | test.rs:581:20:581:52 | ...::open(...) [future, Ok] | provenance | Src:MaD:14 | | test.rs:581:20:581:52 | ...::open(...) [future, Ok] | test.rs:581:20:581:58 | await ... [Ok] | provenance | | | test.rs:581:20:581:58 | await ... [Ok] | test.rs:581:20:581:59 | TryExpr | provenance | | | test.rs:581:20:581:59 | TryExpr | test.rs:581:9:581:16 | mut file | provenance | | @@ -639,45 +642,45 @@ edges | test.rs:620:23:620:33 | [post] &mut buffer [&ref] | test.rs:620:28:620:33 | [post] buffer | provenance | | | test.rs:620:28:620:33 | [post] buffer | test.rs:621:15:621:20 | buffer | provenance | | | test.rs:621:15:621:20 | buffer | test.rs:621:14:621:20 | &buffer | provenance | | -| test.rs:627:13:627:18 | mut f1 | test.rs:629:30:629:40 | [post] &mut buffer [&ref] | provenance | MaD:67 | +| test.rs:627:13:627:18 | mut f1 | test.rs:629:30:629:40 | [post] &mut buffer [&ref] | provenance | MaD:70 | | test.rs:627:22:627:65 | ... .open(...) [future, Ok] | test.rs:627:22:627:71 | await ... [Ok] | provenance | | | test.rs:627:22:627:71 | await ... [Ok] | test.rs:627:22:627:72 | TryExpr | provenance | | | test.rs:627:22:627:72 | TryExpr | test.rs:627:13:627:18 | mut f1 | provenance | | -| test.rs:627:52:627:55 | open | test.rs:627:22:627:65 | ... .open(...) [future, Ok] | provenance | Src:MaD:12 | +| test.rs:627:52:627:55 | open | test.rs:627:22:627:65 | ... .open(...) [future, Ok] | provenance | Src:MaD:15 | | test.rs:629:30:629:40 | [post] &mut buffer [&ref] | test.rs:629:35:629:40 | [post] buffer | provenance | | | test.rs:629:35:629:40 | [post] buffer | test.rs:630:15:630:20 | buffer | provenance | | | test.rs:630:15:630:20 | buffer | test.rs:630:14:630:20 | &buffer | provenance | | | test.rs:660:9:660:16 | mut file | test.rs:664:22:664:25 | file | provenance | | -| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:35 | -| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:36 | -| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:46 | -| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:47 | -| test.rs:660:20:660:44 | ...::open | test.rs:660:20:660:56 | ...::open(...) [future, Ok] | provenance | Src:MaD:1 | +| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:38 | +| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:39 | +| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:49 | +| test.rs:660:9:660:16 | mut file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:50 | +| test.rs:660:20:660:44 | ...::open | test.rs:660:20:660:56 | ...::open(...) [future, Ok] | provenance | Src:MaD:4 | | test.rs:660:20:660:56 | ...::open(...) [future, Ok] | test.rs:660:20:660:62 | await ... [Ok] | provenance | | | test.rs:660:20:660:62 | await ... [Ok] | test.rs:660:20:660:63 | TryExpr | provenance | | | test.rs:660:20:660:63 | TryExpr | test.rs:660:9:660:16 | mut file | provenance | | -| test.rs:664:22:664:25 | file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:35 | -| test.rs:664:22:664:25 | file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:46 | +| test.rs:664:22:664:25 | file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:38 | +| test.rs:664:22:664:25 | file | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | provenance | MaD:49 | | test.rs:664:32:664:42 | [post] &mut buffer [&ref] | test.rs:664:37:664:42 | [post] buffer | provenance | | | test.rs:664:37:664:42 | [post] buffer | test.rs:665:15:665:20 | buffer | provenance | | | test.rs:665:15:665:20 | buffer | test.rs:665:14:665:20 | &buffer | provenance | | | test.rs:671:13:671:18 | mut f1 | test.rs:673:22:673:23 | f1 | provenance | | -| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:35 | -| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:36 | -| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:46 | -| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:47 | +| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:38 | +| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:39 | +| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:49 | +| test.rs:671:13:671:18 | mut f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:50 | | test.rs:671:22:671:69 | ... .open(...) [future, Ok] | test.rs:671:22:671:75 | await ... [Ok] | provenance | | | test.rs:671:22:671:75 | await ... [Ok] | test.rs:671:22:671:76 | TryExpr | provenance | | | test.rs:671:22:671:76 | TryExpr | test.rs:671:13:671:18 | mut f1 | provenance | | -| test.rs:671:56:671:59 | open | test.rs:671:22:671:69 | ... .open(...) [future, Ok] | provenance | Src:MaD:2 | -| test.rs:673:22:673:23 | f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:35 | -| test.rs:673:22:673:23 | f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:46 | +| test.rs:671:56:671:59 | open | test.rs:671:22:671:69 | ... .open(...) [future, Ok] | provenance | Src:MaD:5 | +| test.rs:673:22:673:23 | f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:38 | +| test.rs:673:22:673:23 | f1 | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | provenance | MaD:49 | | test.rs:673:30:673:40 | [post] &mut buffer [&ref] | test.rs:673:35:673:40 | [post] buffer | provenance | | | test.rs:673:35:673:40 | [post] buffer | test.rs:674:15:674:20 | buffer | provenance | | | test.rs:674:15:674:20 | buffer | test.rs:674:14:674:20 | &buffer | provenance | | -| test.rs:688:13:688:22 | mut stream | test.rs:695:29:695:39 | [post] &mut buffer [&ref] | provenance | MaD:57 | -| test.rs:688:13:688:22 | mut stream | test.rs:695:29:695:39 | [post] &mut buffer [&ref] | provenance | MaD:115 | -| test.rs:688:26:688:53 | ...::connect | test.rs:688:26:688:62 | ...::connect(...) [Ok] | provenance | Src:MaD:9 | +| test.rs:688:13:688:22 | mut stream | test.rs:695:29:695:39 | [post] &mut buffer [&ref] | provenance | MaD:60 | +| test.rs:688:13:688:22 | mut stream | test.rs:695:29:695:39 | [post] &mut buffer [&ref] | provenance | MaD:118 | +| test.rs:688:26:688:53 | ...::connect | test.rs:688:26:688:62 | ...::connect(...) [Ok] | provenance | Src:MaD:12 | | test.rs:688:26:688:62 | ...::connect(...) [Ok] | test.rs:688:26:688:63 | TryExpr | provenance | | | test.rs:688:26:688:63 | TryExpr | test.rs:688:13:688:22 | mut stream | provenance | | | test.rs:695:29:695:39 | [post] &mut buffer [&ref] | test.rs:695:34:695:39 | [post] buffer | provenance | | @@ -685,21 +688,21 @@ edges | test.rs:695:34:695:39 | [post] buffer | test.rs:699:14:699:22 | buffer[0] | provenance | | | test.rs:698:15:698:20 | buffer | test.rs:698:14:698:20 | &buffer | provenance | | | test.rs:707:13:707:22 | mut stream | test.rs:715:58:715:63 | stream | provenance | | -| test.rs:707:26:707:61 | ...::connect_timeout | test.rs:707:26:707:105 | ...::connect_timeout(...) [Ok] | provenance | Src:MaD:10 | +| test.rs:707:26:707:61 | ...::connect_timeout | test.rs:707:26:707:105 | ...::connect_timeout(...) [Ok] | provenance | Src:MaD:13 | | test.rs:707:26:707:105 | ...::connect_timeout(...) [Ok] | test.rs:707:26:707:106 | TryExpr | provenance | | | test.rs:707:26:707:106 | TryExpr | test.rs:707:13:707:22 | mut stream | provenance | | -| test.rs:715:21:715:30 | mut reader | test.rs:718:44:718:52 | [post] &mut line [&ref] | provenance | MaD:51 | -| test.rs:715:34:715:64 | ...::new(...) | test.rs:715:34:715:74 | ... .take(...) | provenance | MaD:61 | +| test.rs:715:21:715:30 | mut reader | test.rs:718:44:718:52 | [post] &mut line [&ref] | provenance | MaD:54 | +| test.rs:715:34:715:64 | ...::new(...) | test.rs:715:34:715:74 | ... .take(...) | provenance | MaD:64 | | test.rs:715:34:715:74 | ... .take(...) | test.rs:715:21:715:30 | mut reader | provenance | | -| test.rs:715:58:715:63 | stream | test.rs:715:34:715:64 | ...::new(...) | provenance | MaD:105 | +| test.rs:715:58:715:63 | stream | test.rs:715:34:715:64 | ...::new(...) | provenance | MaD:108 | | test.rs:718:44:718:52 | [post] &mut line [&ref] | test.rs:718:49:718:52 | [post] line | provenance | | | test.rs:718:49:718:52 | [post] line | test.rs:725:35:725:38 | line | provenance | | | test.rs:725:35:725:38 | line | test.rs:725:34:725:38 | &line | provenance | | -| test.rs:759:9:759:24 | mut tokio_stream | test.rs:767:35:767:46 | [post] &mut buffer1 [&ref] | provenance | MaD:121 | -| test.rs:759:9:759:24 | mut tokio_stream | test.rs:771:36:771:47 | [post] &mut buffer2 [&ref] | provenance | MaD:67 | -| test.rs:759:9:759:24 | mut tokio_stream | test.rs:787:41:787:51 | [post] &mut buffer [&ref] | provenance | MaD:122 | -| test.rs:759:9:759:24 | mut tokio_stream | test.rs:810:45:810:55 | [post] &mut buffer [&ref] | provenance | MaD:123 | -| test.rs:759:28:759:57 | ...::connect | test.rs:759:28:759:66 | ...::connect(...) [future, Ok] | provenance | Src:MaD:15 | +| test.rs:759:9:759:24 | mut tokio_stream | test.rs:767:35:767:46 | [post] &mut buffer1 [&ref] | provenance | MaD:124 | +| test.rs:759:9:759:24 | mut tokio_stream | test.rs:771:36:771:47 | [post] &mut buffer2 [&ref] | provenance | MaD:70 | +| test.rs:759:9:759:24 | mut tokio_stream | test.rs:787:41:787:51 | [post] &mut buffer [&ref] | provenance | MaD:125 | +| test.rs:759:9:759:24 | mut tokio_stream | test.rs:810:45:810:55 | [post] &mut buffer [&ref] | provenance | MaD:126 | +| test.rs:759:28:759:57 | ...::connect | test.rs:759:28:759:66 | ...::connect(...) [future, Ok] | provenance | Src:MaD:18 | | test.rs:759:28:759:66 | ...::connect(...) [future, Ok] | test.rs:759:28:759:72 | await ... [Ok] | provenance | | | test.rs:759:28:759:72 | await ... [Ok] | test.rs:759:28:759:73 | TryExpr | provenance | | | test.rs:759:28:759:73 | TryExpr | test.rs:759:9:759:24 | mut tokio_stream | provenance | | @@ -719,7 +722,7 @@ edges | test.rs:817:27:817:32 | buffer | test.rs:817:26:817:32 | &buffer | provenance | | | test_futures_io.rs:19:9:19:11 | tcp | test_futures_io.rs:20:11:20:13 | tcp | provenance | | | test_futures_io.rs:19:9:19:11 | tcp | test_futures_io.rs:26:53:26:55 | tcp | provenance | | -| test_futures_io.rs:19:15:19:32 | ...::connect | test_futures_io.rs:19:15:19:37 | ...::connect(...) [future, Ok] | provenance | Src:MaD:3 | +| test_futures_io.rs:19:15:19:32 | ...::connect | test_futures_io.rs:19:15:19:37 | ...::connect(...) [future, Ok] | provenance | Src:MaD:6 | | test_futures_io.rs:19:15:19:37 | ...::connect(...) [future, Ok] | test_futures_io.rs:19:15:19:43 | await ... [Ok] | provenance | | | test_futures_io.rs:19:15:19:43 | await ... [Ok] | test_futures_io.rs:19:15:19:44 | TryExpr | provenance | | | test_futures_io.rs:19:15:19:44 | TryExpr | test_futures_io.rs:19:9:19:11 | tcp | provenance | | @@ -728,15 +731,15 @@ edges | test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:32:40:32:45 | reader | provenance | | | test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:45:64:45:69 | reader | provenance | | | test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:27:49:32 | reader | provenance | | -| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:36 | -| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:46 | -| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:47 | +| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:39 | +| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:49 | +| test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:50 | | test_futures_io.rs:26:9:26:18 | mut reader | test_futures_io.rs:54:51:54:56 | reader | provenance | | | test_futures_io.rs:26:22:26:56 | connector.connect(...) [future, Ok] | test_futures_io.rs:26:22:26:62 | await ... [Ok] | provenance | | | test_futures_io.rs:26:22:26:62 | await ... [Ok] | test_futures_io.rs:26:22:26:63 | TryExpr | provenance | | | test_futures_io.rs:26:22:26:63 | TryExpr | test_futures_io.rs:26:9:26:18 | mut reader | provenance | | -| test_futures_io.rs:26:53:26:55 | tcp | test_futures_io.rs:26:22:26:56 | connector.connect(...) [future, Ok] | provenance | MaD:88 | +| test_futures_io.rs:26:53:26:55 | tcp | test_futures_io.rs:26:22:26:56 | connector.connect(...) [future, Ok] | provenance | MaD:91 | | test_futures_io.rs:27:11:27:16 | reader | test_futures_io.rs:27:10:27:16 | &reader | provenance | | | test_futures_io.rs:32:13:32:22 | mut pinned | test_futures_io.rs:33:15:33:20 | pinned | provenance | | | test_futures_io.rs:32:13:32:22 | mut pinned [&ref] | test_futures_io.rs:33:15:33:20 | pinned [&ref] | provenance | | @@ -744,60 +747,60 @@ edges | test_futures_io.rs:32:26:32:46 | ...::new(...) | test_futures_io.rs:32:13:32:22 | mut pinned | provenance | | | test_futures_io.rs:32:26:32:46 | ...::new(...) [&ref] | test_futures_io.rs:32:13:32:22 | mut pinned [&ref] | provenance | | | test_futures_io.rs:32:26:32:46 | ...::new(...) [Pin, &ref] | test_futures_io.rs:32:13:32:22 | mut pinned [Pin, &ref] | provenance | | -| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) | provenance | MaD:80 | -| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) [&ref] | provenance | MaD:82 | -| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) [Pin, &ref] | provenance | MaD:81 | +| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) | provenance | MaD:83 | +| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) [&ref] | provenance | MaD:85 | +| test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | test_futures_io.rs:32:26:32:46 | ...::new(...) [Pin, &ref] | provenance | MaD:84 | | test_futures_io.rs:32:40:32:45 | reader | test_futures_io.rs:32:35:32:45 | &mut reader [&ref] | provenance | | | test_futures_io.rs:33:15:33:20 | pinned | test_futures_io.rs:33:14:33:20 | &pinned | provenance | | | test_futures_io.rs:33:15:33:20 | pinned [&ref] | test_futures_io.rs:33:14:33:20 | &pinned | provenance | | | test_futures_io.rs:33:15:33:20 | pinned [Pin, &ref] | test_futures_io.rs:33:14:33:20 | &pinned | provenance | | -| test_futures_io.rs:45:59:45:69 | &mut reader [&ref] | test_futures_io.rs:45:72:45:83 | [post] &mut buffer1 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:45:59:45:69 | &mut reader [&ref] | test_futures_io.rs:45:72:45:83 | [post] &mut buffer1 [&ref] | provenance | MaD:46 | +| test_futures_io.rs:45:59:45:69 | &mut reader [&ref] | test_futures_io.rs:45:72:45:83 | [post] &mut buffer1 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:45:59:45:69 | &mut reader [&ref] | test_futures_io.rs:45:72:45:83 | [post] &mut buffer1 [&ref] | provenance | MaD:49 | | test_futures_io.rs:45:64:45:69 | reader | test_futures_io.rs:45:59:45:69 | &mut reader [&ref] | provenance | | | test_futures_io.rs:45:72:45:83 | [post] &mut buffer1 [&ref] | test_futures_io.rs:45:77:45:83 | [post] buffer1 | provenance | | | test_futures_io.rs:45:77:45:83 | [post] buffer1 | test_futures_io.rs:46:15:46:36 | buffer1[...] | provenance | | | test_futures_io.rs:46:15:46:36 | buffer1[...] | test_futures_io.rs:46:14:46:36 | &... | provenance | | -| test_futures_io.rs:49:27:49:32 | reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:49:27:49:32 | reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:46 | +| test_futures_io.rs:49:27:49:32 | reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:49:27:49:32 | reader | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | provenance | MaD:49 | | test_futures_io.rs:49:39:49:50 | [post] &mut buffer2 [&ref] | test_futures_io.rs:49:44:49:50 | [post] buffer2 | provenance | | | test_futures_io.rs:49:44:49:50 | [post] buffer2 | test_futures_io.rs:51:15:51:36 | buffer2[...] | provenance | | | test_futures_io.rs:51:15:51:36 | buffer2[...] | test_futures_io.rs:51:14:51:36 | &... | provenance | | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:55:11:55:17 | reader2 | provenance | | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:59:40:59:46 | reader2 | provenance | | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:69:37:69:43 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:83:22:83:39 | reader2.fill_buf() [future, Ok] | provenance | MaD:41 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:83:22:83:39 | reader2.fill_buf() [future, Ok] | provenance | MaD:44 | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:90:40:90:46 | reader2 | provenance | | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:103:64:103:70 | reader2 | provenance | | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:27:107:33 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:36 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:46 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:47 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:39 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:49 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:50 | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:113:40:113:46 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:125:22:125:39 | reader2.fill_buf() [future, Ok] | provenance | MaD:41 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:125:22:125:39 | reader2.fill_buf() [future, Ok] | provenance | MaD:44 | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:132:27:132:33 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:44 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:45 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:47 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:48 | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:139:27:139:33 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:42 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:43 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:45 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:46 | | test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:146:27:146:33 | reader2 | provenance | | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:48 | -| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:49 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:51 | +| test_futures_io.rs:54:9:54:19 | mut reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:52 | | test_futures_io.rs:54:23:54:57 | ...::new(...) | test_futures_io.rs:54:9:54:19 | mut reader2 | provenance | | -| test_futures_io.rs:54:51:54:56 | reader | test_futures_io.rs:54:23:54:57 | ...::new(...) | provenance | MaD:89 | +| test_futures_io.rs:54:51:54:56 | reader | test_futures_io.rs:54:23:54:57 | ...::new(...) | provenance | MaD:92 | | test_futures_io.rs:55:11:55:17 | reader2 | test_futures_io.rs:55:10:55:17 | &reader2 | provenance | | | test_futures_io.rs:59:13:59:22 | mut pinned | test_futures_io.rs:60:15:60:20 | pinned | provenance | | -| test_futures_io.rs:59:13:59:22 | mut pinned | test_futures_io.rs:62:22:62:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | +| test_futures_io.rs:59:13:59:22 | mut pinned | test_futures_io.rs:62:22:62:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | | test_futures_io.rs:59:13:59:22 | mut pinned [&ref] | test_futures_io.rs:60:15:60:20 | pinned [&ref] | provenance | | -| test_futures_io.rs:59:13:59:22 | mut pinned [&ref] | test_futures_io.rs:62:22:62:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | +| test_futures_io.rs:59:13:59:22 | mut pinned [&ref] | test_futures_io.rs:62:22:62:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | | test_futures_io.rs:59:13:59:22 | mut pinned [Pin, &ref] | test_futures_io.rs:60:15:60:20 | pinned [Pin, &ref] | provenance | | | test_futures_io.rs:59:26:59:47 | ...::new(...) | test_futures_io.rs:59:13:59:22 | mut pinned | provenance | | | test_futures_io.rs:59:26:59:47 | ...::new(...) [&ref] | test_futures_io.rs:59:13:59:22 | mut pinned [&ref] | provenance | | | test_futures_io.rs:59:26:59:47 | ...::new(...) [Pin, &ref] | test_futures_io.rs:59:13:59:22 | mut pinned [Pin, &ref] | provenance | | -| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) | provenance | MaD:80 | -| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) [&ref] | provenance | MaD:82 | -| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) [Pin, &ref] | provenance | MaD:81 | +| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) | provenance | MaD:83 | +| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) [&ref] | provenance | MaD:85 | +| test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | test_futures_io.rs:59:26:59:47 | ...::new(...) [Pin, &ref] | provenance | MaD:84 | | test_futures_io.rs:59:40:59:46 | reader2 | test_futures_io.rs:59:35:59:46 | &mut reader2 [&ref] | provenance | | | test_futures_io.rs:60:15:60:20 | pinned | test_futures_io.rs:60:14:60:20 | &pinned | provenance | | | test_futures_io.rs:60:15:60:20 | pinned [&ref] | test_futures_io.rs:60:14:60:20 | &pinned | provenance | | @@ -810,11 +813,11 @@ edges | test_futures_io.rs:63:31:63:33 | buf | test_futures_io.rs:65:18:65:20 | buf | provenance | | | test_futures_io.rs:64:19:64:24 | buffer [Ready, Ok] | test_futures_io.rs:64:18:64:24 | &buffer | provenance | | | test_futures_io.rs:69:13:69:19 | buffer2 [Ready, Ok] | test_futures_io.rs:70:16:70:22 | buffer2 [Ready, Ok] | provenance | | -| test_futures_io.rs:69:23:69:44 | ...::new(...) | test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | -| test_futures_io.rs:69:23:69:44 | ...::new(...) [&ref] | test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | +| test_futures_io.rs:69:23:69:44 | ...::new(...) | test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | +| test_futures_io.rs:69:23:69:44 | ...::new(...) [&ref] | test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | | test_futures_io.rs:69:23:69:67 | ... .poll_fill_buf(...) [Ready, Ok] | test_futures_io.rs:69:13:69:19 | buffer2 [Ready, Ok] | provenance | | -| test_futures_io.rs:69:32:69:43 | &mut reader2 [&ref] | test_futures_io.rs:69:23:69:44 | ...::new(...) | provenance | MaD:80 | -| test_futures_io.rs:69:32:69:43 | &mut reader2 [&ref] | test_futures_io.rs:69:23:69:44 | ...::new(...) [&ref] | provenance | MaD:82 | +| test_futures_io.rs:69:32:69:43 | &mut reader2 [&ref] | test_futures_io.rs:69:23:69:44 | ...::new(...) | provenance | MaD:83 | +| test_futures_io.rs:69:32:69:43 | &mut reader2 [&ref] | test_futures_io.rs:69:23:69:44 | ...::new(...) [&ref] | provenance | MaD:85 | | test_futures_io.rs:69:37:69:43 | reader2 | test_futures_io.rs:69:32:69:43 | &mut reader2 [&ref] | provenance | | | test_futures_io.rs:70:16:70:22 | buffer2 [Ready, Ok] | test_futures_io.rs:71:13:71:32 | ...::Ready(...) [Ready, Ok] | provenance | | | test_futures_io.rs:70:16:70:22 | buffer2 [Ready, Ok] | test_futures_io.rs:72:23:72:29 | buffer2 [Ready, Ok] | provenance | | @@ -832,35 +835,35 @@ edges | test_futures_io.rs:90:26:90:47 | ...::new(...) | test_futures_io.rs:90:13:90:22 | mut pinned | provenance | | | test_futures_io.rs:90:26:90:47 | ...::new(...) [&ref] | test_futures_io.rs:90:13:90:22 | mut pinned [&ref] | provenance | | | test_futures_io.rs:90:26:90:47 | ...::new(...) [Pin, &ref] | test_futures_io.rs:90:13:90:22 | mut pinned [Pin, &ref] | provenance | | -| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) | provenance | MaD:80 | -| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) [&ref] | provenance | MaD:82 | -| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) [Pin, &ref] | provenance | MaD:81 | +| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) | provenance | MaD:83 | +| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) [&ref] | provenance | MaD:85 | +| test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | test_futures_io.rs:90:26:90:47 | ...::new(...) [Pin, &ref] | provenance | MaD:84 | | test_futures_io.rs:90:40:90:46 | reader2 | test_futures_io.rs:90:35:90:46 | &mut reader2 [&ref] | provenance | | | test_futures_io.rs:91:15:91:20 | pinned | test_futures_io.rs:91:14:91:20 | &pinned | provenance | | | test_futures_io.rs:91:15:91:20 | pinned [&ref] | test_futures_io.rs:91:14:91:20 | &pinned | provenance | | | test_futures_io.rs:91:15:91:20 | pinned [Pin, &ref] | test_futures_io.rs:91:14:91:20 | &pinned | provenance | | -| test_futures_io.rs:103:59:103:70 | &mut reader2 [&ref] | test_futures_io.rs:103:73:103:84 | [post] &mut buffer1 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:103:59:103:70 | &mut reader2 [&ref] | test_futures_io.rs:103:73:103:84 | [post] &mut buffer1 [&ref] | provenance | MaD:46 | +| test_futures_io.rs:103:59:103:70 | &mut reader2 [&ref] | test_futures_io.rs:103:73:103:84 | [post] &mut buffer1 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:103:59:103:70 | &mut reader2 [&ref] | test_futures_io.rs:103:73:103:84 | [post] &mut buffer1 [&ref] | provenance | MaD:49 | | test_futures_io.rs:103:64:103:70 | reader2 | test_futures_io.rs:103:59:103:70 | &mut reader2 [&ref] | provenance | | | test_futures_io.rs:103:73:103:84 | [post] &mut buffer1 [&ref] | test_futures_io.rs:103:78:103:84 | [post] buffer1 | provenance | | | test_futures_io.rs:103:78:103:84 | [post] buffer1 | test_futures_io.rs:104:15:104:36 | buffer1[...] | provenance | | | test_futures_io.rs:104:15:104:36 | buffer1[...] | test_futures_io.rs:104:14:104:36 | &... | provenance | | -| test_futures_io.rs:107:27:107:33 | reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:35 | -| test_futures_io.rs:107:27:107:33 | reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:46 | +| test_futures_io.rs:107:27:107:33 | reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:38 | +| test_futures_io.rs:107:27:107:33 | reader2 | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | provenance | MaD:49 | | test_futures_io.rs:107:40:107:51 | [post] &mut buffer2 [&ref] | test_futures_io.rs:107:45:107:51 | [post] buffer2 | provenance | | | test_futures_io.rs:107:45:107:51 | [post] buffer2 | test_futures_io.rs:108:15:108:36 | buffer2[...] | provenance | | | test_futures_io.rs:108:15:108:36 | buffer2[...] | test_futures_io.rs:108:14:108:36 | &... | provenance | | | test_futures_io.rs:113:13:113:22 | mut pinned | test_futures_io.rs:114:15:114:20 | pinned | provenance | | -| test_futures_io.rs:113:13:113:22 | mut pinned | test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | +| test_futures_io.rs:113:13:113:22 | mut pinned | test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | | test_futures_io.rs:113:13:113:22 | mut pinned [&ref] | test_futures_io.rs:114:15:114:20 | pinned [&ref] | provenance | | -| test_futures_io.rs:113:13:113:22 | mut pinned [&ref] | test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:40 | +| test_futures_io.rs:113:13:113:22 | mut pinned [&ref] | test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) [Ready, Ok] | provenance | MaD:43 | | test_futures_io.rs:113:13:113:22 | mut pinned [Pin, &ref] | test_futures_io.rs:114:15:114:20 | pinned [Pin, &ref] | provenance | | | test_futures_io.rs:113:26:113:47 | ...::new(...) | test_futures_io.rs:113:13:113:22 | mut pinned | provenance | | | test_futures_io.rs:113:26:113:47 | ...::new(...) [&ref] | test_futures_io.rs:113:13:113:22 | mut pinned [&ref] | provenance | | | test_futures_io.rs:113:26:113:47 | ...::new(...) [Pin, &ref] | test_futures_io.rs:113:13:113:22 | mut pinned [Pin, &ref] | provenance | | -| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) | provenance | MaD:80 | -| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) [&ref] | provenance | MaD:82 | -| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) [Pin, &ref] | provenance | MaD:81 | +| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) | provenance | MaD:83 | +| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) [&ref] | provenance | MaD:85 | +| test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | test_futures_io.rs:113:26:113:47 | ...::new(...) [Pin, &ref] | provenance | MaD:84 | | test_futures_io.rs:113:40:113:46 | reader2 | test_futures_io.rs:113:35:113:46 | &mut reader2 [&ref] | provenance | | | test_futures_io.rs:114:15:114:20 | pinned | test_futures_io.rs:114:14:114:20 | &pinned | provenance | | | test_futures_io.rs:114:15:114:20 | pinned [&ref] | test_futures_io.rs:114:14:114:20 | &pinned | provenance | | @@ -876,42 +879,58 @@ edges | test_futures_io.rs:125:22:125:39 | reader2.fill_buf() [future, Ok] | test_futures_io.rs:125:22:125:45 | await ... [Ok] | provenance | | | test_futures_io.rs:125:22:125:45 | await ... [Ok] | test_futures_io.rs:125:22:125:46 | TryExpr | provenance | | | test_futures_io.rs:125:22:125:46 | TryExpr | test_futures_io.rs:125:13:125:18 | buffer | provenance | | -| test_futures_io.rs:132:27:132:33 | reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:44 | +| test_futures_io.rs:132:27:132:33 | reader2 | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | provenance | MaD:47 | | test_futures_io.rs:132:53:132:61 | [post] &mut line [&ref] | test_futures_io.rs:132:58:132:61 | [post] line | provenance | | | test_futures_io.rs:132:58:132:61 | [post] line | test_futures_io.rs:133:15:133:18 | line | provenance | | | test_futures_io.rs:133:15:133:18 | line | test_futures_io.rs:133:14:133:18 | &line | provenance | | -| test_futures_io.rs:139:27:139:33 | reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:42 | +| test_futures_io.rs:139:27:139:33 | reader2 | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | provenance | MaD:45 | | test_futures_io.rs:139:45:139:53 | [post] &mut line [&ref] | test_futures_io.rs:139:50:139:53 | [post] line | provenance | | | test_futures_io.rs:139:50:139:53 | [post] line | test_futures_io.rs:140:15:140:18 | line | provenance | | | test_futures_io.rs:140:15:140:18 | line | test_futures_io.rs:140:14:140:18 | &line | provenance | | -| test_futures_io.rs:146:27:146:33 | reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:48 | +| test_futures_io.rs:146:27:146:33 | reader2 | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | provenance | MaD:51 | | test_futures_io.rs:146:47:146:57 | [post] &mut buffer [&ref] | test_futures_io.rs:146:52:146:57 | [post] buffer | provenance | | | test_futures_io.rs:146:52:146:57 | [post] buffer | test_futures_io.rs:147:15:147:20 | buffer | provenance | | | test_futures_io.rs:147:15:147:20 | buffer | test_futures_io.rs:147:14:147:20 | &buffer | provenance | | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:14 | a | provenance | | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:14 | a | provenance | | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:77 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:86 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:77 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:86 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:80 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:89 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:80 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:89 | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:14 | a | provenance | | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:14 | a | provenance | | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:76 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:85 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:76 | -| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:85 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:79 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:88 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:79 | +| web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:88 | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:15:14:15:14 | a | provenance | | | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:15:14:15:14 | a | provenance | | -| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:77 | -| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:86 | -| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:77 | -| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:86 | -| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:76 | -| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:85 | -| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:76 | -| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:85 | +| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:80 | +| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:22 | a.as_str() | provenance | MaD:89 | +| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:80 | +| web_frameworks.rs:13:14:13:14 | a | web_frameworks.rs:13:14:13:23 | a.as_str() | provenance | MaD:89 | +| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:79 | +| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:24 | a.as_bytes() | provenance | MaD:88 | +| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:79 | +| web_frameworks.rs:14:14:14:14 | a | web_frameworks.rs:14:14:14:25 | a.as_bytes() | provenance | MaD:88 | | web_frameworks.rs:68:15:68:15 | a | web_frameworks.rs:70:14:70:14 | a | provenance | | | web_frameworks.rs:68:15:68:15 | a | web_frameworks.rs:70:14:70:14 | a | provenance | | +| web_frameworks.rs:242:33:242:35 | map | web_frameworks.rs:242:38:242:46 | ...: String | provenance | Src:MaD:2 | +| web_frameworks.rs:242:33:242:35 | map | web_frameworks.rs:242:38:242:46 | ...: String | provenance | Src:MaD:2 | +| web_frameworks.rs:242:38:242:46 | ...: String | web_frameworks.rs:244:18:244:18 | a | provenance | | +| web_frameworks.rs:242:38:242:46 | ...: String | web_frameworks.rs:244:18:244:18 | a | provenance | | +| web_frameworks.rs:250:46:250:49 | then | web_frameworks.rs:251:25:251:33 | ...: String | provenance | Src:MaD:3 | +| web_frameworks.rs:250:46:250:49 | then | web_frameworks.rs:251:25:251:33 | ...: String | provenance | Src:MaD:3 | +| web_frameworks.rs:251:25:251:33 | ...: String | web_frameworks.rs:252:22:252:22 | a | provenance | | +| web_frameworks.rs:251:25:251:33 | ...: String | web_frameworks.rs:252:22:252:22 | a | provenance | | +| web_frameworks.rs:259:50:259:57 | and_then | web_frameworks.rs:260:26:260:32 | ...: u64 | provenance | Src:MaD:1 | +| web_frameworks.rs:259:50:259:57 | and_then | web_frameworks.rs:260:26:260:32 | ...: u64 | provenance | Src:MaD:1 | +| web_frameworks.rs:260:26:260:32 | ...: u64 | web_frameworks.rs:263:22:263:23 | id | provenance | | +| web_frameworks.rs:260:26:260:32 | ...: u64 | web_frameworks.rs:263:22:263:23 | id | provenance | | +| web_frameworks.rs:272:75:272:77 | map | web_frameworks.rs:273:15:273:23 | ...: String | provenance | Src:MaD:2 | +| web_frameworks.rs:272:75:272:77 | map | web_frameworks.rs:273:15:273:23 | ...: String | provenance | Src:MaD:2 | +| web_frameworks.rs:273:15:273:23 | ...: String | web_frameworks.rs:275:22:275:22 | a | provenance | | +| web_frameworks.rs:273:15:273:23 | ...: String | web_frameworks.rs:275:22:275:22 | a | provenance | | nodes | test.rs:8:10:8:22 | ...::var | semmle.label | ...::var | | test.rs:8:10:8:30 | ...::var(...) | semmle.label | ...::var(...) | @@ -1700,6 +1719,30 @@ nodes | web_frameworks.rs:68:15:68:15 | a | semmle.label | a | | web_frameworks.rs:70:14:70:14 | a | semmle.label | a | | web_frameworks.rs:70:14:70:14 | a | semmle.label | a | +| web_frameworks.rs:242:33:242:35 | map | semmle.label | map | +| web_frameworks.rs:242:33:242:35 | map | semmle.label | map | +| web_frameworks.rs:242:38:242:46 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:242:38:242:46 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:244:18:244:18 | a | semmle.label | a | +| web_frameworks.rs:244:18:244:18 | a | semmle.label | a | +| web_frameworks.rs:250:46:250:49 | then | semmle.label | then | +| web_frameworks.rs:250:46:250:49 | then | semmle.label | then | +| web_frameworks.rs:251:25:251:33 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:251:25:251:33 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:252:22:252:22 | a | semmle.label | a | +| web_frameworks.rs:252:22:252:22 | a | semmle.label | a | +| web_frameworks.rs:259:50:259:57 | and_then | semmle.label | and_then | +| web_frameworks.rs:259:50:259:57 | and_then | semmle.label | and_then | +| web_frameworks.rs:260:26:260:32 | ...: u64 | semmle.label | ...: u64 | +| web_frameworks.rs:260:26:260:32 | ...: u64 | semmle.label | ...: u64 | +| web_frameworks.rs:263:22:263:23 | id | semmle.label | id | +| web_frameworks.rs:263:22:263:23 | id | semmle.label | id | +| web_frameworks.rs:272:75:272:77 | map | semmle.label | map | +| web_frameworks.rs:272:75:272:77 | map | semmle.label | map | +| web_frameworks.rs:273:15:273:23 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:273:15:273:23 | ...: String | semmle.label | ...: String | +| web_frameworks.rs:275:22:275:22 | a | semmle.label | a | +| web_frameworks.rs:275:22:275:22 | a | semmle.label | a | subpaths testFailures #select @@ -1839,3 +1882,11 @@ testFailures | web_frameworks.rs:15:14:15:14 | a | web_frameworks.rs:11:31:11:31 | a | web_frameworks.rs:15:14:15:14 | a | $@ | web_frameworks.rs:11:31:11:31 | a | a | | web_frameworks.rs:70:14:70:14 | a | web_frameworks.rs:68:15:68:15 | a | web_frameworks.rs:70:14:70:14 | a | $@ | web_frameworks.rs:68:15:68:15 | a | a | | web_frameworks.rs:70:14:70:14 | a | web_frameworks.rs:68:15:68:15 | a | web_frameworks.rs:70:14:70:14 | a | $@ | web_frameworks.rs:68:15:68:15 | a | a | +| web_frameworks.rs:244:18:244:18 | a | web_frameworks.rs:242:33:242:35 | map | web_frameworks.rs:244:18:244:18 | a | $@ | web_frameworks.rs:242:33:242:35 | map | map | +| web_frameworks.rs:244:18:244:18 | a | web_frameworks.rs:242:33:242:35 | map | web_frameworks.rs:244:18:244:18 | a | $@ | web_frameworks.rs:242:33:242:35 | map | map | +| web_frameworks.rs:252:22:252:22 | a | web_frameworks.rs:250:46:250:49 | then | web_frameworks.rs:252:22:252:22 | a | $@ | web_frameworks.rs:250:46:250:49 | then | then | +| web_frameworks.rs:252:22:252:22 | a | web_frameworks.rs:250:46:250:49 | then | web_frameworks.rs:252:22:252:22 | a | $@ | web_frameworks.rs:250:46:250:49 | then | then | +| web_frameworks.rs:263:22:263:23 | id | web_frameworks.rs:259:50:259:57 | and_then | web_frameworks.rs:263:22:263:23 | id | $@ | web_frameworks.rs:259:50:259:57 | and_then | and_then | +| web_frameworks.rs:263:22:263:23 | id | web_frameworks.rs:259:50:259:57 | and_then | web_frameworks.rs:263:22:263:23 | id | $@ | web_frameworks.rs:259:50:259:57 | and_then | and_then | +| web_frameworks.rs:275:22:275:22 | a | web_frameworks.rs:272:75:272:77 | map | web_frameworks.rs:275:22:275:22 | a | $@ | web_frameworks.rs:272:75:272:77 | map | map | +| web_frameworks.rs:275:22:275:22 | a | web_frameworks.rs:272:75:272:77 | map | web_frameworks.rs:275:22:275:22 | a | $@ | web_frameworks.rs:272:75:272:77 | map | map | diff --git a/rust/ql/test/library-tests/dataflow/sources/web_frameworks.rs b/rust/ql/test/library-tests/dataflow/sources/web_frameworks.rs index 857fc3b479e..3b901bd823f 100644 --- a/rust/ql/test/library-tests/dataflow/sources/web_frameworks.rs +++ b/rust/ql/test/library-tests/dataflow/sources/web_frameworks.rs @@ -241,7 +241,7 @@ mod warp_test { let map_route = warp::path::param().map(|a: String| // $ Alert[rust/summary/taint-sources] { - sink(a); // $ MISSING: hasTaintFlow + sink(a); // $ hasTaintFlow "".to_string() }); @@ -249,7 +249,7 @@ mod warp_test { // A route with parameter and `then` let then_route = warp::path::param().then( // $ Alert[rust/summary/taint-sources] async move |a: String| { - sink(a); // $ MISSING: hasTaintFlow + sink(a); // $ hasTaintFlow "".to_string() }, @@ -260,7 +260,7 @@ mod warp_test { async move | id: u64 | { if id != 0 { - sink(id); // $ MISSING: hasTaintFlow + sink(id); // $ hasTaintFlow Ok("".to_string()) } else { Err(warp::reject::not_found()) @@ -272,7 +272,7 @@ mod warp_test { let path_and_map_route = warp::path("1").and(warp::path::param()).map( // $ Alert[rust/summary/taint-sources] | a: String | { - sink(a); // $ MISSING: hasTaintFlow + sink(a); // $ hasTaintFlow "".to_string() }, diff --git a/rust/ql/test/query-tests/security/CWE-918/RequestForgery.expected b/rust/ql/test/query-tests/security/CWE-918/RequestForgery.expected index 4d44df7349f..a33742a7c4b 100644 --- a/rust/ql/test/query-tests/security/CWE-918/RequestForgery.expected +++ b/rust/ql/test/query-tests/security/CWE-918/RequestForgery.expected @@ -8,6 +8,8 @@ | request_forgery_tests.rs:31:29:31:40 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:29:31:40 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value | | request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value | | request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value | +| request_forgery_tests.rs:68:28:68:39 | ...::get | request_forgery_tests.rs:65:33:65:40 | and_then | request_forgery_tests.rs:68:28:68:39 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:65:33:65:40 | and_then | user-provided value | +| request_forgery_tests.rs:68:28:68:39 | ...::get | request_forgery_tests.rs:65:33:65:40 | and_then | request_forgery_tests.rs:68:28:68:39 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:65:33:65:40 | and_then | user-provided value | edges | request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:16:27:16:49 | { ... } | provenance | | | request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:20:27:20:57 | { ... } | provenance | | @@ -28,22 +30,22 @@ edges | request_forgery_tests.rs:16:13:16:15 | url | request_forgery_tests.rs:17:39:17:41 | url | provenance | | | request_forgery_tests.rs:16:27:16:49 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | | | request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | request_forgery_tests.rs:16:13:16:15 | url | provenance | | -| request_forgery_tests.rs:16:27:16:49 | MacroExpr | request_forgery_tests.rs:16:27:16:49 | ...::format(...) | provenance | MaD:2 | -| request_forgery_tests.rs:16:27:16:49 | { ... } | request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | provenance | MaD:3 | +| request_forgery_tests.rs:16:27:16:49 | MacroExpr | request_forgery_tests.rs:16:27:16:49 | ...::format(...) | provenance | MaD:3 | +| request_forgery_tests.rs:16:27:16:49 | { ... } | request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | provenance | MaD:4 | | request_forgery_tests.rs:17:38:17:41 | &url [&ref] | request_forgery_tests.rs:17:25:17:36 | ...::get | provenance | MaD:1 Sink:MaD:1 | | request_forgery_tests.rs:17:39:17:41 | url | request_forgery_tests.rs:17:38:17:41 | &url [&ref] | provenance | | | request_forgery_tests.rs:20:13:20:15 | url | request_forgery_tests.rs:21:39:21:41 | url | provenance | | | request_forgery_tests.rs:20:27:20:57 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | | | request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | request_forgery_tests.rs:20:13:20:15 | url | provenance | | -| request_forgery_tests.rs:20:27:20:57 | MacroExpr | request_forgery_tests.rs:20:27:20:57 | ...::format(...) | provenance | MaD:2 | -| request_forgery_tests.rs:20:27:20:57 | { ... } | request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | provenance | MaD:3 | +| request_forgery_tests.rs:20:27:20:57 | MacroExpr | request_forgery_tests.rs:20:27:20:57 | ...::format(...) | provenance | MaD:3 | +| request_forgery_tests.rs:20:27:20:57 | { ... } | request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | provenance | MaD:4 | | request_forgery_tests.rs:21:38:21:41 | &url [&ref] | request_forgery_tests.rs:21:25:21:36 | ...::get | provenance | MaD:1 Sink:MaD:1 | | request_forgery_tests.rs:21:39:21:41 | url | request_forgery_tests.rs:21:38:21:41 | &url [&ref] | provenance | | | request_forgery_tests.rs:24:13:24:15 | url | request_forgery_tests.rs:25:39:25:41 | url | provenance | | | request_forgery_tests.rs:24:27:24:70 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | | | request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | request_forgery_tests.rs:24:13:24:15 | url | provenance | | -| request_forgery_tests.rs:24:27:24:70 | MacroExpr | request_forgery_tests.rs:24:27:24:70 | ...::format(...) | provenance | MaD:2 | -| request_forgery_tests.rs:24:27:24:70 | { ... } | request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | provenance | MaD:3 | +| request_forgery_tests.rs:24:27:24:70 | MacroExpr | request_forgery_tests.rs:24:27:24:70 | ...::format(...) | provenance | MaD:3 | +| request_forgery_tests.rs:24:27:24:70 | { ... } | request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | provenance | MaD:4 | | request_forgery_tests.rs:25:38:25:41 | &url [&ref] | request_forgery_tests.rs:25:25:25:36 | ...::get | provenance | MaD:1 Sink:MaD:1 | | request_forgery_tests.rs:25:39:25:41 | url | request_forgery_tests.rs:25:38:25:41 | &url [&ref] | provenance | | | request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | request_forgery_tests.rs:31:29:31:40 | ...::get | provenance | MaD:1 Sink:MaD:1 | @@ -54,10 +56,19 @@ edges | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | request_forgery_tests.rs:37:37:37:48 | ...::get | provenance | MaD:1 Sink:MaD:1 | | request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | | | request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | | +| request_forgery_tests.rs:65:33:65:40 | and_then | request_forgery_tests.rs:65:49:65:57 | ...: String | provenance | Src:MaD:2 | +| request_forgery_tests.rs:65:33:65:40 | and_then | request_forgery_tests.rs:65:49:65:57 | ...: String | provenance | Src:MaD:2 | +| request_forgery_tests.rs:65:49:65:57 | ...: String | request_forgery_tests.rs:68:42:68:42 | a | provenance | | +| request_forgery_tests.rs:65:49:65:57 | ...: String | request_forgery_tests.rs:68:42:68:42 | a | provenance | | +| request_forgery_tests.rs:68:41:68:42 | &a [&ref] | request_forgery_tests.rs:68:28:68:39 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| request_forgery_tests.rs:68:41:68:42 | &a [&ref] | request_forgery_tests.rs:68:28:68:39 | ...::get | provenance | MaD:1 Sink:MaD:1 | +| request_forgery_tests.rs:68:42:68:42 | a | request_forgery_tests.rs:68:41:68:42 | &a [&ref] | provenance | | +| request_forgery_tests.rs:68:42:68:42 | a | request_forgery_tests.rs:68:41:68:42 | &a [&ref] | provenance | | models | 1 | Sink: reqwest::get; Argument[0]; request-url | -| 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | -| 3 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | +| 2 | Source: <_ as warp::filter::Filter>::and_then; Argument[0].Parameter[0..7]; remote | +| 3 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 4 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | nodes | request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res | | request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res | @@ -106,4 +117,14 @@ nodes | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | semmle.label | &user_url [&ref] | | request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url | | request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url | +| request_forgery_tests.rs:65:33:65:40 | and_then | semmle.label | and_then | +| request_forgery_tests.rs:65:33:65:40 | and_then | semmle.label | and_then | +| request_forgery_tests.rs:65:49:65:57 | ...: String | semmle.label | ...: String | +| request_forgery_tests.rs:65:49:65:57 | ...: String | semmle.label | ...: String | +| request_forgery_tests.rs:68:28:68:39 | ...::get | semmle.label | ...::get | +| request_forgery_tests.rs:68:28:68:39 | ...::get | semmle.label | ...::get | +| request_forgery_tests.rs:68:41:68:42 | &a [&ref] | semmle.label | &a [&ref] | +| request_forgery_tests.rs:68:41:68:42 | &a [&ref] | semmle.label | &a [&ref] | +| request_forgery_tests.rs:68:42:68:42 | a | semmle.label | a | +| request_forgery_tests.rs:68:42:68:42 | a | semmle.label | a | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs b/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs index ab99d73db43..f9abf14de4f 100644 --- a/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs +++ b/rust/ql/test/query-tests/security/CWE-918/request_forgery_tests.rs @@ -62,10 +62,10 @@ mod warp_test { async fn test_warp() { // A route with parameter and `and_then` let map_route = - warp::path::param().and_then(async |a: String| // $ MISSING: Source=a + warp::path::param().and_then(async |a: String| // $ Source=a { - let response = reqwest::get(&a).await; // $ MISSING: Alert[rust/request-forgery]=a + let response = reqwest::get(&a).await; // $ Alert[rust/request-forgery]=a match response { Ok(resp) => Ok(resp.text().await.unwrap_or_default()), Err(_err) => Err(warp::reject::not_found()), diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index 3eda6709517..9c46e04bf4b 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -1206,12 +1206,12 @@ module Make< * Holds if this node is an exit node, i.e. after all stores have been performed. * * A local flow step should be added from this node to a data flow node representing - * `sc` inside `source`. + * `s` inside `source`. */ - predicate isExit(SourceElement source, SummaryComponent sc, string model) { + predicate isExit(SourceElement source, SummaryComponentStack s, string model) { source = source_ and model = model_ and - state_.isSourceOutputState(source, TSingletonSummaryComponentStack(sc), _, model) + state_.isSourceOutputState(source, s, _, model) } override predicate isHidden() { not this.isEntry(_, _) } @@ -1460,7 +1460,7 @@ module Make< DataFlowType getSyntheticGlobalType(SyntheticGlobal sg); - DataFlowType getSourceType(SourceBase source, SummaryComponent sc); + DataFlowType getSourceType(SourceBase source, SummaryComponentStack sc); DataFlowType getSinkType(SinkBase sink, SummaryComponent sc); } @@ -1543,9 +1543,9 @@ module Make< ) or exists(SourceElement source | - exists(SummaryComponent sc | - n.(SourceOutputNode).isExit(source, sc, _) and - result = getSourceType(source, sc) + exists(SummaryComponentStack s | + n.(SourceOutputNode).isExit(source, s, _) and + result = getSourceType(source, s) ) or exists(SummaryComponentStack s, ContentSet cont | @@ -1574,13 +1574,16 @@ module Make< /** Gets a call that targets summarized callable `sc`. */ DataFlowCall getACall(SummarizedCallable sc); + /** Gets the enclosing callable of `source`. */ + DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source); + /** - * Gets a data flow node corresponding to the `sc` part of `source`. + * Gets a data flow node corresponding to the `s` part of `source`. * - * `sc` is typically `ReturnValue` and the result is the node that + * `s` is typically `ReturnValue` and the result is the node that * represents the return value of `source`. */ - Node getSourceNode(SourceBase source, SummaryComponent sc); + Node getSourceNode(SourceBase source, SummaryComponentStack s); /** * Gets a data flow node corresponding to the `sc` part of `sink`. @@ -1622,13 +1625,20 @@ module Make< ) } - predicate sourceLocalStep(SourceOutputNode nodeFrom, Node nodeTo, string model) { - exists(SummaryComponent sc, SourceElement source | + predicate sourceStep(SourceOutputNode nodeFrom, Node nodeTo, string model, boolean local) { + exists(SummaryComponentStack sc, SourceElement source | nodeFrom.isExit(source, sc, model) and - nodeTo = StepsInput::getSourceNode(source, sc) + nodeTo = StepsInput::getSourceNode(source, sc) and + if StepsInput::getSourceNodeEnclosingCallable(source) = getNodeEnclosingCallable(nodeTo) + then local = true + else local = false ) } + predicate sourceLocalStep(SourceOutputNode nodeFrom, Node nodeTo, string model) { + sourceStep(nodeFrom, nodeTo, model, true) + } + predicate sinkLocalStep(Node nodeFrom, SinkInputNode nodeTo, string model) { exists(SummaryComponent sc, SinkElement sink | nodeFrom = StepsInput::getSinkNode(sink, sc) and @@ -1689,6 +1699,10 @@ module Make< ) } + predicate sourceJumpStep(SourceOutputNode nodeFrom, Node nodeTo) { + sourceStep(nodeFrom, nodeTo, _, false) + } + /** * Holds if values stored inside content `c` are cleared at `n`. `n` is a * synthesized summary node, so in order for values to be cleared at calls From 7d6e2060e526419ac1f14cf127b7d8e42bbcacfe Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 17 Sep 2025 14:05:39 +0200 Subject: [PATCH 39/90] Adapt all languages to changes in shared library --- .../semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll | 4 +++- .../code/csharp/dataflow/internal/FlowSummaryImpl.qll | 6 ++++-- go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll | 4 +++- .../semmle/code/java/dataflow/internal/FlowSummaryImpl.qll | 6 ++++-- .../javascript/dataflow/internal/FlowSummaryPrivate.qll | 4 +++- .../semmle/python/dataflow/new/internal/FlowSummaryImpl.qll | 4 +++- .../lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll | 4 +++- .../lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll | 4 +++- 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll index 58c3dfdea16..d89ab06ed82 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll @@ -104,7 +104,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { result.getStaticCallTarget().getUnderlyingCallable() = sc } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll index 90db68f7c93..3ee16f21489 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll @@ -183,7 +183,7 @@ private module TypesInput implements Impl::Private::TypesInputSig { ) } - DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponent sc) { + DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } @@ -195,7 +195,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { sc = viableCallable(result).asSummarizedCallable() } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll index 35887d076c0..496870286e9 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll @@ -117,7 +117,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { ) } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll index a2d25cadd88..8dc28ea2f60 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll @@ -132,7 +132,7 @@ private module TypesInput implements Impl::Private::TypesInputSig { exists(rk) } - DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponent sc) { + DataFlowType getSourceType(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } @@ -144,7 +144,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { sc = viableCallable(result).asSummarizedCallable() } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index 6315b34b0a4..a5131e4fd64 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -150,7 +150,9 @@ private module FlowSummaryStepInput implements Private::StepsInputSig { ) } - DataFlow::Node getSourceNode(SourceBase source, Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source) { none() } + + DataFlow::Node getSourceNode(SourceBase source, Private::SummaryComponentStack s) { none() } DataFlow::Node getSinkNode(SinkBase sink, Private::SummaryComponent sc) { none() } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll index f7fdf84549e..396154c06ee 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll @@ -105,7 +105,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { ]) } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll index c85d2230b23..f8e3894a833 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll @@ -161,7 +161,9 @@ private module StepsInput implements Impl::Private::StepsInputSig { result.asCall().getAstNode() = sc.(LibraryCallable).getACallSimple() } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll index cb889baaebc..46e2e63f2ca 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll @@ -113,7 +113,9 @@ private import Make as Imp private module StepsInput implements Impl::Private::StepsInputSig { DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc } - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponent sc) { none() } + DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } + + Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } From a4c61f69456415bdcf18b837d4adbe15e0bc6adf Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 18 Sep 2025 16:01:07 +0200 Subject: [PATCH 40/90] Rust: Accept test changes --- .../PathResolutionConsistency.expected | 2 +- .../dataflow/models/models.expected | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/models/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/dataflow/models/CONSISTENCY/PathResolutionConsistency.expected index ebe4e66e6e2..7db15783781 100644 --- a/rust/ql/test/library-tests/dataflow/models/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/dataflow/models/CONSISTENCY/PathResolutionConsistency.expected @@ -1,2 +1,2 @@ multipleCallTargets -| main.rs:362:14:362:30 | ... .lt(...) | +| main.rs:389:14:389:30 | ... .lt(...) | diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index 2918e5c3c39..955b0b81b44 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -233,18 +233,18 @@ edges | main.rs:247:35:247:35 | i | main.rs:247:47:247:47 | i | provenance | | | main.rs:261:18:261:18 | ... | main.rs:261:26:261:26 | a | provenance | | | main.rs:261:18:261:18 | ... | main.rs:261:26:261:26 | a | provenance | | -| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 MaD:8 | -| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 MaD:8 | -| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 MaD:8 | -| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 | +| main.rs:262:9:262:19 | pass_source | main.rs:261:18:261:18 | ... | provenance | Src:MaD:8 | +| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 | +| main.rs:264:9:264:19 | pass_source | main.rs:264:25:264:25 | ... | provenance | Src:MaD:8 | | main.rs:264:25:264:25 | ... | main.rs:265:18:265:18 | a | provenance | | | main.rs:264:25:264:25 | ... | main.rs:265:18:265:18 | a | provenance | | | main.rs:268:14:268:19 | ...: i64 | main.rs:269:18:269:18 | a | provenance | | | main.rs:268:14:268:19 | ...: i64 | main.rs:269:18:269:18 | a | provenance | | -| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 MaD:8 | -| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 MaD:8 | -| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 MaD:8 | -| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 MaD:8 | +| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 | +| main.rs:271:9:271:19 | pass_source | main.rs:268:14:268:19 | ...: i64 | provenance | Src:MaD:8 | +| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 | +| main.rs:273:9:273:19 | pass_source | main.rs:273:36:273:36 | ... | provenance | Src:MaD:8 | | main.rs:273:36:273:36 | ... | main.rs:274:18:274:18 | a | provenance | | | main.rs:273:36:273:36 | ... | main.rs:274:18:274:18 | a | provenance | | | main.rs:283:9:283:9 | s | main.rs:284:41:284:41 | s | provenance | | From 4244a6569c53e3f3b2fdf270769bbe23d2d84f22 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 19 Sep 2025 09:19:17 +0200 Subject: [PATCH 41/90] Rust: Add change note --- rust/ql/lib/change-notes/2025-09-19-parameter-mad.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 rust/ql/lib/change-notes/2025-09-19-parameter-mad.md diff --git a/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md b/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md new file mode 100644 index 00000000000..06f664a5213 --- /dev/null +++ b/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md @@ -0,0 +1,7 @@ +--- +category: feature +--- +* The models-as-data format for sources now supports access paths of the form + `Argument[i].Parameter[j]`. This denotes that the source passes tainted data to + the `j`th parameter of it's `i`th argument (which must be a function or a + closure). \ No newline at end of file From 45b84ffb3195f7b0069494624cd47e805c539872 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 22 Sep 2025 14:23:50 +0200 Subject: [PATCH 42/90] Rust: Ensure singleton --- rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll | 4 ++-- shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll index 129bd468e01..2763908ae02 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll @@ -168,12 +168,12 @@ private module StepsInput implements Impl::Private::StepsInputSig { or exists(ArgumentPosition pos, Expr arg | s.head() = Impl::Private::SummaryComponent::parameter(pos) and - arg = getSourceNodeArgument(source, s.tail().head()) and + arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and result.asParameter() = getCallable(arg).getParam(pos.getPosition()) ) or result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr() = - getSourceNodeArgument(source, s.head()) + getSourceNodeArgument(source, s.headOfSingleton()) } RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index 9c46e04bf4b..6cc9d6f88a4 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -709,6 +709,9 @@ module Make< this = TConsSummaryComponentStack(result, _) } + /** Gets the head of this stack if it is a singleton. */ + SummaryComponent headOfSingleton() { this = TSingletonSummaryComponentStack(result) } + /** Gets the tail of this stack, if any. */ SummaryComponentStack tail() { this = TConsSummaryComponentStack(_, result) } From b837c56bec5a598bdd951e30e998e449f8f19305 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:13:33 -0400 Subject: [PATCH 43/90] Refactor RootApi and GrapeApiClass constructors for improved readability; add getHelperSelf method to retrieve self parameter in helpers block. --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 39 +++++++++++--------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 4e178792572..95aa42fdfad 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -25,9 +25,7 @@ module Grape { * In other words, it does not subclass any other Grape API class in source code. */ class RootApi extends GrapeApiClass { - RootApi() { - not this = any(GrapeApiClass parent).getAnImmediateDescendent() - } + RootApi() { not this = any(GrapeApiClass parent).getAnImmediateDescendent() } } /** @@ -44,9 +42,7 @@ module Grape { * ``` */ class GrapeApiClass extends DataFlow::ClassNode { - GrapeApiClass() { - this = grapeApiBaseClass().getADescendentModule() - } + GrapeApiClass() { this = grapeApiBaseClass().getADescendentModule() } /** * Gets a `GrapeEndpoint` defined in this class. @@ -63,6 +59,20 @@ module Grape { // is invoked with an instance as the `self`. result = this.getModuleLevelSelf() } + + /** + * Gets the `self` parameter belonging to a method defined within a + * `helpers` block in this API class. + * + * These methods become available in endpoint contexts through Grape's DSL. + */ + DataFlow::SelfParameterNode getHelperSelf() { + exists(DataFlow::CallNode helpersCall | + helpersCall = this.getAModuleLevelCall("helpers") and + result.getSelfVariable().getDeclaringScope().getOuterScope+() = + helpersCall.getBlock().asExpr().getExpr() + ) + } } private DataFlow::ConstRef grapeApiBaseClass() { @@ -122,17 +132,12 @@ module Grape { */ private class GrapeParamsCall extends ParamsCallImpl { GrapeParamsCall() { - // Params calls within endpoint blocks - exists(GrapeApiClass api | - this.getMethodName() = "params" and - this.getParent+() = api.getADeclaration() - ) - or - // Params calls within helper methods (defined in helpers blocks) - exists(GrapeApiClass api, DataFlow::CallNode helpersCall | - helpersCall = api.getAModuleLevelCall("helpers") and - this.getMethodName() = "params" and - this.getParent+() = helpersCall.getBlock().asExpr().getExpr() + exists(API::Node n | this = n.getAMethodCall("params").asExpr().getExpr() | + // Params calls within endpoint blocks + n = grapeApiInstance() + or + // Params calls within helper methods (defined in helpers blocks) + n = any(GrapeApiClass c).getHelperSelf().track() ) } } From ecd0ce65fe91f6ff604185c59f526ca0442c8389 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:52:30 -0400 Subject: [PATCH 44/90] Refactor GrapeHeadersBlockCall and GrapeCookiesBlockCall to simplify method call checks --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 95aa42fdfad..7e3d6c54fe4 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -237,11 +237,8 @@ module Grape { */ private class GrapeHeadersBlockCall extends MethodCall { GrapeHeadersBlockCall() { - exists(GrapeApiClass api | - this.getParent+() = api.getADeclaration() and - this.getMethodName() = "headers" and - exists(this.getBlock()) - ) + this = grapeApiInstance().getAMethodCall("headers").asExpr().getExpr() and + exists(this.getBlock()) } } @@ -251,11 +248,8 @@ module Grape { */ private class GrapeCookiesBlockCall extends MethodCall { GrapeCookiesBlockCall() { - exists(GrapeApiClass api | - this.getParent+() = api.getADeclaration() and - this.getMethodName() = "cookies" and - exists(this.getBlock()) - ) + this = grapeApiInstance().getAMethodCall("cookies").asExpr().getExpr() and + exists(this.getBlock()) } } From 1183e50435d615679a27644e290138684aa7d203 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Sep 2025 19:45:34 +0200 Subject: [PATCH 45/90] Update rust/ql/lib/change-notes/2025-09-19-parameter-mad.md --- rust/ql/lib/change-notes/2025-09-19-parameter-mad.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md b/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md index 06f664a5213..fa3970790fa 100644 --- a/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md +++ b/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md @@ -3,5 +3,5 @@ category: feature --- * The models-as-data format for sources now supports access paths of the form `Argument[i].Parameter[j]`. This denotes that the source passes tainted data to - the `j`th parameter of it's `i`th argument (which must be a function or a + the `j`th parameter of its `i`th argument (which must be a function or a closure). \ No newline at end of file From 0665c39a072181e9adac06470466ff4377b17148 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:08:34 -0400 Subject: [PATCH 46/90] Refactor GrapeHelperMethod constructor to reuse getHelperSelf to traverse dataflow instead of AST - add tests to check for nested helpers --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 7 +- .../frameworks/grape/Flow.expected | 276 ++++++++++++------ .../frameworks/grape/Grape.expected | 32 +- .../library-tests/frameworks/grape/app.rb | 71 +++++ 4 files changed, 275 insertions(+), 111 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 7e3d6c54fe4..4d64e9461b3 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -291,12 +291,7 @@ module Grape { private class GrapeHelperMethod extends Method { private GrapeApiClass apiClass; - GrapeHelperMethod() { - exists(DataFlow::CallNode helpersCall | - helpersCall = apiClass.getAModuleLevelCall("helpers") and - this.getParent+() = helpersCall.getBlock().asExpr().getExpr() - ) - } + GrapeHelperMethod() { this = apiClass.getHelperSelf().getSelfVariable().getDeclaringScope() } /** * Gets the API class that contains this helper method. diff --git a/ruby/ql/test/library-tests/frameworks/grape/Flow.expected b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected index c104b36afb2..f04bd930ea9 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Flow.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Flow.expected @@ -2,44 +2,80 @@ models edges | app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select | provenance | | | app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select : [collection] [element] | provenance | | -| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | | -| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | | -| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:149:21:149:31 | call to user_params : [collection] [element] | provenance | | -| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:165:21:165:31 | call to user_params : [collection] [element] | provenance | | -| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | | -| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | | -| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | | -| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | | -| app.rb:126:9:126:15 | user_id | app.rb:133:14:133:20 | user_id | provenance | | -| app.rb:126:19:126:24 | call to params | app.rb:126:19:126:34 | ...[...] | provenance | | -| app.rb:126:19:126:34 | ...[...] | app.rb:126:9:126:15 | user_id | provenance | | -| app.rb:127:9:127:16 | route_id | app.rb:134:14:134:21 | route_id | provenance | | -| app.rb:127:20:127:40 | call to route_param | app.rb:127:9:127:16 | route_id | provenance | | -| app.rb:128:9:128:12 | auth | app.rb:135:14:135:17 | auth | provenance | | -| app.rb:128:16:128:22 | call to headers | app.rb:128:16:128:38 | ...[...] | provenance | | -| app.rb:128:16:128:38 | ...[...] | app.rb:128:9:128:12 | auth | provenance | | -| app.rb:129:9:129:15 | session | app.rb:136:14:136:20 | session | provenance | | -| app.rb:129:19:129:25 | call to cookies | app.rb:129:19:129:38 | ...[...] | provenance | | -| app.rb:129:19:129:38 | ...[...] | app.rb:129:9:129:15 | session | provenance | | -| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | | -| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | | -| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | | -| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | | -| app.rb:149:9:149:17 | user_data | app.rb:151:14:151:22 | user_data | provenance | | -| app.rb:149:9:149:17 | user_data : [collection] [element] | app.rb:151:14:151:22 | user_data | provenance | | -| app.rb:149:21:149:31 | call to user_params | app.rb:149:9:149:17 | user_data | provenance | | -| app.rb:149:21:149:31 | call to user_params : [collection] [element] | app.rb:149:9:149:17 | user_data : [collection] [element] | provenance | | -| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | | -| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | | -| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | | -| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | | -| app.rb:159:13:159:19 | user_id | app.rb:160:18:160:24 | user_id | provenance | | -| app.rb:159:23:159:28 | call to params | app.rb:159:23:159:33 | ...[...] | provenance | | -| app.rb:159:23:159:33 | ...[...] | app.rb:159:13:159:19 | user_id | provenance | | -| app.rb:165:9:165:17 | user_data | app.rb:166:14:166:22 | user_data | provenance | | -| app.rb:165:9:165:17 | user_data : [collection] [element] | app.rb:166:14:166:22 | user_data | provenance | | -| app.rb:165:21:165:31 | call to user_params | app.rb:165:9:165:17 | user_data | provenance | | -| app.rb:165:21:165:31 | call to user_params : [collection] [element] | app.rb:165:9:165:17 | user_data : [collection] [element] | provenance | | +| app.rb:103:13:103:70 | call to select | app.rb:189:21:189:31 | call to user_params | provenance | | +| app.rb:103:13:103:70 | call to select | app.rb:205:21:205:31 | call to user_params | provenance | | +| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:189:21:189:31 | call to user_params : [collection] [element] | provenance | | +| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:205:21:205:31 | call to user_params : [collection] [element] | provenance | | +| app.rb:107:13:107:32 | call to source | app.rb:183:18:183:43 | call to vulnerable_helper | provenance | | +| app.rb:107:13:107:32 | call to source | app.rb:183:18:183:43 | call to vulnerable_helper | provenance | | +| app.rb:111:13:111:33 | call to source | app.rb:190:25:190:37 | call to simple_helper | provenance | | +| app.rb:111:13:111:33 | call to source | app.rb:190:25:190:37 | call to simple_helper | provenance | | +| app.rb:118:17:118:43 | call to source | app.rb:212:23:212:39 | call to authenticate_user | provenance | | +| app.rb:118:17:118:43 | call to source | app.rb:212:23:212:39 | call to authenticate_user | provenance | | +| app.rb:122:17:122:47 | call to source | app.rb:216:23:216:48 | call to check_permissions | provenance | | +| app.rb:122:17:122:47 | call to source | app.rb:216:23:216:48 | call to check_permissions | provenance | | +| app.rb:128:17:128:42 | call to source | app.rb:220:29:220:80 | call to validate_email | provenance | | +| app.rb:128:17:128:42 | call to source | app.rb:220:29:220:80 | call to validate_email | provenance | | +| app.rb:134:17:134:42 | call to source | app.rb:225:28:225:39 | call to debug_helper | provenance | | +| app.rb:134:17:134:42 | call to source | app.rb:225:28:225:39 | call to debug_helper | provenance | | +| app.rb:140:17:140:37 | call to source | app.rb:230:25:230:37 | call to rescue_helper | provenance | | +| app.rb:140:17:140:37 | call to source | app.rb:230:25:230:37 | call to rescue_helper | provenance | | +| app.rb:150:17:150:35 | call to source | app.rb:235:27:235:37 | call to test_helper | provenance | | +| app.rb:150:17:150:35 | call to source | app.rb:235:27:235:37 | call to test_helper | provenance | | +| app.rb:166:9:166:15 | user_id | app.rb:173:14:173:20 | user_id | provenance | | +| app.rb:166:19:166:24 | call to params | app.rb:166:19:166:34 | ...[...] | provenance | | +| app.rb:166:19:166:34 | ...[...] | app.rb:166:9:166:15 | user_id | provenance | | +| app.rb:167:9:167:16 | route_id | app.rb:174:14:174:21 | route_id | provenance | | +| app.rb:167:20:167:40 | call to route_param | app.rb:167:9:167:16 | route_id | provenance | | +| app.rb:168:9:168:12 | auth | app.rb:175:14:175:17 | auth | provenance | | +| app.rb:168:16:168:22 | call to headers | app.rb:168:16:168:38 | ...[...] | provenance | | +| app.rb:168:16:168:38 | ...[...] | app.rb:168:9:168:12 | auth | provenance | | +| app.rb:169:9:169:15 | session | app.rb:176:14:176:20 | session | provenance | | +| app.rb:169:19:169:25 | call to cookies | app.rb:169:19:169:38 | ...[...] | provenance | | +| app.rb:169:19:169:38 | ...[...] | app.rb:169:9:169:15 | session | provenance | | +| app.rb:183:9:183:14 | result | app.rb:184:14:184:19 | result | provenance | | +| app.rb:183:9:183:14 | result | app.rb:184:14:184:19 | result | provenance | | +| app.rb:183:18:183:43 | call to vulnerable_helper | app.rb:183:9:183:14 | result | provenance | | +| app.rb:183:18:183:43 | call to vulnerable_helper | app.rb:183:9:183:14 | result | provenance | | +| app.rb:189:9:189:17 | user_data | app.rb:191:14:191:22 | user_data | provenance | | +| app.rb:189:9:189:17 | user_data : [collection] [element] | app.rb:191:14:191:22 | user_data | provenance | | +| app.rb:189:21:189:31 | call to user_params | app.rb:189:9:189:17 | user_data | provenance | | +| app.rb:189:21:189:31 | call to user_params : [collection] [element] | app.rb:189:9:189:17 | user_data : [collection] [element] | provenance | | +| app.rb:190:9:190:21 | simple_result | app.rb:192:14:192:26 | simple_result | provenance | | +| app.rb:190:9:190:21 | simple_result | app.rb:192:14:192:26 | simple_result | provenance | | +| app.rb:190:25:190:37 | call to simple_helper | app.rb:190:9:190:21 | simple_result | provenance | | +| app.rb:190:25:190:37 | call to simple_helper | app.rb:190:9:190:21 | simple_result | provenance | | +| app.rb:199:13:199:19 | user_id | app.rb:200:18:200:24 | user_id | provenance | | +| app.rb:199:23:199:28 | call to params | app.rb:199:23:199:33 | ...[...] | provenance | | +| app.rb:199:23:199:33 | ...[...] | app.rb:199:13:199:19 | user_id | provenance | | +| app.rb:205:9:205:17 | user_data | app.rb:206:14:206:22 | user_data | provenance | | +| app.rb:205:9:205:17 | user_data : [collection] [element] | app.rb:206:14:206:22 | user_data | provenance | | +| app.rb:205:21:205:31 | call to user_params | app.rb:205:9:205:17 | user_data | provenance | | +| app.rb:205:21:205:31 | call to user_params : [collection] [element] | app.rb:205:9:205:17 | user_data : [collection] [element] | provenance | | +| app.rb:212:9:212:19 | auth_result | app.rb:213:14:213:24 | auth_result | provenance | | +| app.rb:212:9:212:19 | auth_result | app.rb:213:14:213:24 | auth_result | provenance | | +| app.rb:212:23:212:39 | call to authenticate_user | app.rb:212:9:212:19 | auth_result | provenance | | +| app.rb:212:23:212:39 | call to authenticate_user | app.rb:212:9:212:19 | auth_result | provenance | | +| app.rb:216:9:216:19 | perm_result | app.rb:217:14:217:24 | perm_result | provenance | | +| app.rb:216:9:216:19 | perm_result | app.rb:217:14:217:24 | perm_result | provenance | | +| app.rb:216:23:216:48 | call to check_permissions | app.rb:216:9:216:19 | perm_result | provenance | | +| app.rb:216:23:216:48 | call to check_permissions | app.rb:216:9:216:19 | perm_result | provenance | | +| app.rb:220:9:220:25 | validation_result | app.rb:221:14:221:30 | validation_result | provenance | | +| app.rb:220:9:220:25 | validation_result | app.rb:221:14:221:30 | validation_result | provenance | | +| app.rb:220:29:220:80 | call to validate_email | app.rb:220:9:220:25 | validation_result | provenance | | +| app.rb:220:29:220:80 | call to validate_email | app.rb:220:9:220:25 | validation_result | provenance | | +| app.rb:225:13:225:24 | debug_result | app.rb:226:18:226:29 | debug_result | provenance | | +| app.rb:225:13:225:24 | debug_result | app.rb:226:18:226:29 | debug_result | provenance | | +| app.rb:225:28:225:39 | call to debug_helper | app.rb:225:13:225:24 | debug_result | provenance | | +| app.rb:225:28:225:39 | call to debug_helper | app.rb:225:13:225:24 | debug_result | provenance | | +| app.rb:230:9:230:21 | rescue_result | app.rb:231:14:231:26 | rescue_result | provenance | | +| app.rb:230:9:230:21 | rescue_result | app.rb:231:14:231:26 | rescue_result | provenance | | +| app.rb:230:25:230:37 | call to rescue_helper | app.rb:230:9:230:21 | rescue_result | provenance | | +| app.rb:230:25:230:37 | call to rescue_helper | app.rb:230:9:230:21 | rescue_result | provenance | | +| app.rb:235:13:235:23 | case_result | app.rb:236:18:236:28 | case_result | provenance | | +| app.rb:235:13:235:23 | case_result | app.rb:236:18:236:28 | case_result | provenance | | +| app.rb:235:27:235:37 | call to test_helper | app.rb:235:13:235:23 | case_result | provenance | | +| app.rb:235:27:235:37 | call to test_helper | app.rb:235:13:235:23 | case_result | provenance | | nodes | app.rb:103:13:103:18 | call to params | semmle.label | call to params | | app.rb:103:13:103:70 | call to select | semmle.label | call to select | @@ -48,58 +84,118 @@ nodes | app.rb:107:13:107:32 | call to source | semmle.label | call to source | | app.rb:111:13:111:33 | call to source | semmle.label | call to source | | app.rb:111:13:111:33 | call to source | semmle.label | call to source | -| app.rb:126:9:126:15 | user_id | semmle.label | user_id | -| app.rb:126:19:126:24 | call to params | semmle.label | call to params | -| app.rb:126:19:126:34 | ...[...] | semmle.label | ...[...] | -| app.rb:127:9:127:16 | route_id | semmle.label | route_id | -| app.rb:127:20:127:40 | call to route_param | semmle.label | call to route_param | -| app.rb:128:9:128:12 | auth | semmle.label | auth | -| app.rb:128:16:128:22 | call to headers | semmle.label | call to headers | -| app.rb:128:16:128:38 | ...[...] | semmle.label | ...[...] | -| app.rb:129:9:129:15 | session | semmle.label | session | -| app.rb:129:19:129:25 | call to cookies | semmle.label | call to cookies | -| app.rb:129:19:129:38 | ...[...] | semmle.label | ...[...] | -| app.rb:133:14:133:20 | user_id | semmle.label | user_id | -| app.rb:134:14:134:21 | route_id | semmle.label | route_id | -| app.rb:135:14:135:17 | auth | semmle.label | auth | -| app.rb:136:14:136:20 | session | semmle.label | session | -| app.rb:143:9:143:14 | result | semmle.label | result | -| app.rb:143:9:143:14 | result | semmle.label | result | -| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | -| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | -| app.rb:144:14:144:19 | result | semmle.label | result | -| app.rb:144:14:144:19 | result | semmle.label | result | -| app.rb:149:9:149:17 | user_data | semmle.label | user_data | -| app.rb:149:9:149:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | -| app.rb:149:21:149:31 | call to user_params | semmle.label | call to user_params | -| app.rb:149:21:149:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | -| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result | -| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result | -| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper | -| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper | -| app.rb:151:14:151:22 | user_data | semmle.label | user_data | -| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result | -| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result | -| app.rb:159:13:159:19 | user_id | semmle.label | user_id | -| app.rb:159:23:159:28 | call to params | semmle.label | call to params | -| app.rb:159:23:159:33 | ...[...] | semmle.label | ...[...] | -| app.rb:160:18:160:24 | user_id | semmle.label | user_id | -| app.rb:165:9:165:17 | user_data | semmle.label | user_data | -| app.rb:165:9:165:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | -| app.rb:165:21:165:31 | call to user_params | semmle.label | call to user_params | -| app.rb:165:21:165:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | -| app.rb:166:14:166:22 | user_data | semmle.label | user_data | +| app.rb:118:17:118:43 | call to source | semmle.label | call to source | +| app.rb:118:17:118:43 | call to source | semmle.label | call to source | +| app.rb:122:17:122:47 | call to source | semmle.label | call to source | +| app.rb:122:17:122:47 | call to source | semmle.label | call to source | +| app.rb:128:17:128:42 | call to source | semmle.label | call to source | +| app.rb:128:17:128:42 | call to source | semmle.label | call to source | +| app.rb:134:17:134:42 | call to source | semmle.label | call to source | +| app.rb:134:17:134:42 | call to source | semmle.label | call to source | +| app.rb:140:17:140:37 | call to source | semmle.label | call to source | +| app.rb:140:17:140:37 | call to source | semmle.label | call to source | +| app.rb:150:17:150:35 | call to source | semmle.label | call to source | +| app.rb:150:17:150:35 | call to source | semmle.label | call to source | +| app.rb:166:9:166:15 | user_id | semmle.label | user_id | +| app.rb:166:19:166:24 | call to params | semmle.label | call to params | +| app.rb:166:19:166:34 | ...[...] | semmle.label | ...[...] | +| app.rb:167:9:167:16 | route_id | semmle.label | route_id | +| app.rb:167:20:167:40 | call to route_param | semmle.label | call to route_param | +| app.rb:168:9:168:12 | auth | semmle.label | auth | +| app.rb:168:16:168:22 | call to headers | semmle.label | call to headers | +| app.rb:168:16:168:38 | ...[...] | semmle.label | ...[...] | +| app.rb:169:9:169:15 | session | semmle.label | session | +| app.rb:169:19:169:25 | call to cookies | semmle.label | call to cookies | +| app.rb:169:19:169:38 | ...[...] | semmle.label | ...[...] | +| app.rb:173:14:173:20 | user_id | semmle.label | user_id | +| app.rb:174:14:174:21 | route_id | semmle.label | route_id | +| app.rb:175:14:175:17 | auth | semmle.label | auth | +| app.rb:176:14:176:20 | session | semmle.label | session | +| app.rb:183:9:183:14 | result | semmle.label | result | +| app.rb:183:9:183:14 | result | semmle.label | result | +| app.rb:183:18:183:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | +| app.rb:183:18:183:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper | +| app.rb:184:14:184:19 | result | semmle.label | result | +| app.rb:184:14:184:19 | result | semmle.label | result | +| app.rb:189:9:189:17 | user_data | semmle.label | user_data | +| app.rb:189:9:189:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | +| app.rb:189:21:189:31 | call to user_params | semmle.label | call to user_params | +| app.rb:189:21:189:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | +| app.rb:190:9:190:21 | simple_result | semmle.label | simple_result | +| app.rb:190:9:190:21 | simple_result | semmle.label | simple_result | +| app.rb:190:25:190:37 | call to simple_helper | semmle.label | call to simple_helper | +| app.rb:190:25:190:37 | call to simple_helper | semmle.label | call to simple_helper | +| app.rb:191:14:191:22 | user_data | semmle.label | user_data | +| app.rb:192:14:192:26 | simple_result | semmle.label | simple_result | +| app.rb:192:14:192:26 | simple_result | semmle.label | simple_result | +| app.rb:199:13:199:19 | user_id | semmle.label | user_id | +| app.rb:199:23:199:28 | call to params | semmle.label | call to params | +| app.rb:199:23:199:33 | ...[...] | semmle.label | ...[...] | +| app.rb:200:18:200:24 | user_id | semmle.label | user_id | +| app.rb:205:9:205:17 | user_data | semmle.label | user_data | +| app.rb:205:9:205:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] | +| app.rb:205:21:205:31 | call to user_params | semmle.label | call to user_params | +| app.rb:205:21:205:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] | +| app.rb:206:14:206:22 | user_data | semmle.label | user_data | +| app.rb:212:9:212:19 | auth_result | semmle.label | auth_result | +| app.rb:212:9:212:19 | auth_result | semmle.label | auth_result | +| app.rb:212:23:212:39 | call to authenticate_user | semmle.label | call to authenticate_user | +| app.rb:212:23:212:39 | call to authenticate_user | semmle.label | call to authenticate_user | +| app.rb:213:14:213:24 | auth_result | semmle.label | auth_result | +| app.rb:213:14:213:24 | auth_result | semmle.label | auth_result | +| app.rb:216:9:216:19 | perm_result | semmle.label | perm_result | +| app.rb:216:9:216:19 | perm_result | semmle.label | perm_result | +| app.rb:216:23:216:48 | call to check_permissions | semmle.label | call to check_permissions | +| app.rb:216:23:216:48 | call to check_permissions | semmle.label | call to check_permissions | +| app.rb:217:14:217:24 | perm_result | semmle.label | perm_result | +| app.rb:217:14:217:24 | perm_result | semmle.label | perm_result | +| app.rb:220:9:220:25 | validation_result | semmle.label | validation_result | +| app.rb:220:9:220:25 | validation_result | semmle.label | validation_result | +| app.rb:220:29:220:80 | call to validate_email | semmle.label | call to validate_email | +| app.rb:220:29:220:80 | call to validate_email | semmle.label | call to validate_email | +| app.rb:221:14:221:30 | validation_result | semmle.label | validation_result | +| app.rb:221:14:221:30 | validation_result | semmle.label | validation_result | +| app.rb:225:13:225:24 | debug_result | semmle.label | debug_result | +| app.rb:225:13:225:24 | debug_result | semmle.label | debug_result | +| app.rb:225:28:225:39 | call to debug_helper | semmle.label | call to debug_helper | +| app.rb:225:28:225:39 | call to debug_helper | semmle.label | call to debug_helper | +| app.rb:226:18:226:29 | debug_result | semmle.label | debug_result | +| app.rb:226:18:226:29 | debug_result | semmle.label | debug_result | +| app.rb:230:9:230:21 | rescue_result | semmle.label | rescue_result | +| app.rb:230:9:230:21 | rescue_result | semmle.label | rescue_result | +| app.rb:230:25:230:37 | call to rescue_helper | semmle.label | call to rescue_helper | +| app.rb:230:25:230:37 | call to rescue_helper | semmle.label | call to rescue_helper | +| app.rb:231:14:231:26 | rescue_result | semmle.label | rescue_result | +| app.rb:231:14:231:26 | rescue_result | semmle.label | rescue_result | +| app.rb:235:13:235:23 | case_result | semmle.label | case_result | +| app.rb:235:13:235:23 | case_result | semmle.label | case_result | +| app.rb:235:27:235:37 | call to test_helper | semmle.label | call to test_helper | +| app.rb:235:27:235:37 | call to test_helper | semmle.label | call to test_helper | +| app.rb:236:18:236:28 | case_result | semmle.label | case_result | +| app.rb:236:18:236:28 | case_result | semmle.label | case_result | subpaths testFailures #select -| app.rb:133:14:133:20 | user_id | app.rb:126:19:126:24 | call to params | app.rb:133:14:133:20 | user_id | $@ | app.rb:126:19:126:24 | call to params | call to params | -| app.rb:134:14:134:21 | route_id | app.rb:127:20:127:40 | call to route_param | app.rb:134:14:134:21 | route_id | $@ | app.rb:127:20:127:40 | call to route_param | call to route_param | -| app.rb:135:14:135:17 | auth | app.rb:128:16:128:22 | call to headers | app.rb:135:14:135:17 | auth | $@ | app.rb:128:16:128:22 | call to headers | call to headers | -| app.rb:136:14:136:20 | session | app.rb:129:19:129:25 | call to cookies | app.rb:136:14:136:20 | session | $@ | app.rb:129:19:129:25 | call to cookies | call to cookies | -| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | -| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | -| app.rb:151:14:151:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:151:14:151:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | -| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | -| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | -| app.rb:160:18:160:24 | user_id | app.rb:159:23:159:28 | call to params | app.rb:160:18:160:24 | user_id | $@ | app.rb:159:23:159:28 | call to params | call to params | -| app.rb:166:14:166:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:166:14:166:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | +| app.rb:173:14:173:20 | user_id | app.rb:166:19:166:24 | call to params | app.rb:173:14:173:20 | user_id | $@ | app.rb:166:19:166:24 | call to params | call to params | +| app.rb:174:14:174:21 | route_id | app.rb:167:20:167:40 | call to route_param | app.rb:174:14:174:21 | route_id | $@ | app.rb:167:20:167:40 | call to route_param | call to route_param | +| app.rb:175:14:175:17 | auth | app.rb:168:16:168:22 | call to headers | app.rb:175:14:175:17 | auth | $@ | app.rb:168:16:168:22 | call to headers | call to headers | +| app.rb:176:14:176:20 | session | app.rb:169:19:169:25 | call to cookies | app.rb:176:14:176:20 | session | $@ | app.rb:169:19:169:25 | call to cookies | call to cookies | +| app.rb:184:14:184:19 | result | app.rb:107:13:107:32 | call to source | app.rb:184:14:184:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | +| app.rb:184:14:184:19 | result | app.rb:107:13:107:32 | call to source | app.rb:184:14:184:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source | +| app.rb:191:14:191:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:191:14:191:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | +| app.rb:192:14:192:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:192:14:192:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | +| app.rb:192:14:192:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:192:14:192:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source | +| app.rb:200:18:200:24 | user_id | app.rb:199:23:199:28 | call to params | app.rb:200:18:200:24 | user_id | $@ | app.rb:199:23:199:28 | call to params | call to params | +| app.rb:206:14:206:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:206:14:206:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params | +| app.rb:213:14:213:24 | auth_result | app.rb:118:17:118:43 | call to source | app.rb:213:14:213:24 | auth_result | $@ | app.rb:118:17:118:43 | call to source | call to source | +| app.rb:213:14:213:24 | auth_result | app.rb:118:17:118:43 | call to source | app.rb:213:14:213:24 | auth_result | $@ | app.rb:118:17:118:43 | call to source | call to source | +| app.rb:217:14:217:24 | perm_result | app.rb:122:17:122:47 | call to source | app.rb:217:14:217:24 | perm_result | $@ | app.rb:122:17:122:47 | call to source | call to source | +| app.rb:217:14:217:24 | perm_result | app.rb:122:17:122:47 | call to source | app.rb:217:14:217:24 | perm_result | $@ | app.rb:122:17:122:47 | call to source | call to source | +| app.rb:221:14:221:30 | validation_result | app.rb:128:17:128:42 | call to source | app.rb:221:14:221:30 | validation_result | $@ | app.rb:128:17:128:42 | call to source | call to source | +| app.rb:221:14:221:30 | validation_result | app.rb:128:17:128:42 | call to source | app.rb:221:14:221:30 | validation_result | $@ | app.rb:128:17:128:42 | call to source | call to source | +| app.rb:226:18:226:29 | debug_result | app.rb:134:17:134:42 | call to source | app.rb:226:18:226:29 | debug_result | $@ | app.rb:134:17:134:42 | call to source | call to source | +| app.rb:226:18:226:29 | debug_result | app.rb:134:17:134:42 | call to source | app.rb:226:18:226:29 | debug_result | $@ | app.rb:134:17:134:42 | call to source | call to source | +| app.rb:231:14:231:26 | rescue_result | app.rb:140:17:140:37 | call to source | app.rb:231:14:231:26 | rescue_result | $@ | app.rb:140:17:140:37 | call to source | call to source | +| app.rb:231:14:231:26 | rescue_result | app.rb:140:17:140:37 | call to source | app.rb:231:14:231:26 | rescue_result | $@ | app.rb:140:17:140:37 | call to source | call to source | +| app.rb:236:18:236:28 | case_result | app.rb:150:17:150:35 | call to source | app.rb:236:18:236:28 | case_result | $@ | app.rb:150:17:150:35 | call to source | call to source | +| app.rb:236:18:236:28 | case_result | app.rb:150:17:150:35 | call to source | app.rb:236:18:236:28 | case_result | $@ | app.rb:150:17:150:35 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected index d39d9430f92..7088eeb9018 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.expected +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.expected @@ -1,7 +1,7 @@ grapeApiClasses | app.rb:1:1:90:3 | MyAPI | | app.rb:92:1:96:3 | AdminAPI | -| app.rb:98:1:168:3 | UserAPI | +| app.rb:98:1:239:3 | UserAPI | grapeEndpoints | app.rb:1:1:90:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name | | app.rb:1:1:90:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages | @@ -14,10 +14,11 @@ grapeEndpoints | app.rb:1:1:90:3 | MyAPI | app.rb:78:3:82:5 | call to get | GET | /cookie_test | | app.rb:1:1:90:3 | MyAPI | app.rb:85:3:89:5 | call to get | GET | /header_test | | app.rb:92:1:96:3 | AdminAPI | app.rb:93:3:95:5 | call to get | GET | /admin | -| app.rb:98:1:168:3 | UserAPI | app.rb:124:5:138:7 | call to get | GET | /comprehensive_test/:user_id | -| app.rb:98:1:168:3 | UserAPI | app.rb:140:5:145:7 | call to get | GET | /helper_test/:user_id | -| app.rb:98:1:168:3 | UserAPI | app.rb:147:5:153:7 | call to post | POST | /users | -| app.rb:98:1:168:3 | UserAPI | app.rb:164:5:167:7 | call to post | POST | /users | +| app.rb:98:1:239:3 | UserAPI | app.rb:164:5:178:7 | call to get | GET | /comprehensive_test/:user_id | +| app.rb:98:1:239:3 | UserAPI | app.rb:180:5:185:7 | call to get | GET | /helper_test/:user_id | +| app.rb:98:1:239:3 | UserAPI | app.rb:187:5:193:7 | call to post | POST | /users | +| app.rb:98:1:239:3 | UserAPI | app.rb:204:5:207:7 | call to post | POST | /users | +| app.rb:98:1:239:3 | UserAPI | app.rb:210:5:238:7 | call to get | GET | /nested_test/:token | grapeParams | app.rb:8:12:8:17 | call to params | | app.rb:14:3:16:5 | call to params | @@ -28,29 +29,30 @@ grapeParams | app.rb:60:12:60:17 | call to params | | app.rb:94:5:94:10 | call to params | | app.rb:103:13:103:18 | call to params | -| app.rb:126:19:126:24 | call to params | -| app.rb:142:19:142:24 | call to params | -| app.rb:159:23:159:28 | call to params | +| app.rb:117:25:117:30 | call to params | +| app.rb:166:19:166:24 | call to params | +| app.rb:182:19:182:24 | call to params | +| app.rb:199:23:199:28 | call to params | grapeHeaders | app.rb:9:18:9:24 | call to headers | | app.rb:46:5:46:11 | call to headers | | app.rb:66:3:69:5 | call to headers | | app.rb:86:12:86:18 | call to headers | | app.rb:87:14:87:20 | call to headers | -| app.rb:116:5:118:7 | call to headers | -| app.rb:128:16:128:22 | call to headers | +| app.rb:156:5:158:7 | call to headers | +| app.rb:168:16:168:22 | call to headers | grapeRequest | app.rb:25:12:25:18 | call to request | -| app.rb:130:21:130:27 | call to request | +| app.rb:170:21:170:27 | call to request | grapeRouteParam | app.rb:51:15:51:35 | call to route_param | | app.rb:52:15:52:36 | call to route_param | | app.rb:57:3:63:5 | call to route_param | -| app.rb:127:20:127:40 | call to route_param | -| app.rb:156:5:162:7 | call to route_param | +| app.rb:167:20:167:40 | call to route_param | +| app.rb:196:5:202:7 | call to route_param | grapeCookies | app.rb:72:3:75:5 | call to cookies | | app.rb:79:15:79:21 | call to cookies | | app.rb:80:16:80:22 | call to cookies | -| app.rb:120:5:122:7 | call to cookies | -| app.rb:129:19:129:25 | call to cookies | +| app.rb:160:5:162:7 | call to cookies | +| app.rb:169:19:169:25 | call to cookies | diff --git a/ruby/ql/test/library-tests/frameworks/grape/app.rb b/ruby/ql/test/library-tests/frameworks/grape/app.rb index 81f46482687..1b1fd15d5d8 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/app.rb +++ b/ruby/ql/test/library-tests/frameworks/grape/app.rb @@ -110,6 +110,46 @@ class UserAPI < Grape::API def simple_helper source "simpleHelper" # Test simple helper return end + + # Nested helper scenarios that require getParent+() + module AuthHelpers + def authenticate_user + token = params[:token] + source "nestedModuleHelper" # Test nested module helper + end + + def check_permissions(resource) + source "nestedPermissionHelper" # Test nested module helper with params + end + end + + class ValidationHelpers + def self.validate_email(email) + source "nestedClassHelper" # Test nested class helper + end + end + + if Rails.env.development? + def debug_helper + source "conditionalHelper" # Test helper inside conditional block + end + end + + begin + def rescue_helper + source "rescueHelper" # Test helper inside begin block + end + rescue + # error handling + end + + # Helper inside a case statement + case ENV['RACK_ENV'] + when 'test' + def test_helper + source "caseHelper" # Test helper inside case block + end + end end # Headers and cookies blocks for DSL testing @@ -165,4 +205,35 @@ class UserAPI < Grape::API user_data = user_params sink user_data # $ hasTaintFlow end + + # Test nested helper methods + get '/nested_test/:token' do + # Test nested module helper + auth_result = authenticate_user + sink auth_result # $ hasValueFlow=nestedModuleHelper + + # Test nested module helper with parameters + perm_result = check_permissions("admin") + sink perm_result # $ hasValueFlow=nestedPermissionHelper + + # Test nested class helper + validation_result = ValidationHelpers.validate_email("test@example.com") + sink validation_result # $ hasValueFlow=nestedClassHelper + + # Test conditional helper (if it exists) + if respond_to?(:debug_helper) + debug_result = debug_helper + sink debug_result # $ hasValueFlow=conditionalHelper + end + + # Test rescue helper + rescue_result = rescue_helper + sink rescue_result # $ hasValueFlow=rescueHelper + + # Test case helper (if it exists) + if respond_to?(:test_helper) + case_result = test_helper + sink case_result # $ hasValueFlow=caseHelper + end + end end From 6e56c549b2600540306812048ead37ed53dd37bc Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:21:23 -0400 Subject: [PATCH 47/90] Refactor Grape method call classes to simplify handling of API instance calls for headers, request, route_param, and cookies --- ruby/ql/lib/codeql/ruby/frameworks/Grape.qll | 28 +++----------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll index 4d64e9461b3..9b7ae6185cd 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Grape.qll @@ -163,12 +163,7 @@ module Grape { */ private class GrapeHeadersCall extends MethodCall { GrapeHeadersCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "headers" - ) - or - // Also handle cases where headers is called on an instance of a Grape API class + // Handle cases where headers is called on an instance of a Grape API class this = grapeApiInstance().getAMethodCall("headers").asExpr().getExpr() } } @@ -206,12 +201,7 @@ module Grape { */ private class GrapeRequestCall extends MethodCall { GrapeRequestCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "request" - ) - or - // Also handle cases where request is called on an instance of a Grape API class + // Handle cases where request is called on an instance of a Grape API class this = grapeApiInstance().getAMethodCall("request").asExpr().getExpr() } } @@ -221,12 +211,7 @@ module Grape { */ private class GrapeRouteParamCall extends MethodCall { GrapeRouteParamCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asExpr().getExpr() and - this.getMethodName() = "route_param" - ) - or - // Also handle cases where route_param is called on an instance of a Grape API class + // Handle cases where route_param is called on an instance of a Grape API class this = grapeApiInstance().getAMethodCall("route_param").asExpr().getExpr() } } @@ -274,12 +259,7 @@ module Grape { */ private class GrapeCookiesCall extends MethodCall { GrapeCookiesCall() { - exists(GrapeEndpoint endpoint | - this.getParent+() = endpoint.getBody().asCallableAstNode() and - this.getMethodName() = "cookies" - ) - or - // Also handle cases where cookies is called on an instance of a Grape API class + // Handle cases where cookies is called on an instance of a Grape API class this = grapeApiInstance().getAMethodCall("cookies").asExpr().getExpr() } } From 89fd9694cef692446e54e71a730abf1d427b7627 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:25:05 -0400 Subject: [PATCH 48/90] codeql query format --- ruby/ql/test/library-tests/frameworks/grape/Grape.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql index c5f0798f7a6..63cd15a547e 100644 --- a/ruby/ql/test/library-tests/frameworks/grape/Grape.ql +++ b/ruby/ql/test/library-tests/frameworks/grape/Grape.ql @@ -5,7 +5,9 @@ import codeql.ruby.AST query predicate grapeApiClasses(Grape::GrapeApiClass api) { any() } -query predicate grapeEndpoints(Grape::GrapeApiClass api, Grape::GrapeEndpoint endpoint, string method, string path) { +query predicate grapeEndpoints( + Grape::GrapeApiClass api, Grape::GrapeEndpoint endpoint, string method, string path +) { endpoint = api.getAnEndpoint() and method = endpoint.getHttpMethod() and path = endpoint.getPath() From 718c0abdb6fe073349de892ddbbc383b404de607 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 23 Sep 2025 10:31:28 +0200 Subject: [PATCH 49/90] Overlay: Discard base config entities in overlay extracted files --- java/ql/lib/semmle/code/java/Overlay.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/java/ql/lib/semmle/code/java/Overlay.qll b/java/ql/lib/semmle/code/java/Overlay.qll index 0f6033d87b3..31a1518fc59 100644 --- a/java/ql/lib/semmle/code/java/Overlay.qll +++ b/java/ql/lib/semmle/code/java/Overlay.qll @@ -88,7 +88,17 @@ private string baseConfigLocatable(@configLocatable el) { not isOverlay() and result = getRawFileForConfig(el) } +overlay[local] +private predicate overlayConfigExtracted(string file) { + isOverlay() and + exists(@configLocatable el | file = getRawFileForConfig(el)) +} + overlay[discard_entity] private predicate discardBaseConfigLocatable(@configLocatable el) { overlayChangedFiles(baseConfigLocatable(el)) + or + // The config extractor is currently not incremental and may extract more + // property files than those included in overlayChangedFiles. + overlayConfigExtracted(baseConfigLocatable(el)) } From f02da68c55b450687aab8235b725f58139169fe5 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 23 Sep 2025 10:34:49 +0200 Subject: [PATCH 50/90] Overlay: Discard base XML entities in overlay extracted files --- java/ql/lib/semmle/code/java/Overlay.qll | 28 ++++++++++++++++++++++++ java/ql/lib/semmle/code/xml/XML.qll | 10 ++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Overlay.qll b/java/ql/lib/semmle/code/java/Overlay.qll index 31a1518fc59..b5f7264eb3d 100644 --- a/java/ql/lib/semmle/code/java/Overlay.qll +++ b/java/ql/lib/semmle/code/java/Overlay.qll @@ -102,3 +102,31 @@ private predicate discardBaseConfigLocatable(@configLocatable el) { // property files than those included in overlayChangedFiles. overlayConfigExtracted(baseConfigLocatable(el)) } + +/** + * An `@xmllocatable` that should be discarded in the base variant if its file is + * extracted in the overlay variant. + */ +overlay[local] +abstract class DiscardableXmlLocatable extends @xmllocatable { + /** Gets the raw file for an xmllocatable in base. */ + string getRawFileInBase() { not isOverlay() and result = getRawFile(this) } + + /** Gets a textual representation of this discardable xmllocatable. */ + string toString() { none() } +} + +overlay[local] +private predicate overlayXmlExtracted(string file) { + isOverlay() and + exists(@xmllocatable el | not files(el, _) and not xmlNs(el, _, _, _) and file = getRawFile(el)) +} + +overlay[discard_entity] +private predicate discardXmlLocatable(@xmllocatable el) { + overlayChangedFiles(el.(DiscardableXmlLocatable).getRawFileInBase()) + or + // The XML extractor is currently not incremental and may extract more + // XML files than those included in overlayChangedFiles. + overlayXmlExtracted(el.(DiscardableXmlLocatable).getRawFileInBase()) +} diff --git a/java/ql/lib/semmle/code/xml/XML.qll b/java/ql/lib/semmle/code/xml/XML.qll index cd00991eb65..d13a83e7798 100644 --- a/java/ql/lib/semmle/code/xml/XML.qll +++ b/java/ql/lib/semmle/code/xml/XML.qll @@ -71,12 +71,12 @@ private module Input implements InputSig { import Make -private class DiscardableXmlAttribute extends DiscardableLocatable, @xmlattribute { } +private class DiscardableXmlAttribute extends DiscardableXmlLocatable, @xmlattribute { } -private class DiscardableXmlElement extends DiscardableLocatable, @xmlelement { } +private class DiscardableXmlElement extends DiscardableXmlLocatable, @xmlelement { } -private class DiscardableXmlComment extends DiscardableLocatable, @xmlcomment { } +private class DiscardableXmlComment extends DiscardableXmlLocatable, @xmlcomment { } -private class DiscardableXmlCharacters extends DiscardableLocatable, @xmlcharacters { } +private class DiscardableXmlCharacters extends DiscardableXmlLocatable, @xmlcharacters { } -private class DiscardableXmlDtd extends DiscardableLocatable, @xmldtd { } +private class DiscardableXmlDtd extends DiscardableXmlLocatable, @xmldtd { } From 37e0c3084278fd5a326b7021eaf73b08d1be801f Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:40:30 -0400 Subject: [PATCH 51/90] Add expected output for VariablesConsistency test case --- .../grape/CONSISTENCY/VariablesConsistency.expected | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/test/library-tests/frameworks/grape/CONSISTENCY/VariablesConsistency.expected diff --git a/ruby/ql/test/library-tests/frameworks/grape/CONSISTENCY/VariablesConsistency.expected b/ruby/ql/test/library-tests/frameworks/grape/CONSISTENCY/VariablesConsistency.expected new file mode 100644 index 00000000000..edcc754b792 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/grape/CONSISTENCY/VariablesConsistency.expected @@ -0,0 +1,4 @@ +variableIsCaptured +| app.rb:126:9:130:11 | self | CapturedVariable is not captured | +consistencyOverview +| CapturedVariable is not captured | 1 | From e6b1e8ec561059d45b828e89e5c09e3f1274f63e Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 22 Sep 2025 14:35:27 +0200 Subject: [PATCH 52/90] Rust: Check call arities in path resolution --- .../internal/ControlFlowGraphImpl.qll | 2 +- .../rust/elements/internal/CallImpl.qll | 2 +- .../rust/elements/internal/CallableImpl.qll | 10 ++++ .../rust/elements/internal/VariableImpl.qll | 2 +- .../codeql/rust/internal/PathResolution.qll | 40 +++++++++++-- .../codeql/rust/internal/TypeInference.qll | 12 ++-- .../PathResolutionConsistency.expected | 5 -- .../PathResolutionConsistency.expected | 10 ---- .../HardcodedCryptographicValue.expected | 59 +++++++------------ 9 files changed, 75 insertions(+), 67 deletions(-) delete mode 100644 rust/ql/test/query-tests/security/CWE-798/CONSISTENCY/PathResolutionConsistency.expected diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index ddc4dae9b95..f87daaaf51a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -77,7 +77,7 @@ class CallableScopeTree extends StandardTree, PreOrderTree, PostOrderTree, Scope override AstNode getChildNode(int i) { i = 0 and - result = this.getParamList().getSelfParam() + result = this.getSelfParam() or result = this.getParam(i - 1) or diff --git a/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll index 020b50594a6..210820fd105 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll @@ -102,7 +102,7 @@ module Impl { f = resolvePath(path) and path.getSegment().getIdentifier().getText() = methodName and exists(SelfParam self | - self = f.getParamList().getSelfParam() and + self = f.getSelfParam() and if self.isRef() then selfIsRef = true else selfIsRef = false ) ) diff --git a/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll index 37e24a9150c..46489cab981 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll @@ -17,5 +17,15 @@ module Impl { */ class Callable extends Generated::Callable { override Param getParam(int index) { result = this.getParamList().getParam(index) } + + /** + * Gets the self parameter of this callable, if it exists. + */ + SelfParam getSelfParam() { result = this.getParamList().getSelfParam() } + + /** + * Holds if `getSelfParam()` exists. + */ + predicate hasSelfParam() { exists(this.getSelfParam()) } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll index eaced654b01..80569281721 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll @@ -109,7 +109,7 @@ module Impl { text = name.getText() and // exclude self parameters from functions without a body as these are // trait method declarations without implementations - not exists(Function f | not f.hasBody() and f.getParamList().getSelfParam() = sp) + not exists(Function f | not f.hasBody() and f.getSelfParam() = sp) ) or exists(IdentPat pat | diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index efd614db63a..4b368308878 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -4,6 +4,7 @@ private import rust private import codeql.rust.elements.internal.generated.ParentChild +private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl private import codeql.rust.internal.CachedStages private import codeql.rust.frameworks.stdlib.Builtins as Builtins private import codeql.util.Option @@ -604,7 +605,13 @@ private class EnumItemNode extends TypeItemNode instanceof Enum { } } -private class VariantItemNode extends ItemNode instanceof Variant { +/** An item that can be called with arguments. */ +abstract class CallableItemNode extends ItemNode { + /** Gets the number of parameters of this item. */ + abstract int getNumberOfParameters(); +} + +private class VariantItemNode extends CallableItemNode instanceof Variant { override string getName() { result = Variant.super.getName().getText() } override Namespace getNamespace() { @@ -617,6 +624,10 @@ private class VariantItemNode extends ItemNode instanceof Variant { override Visibility getVisibility() { result = super.getEnum().getVisibility() } + override int getNumberOfParameters() { + result = super.getFieldList().(TupleFieldList).getNumberOfFields() + } + override predicate hasCanonicalPath(Crate c) { this.hasCanonicalPathPrefix(c) } bindingset[c] @@ -638,7 +649,7 @@ private class VariantItemNode extends ItemNode instanceof Variant { } } -class FunctionItemNode extends AssocItemNode instanceof Function { +class FunctionItemNode extends AssocItemNode, CallableItemNode instanceof Function { override string getName() { result = Function.super.getName().getText() } override predicate hasImplementation() { Function.super.hasImplementation() } @@ -648,6 +659,13 @@ class FunctionItemNode extends AssocItemNode instanceof Function { override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) } override Visibility getVisibility() { result = Function.super.getVisibility() } + + override int getNumberOfParameters() { + exists(int arr | + arr = super.getNumberOfParams() and + if super.hasSelfParam() then result = arr + 1 else result = arr + ) + } } abstract class ImplOrTraitItemNode extends ItemNode { @@ -712,8 +730,10 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { TypeParamItemNode getBlanketImplementationTypeParam() { result = this.resolveSelfTy() } /** - * Holds if this impl block is a blanket implementation. That is, the + * Holds if this impl block is a [blanket implementation][1]. That is, the * implementation targets a generic parameter of the impl block. + * + * [1]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods */ predicate isBlanketImplementation() { exists(this.getBlanketImplementationTypeParam()) } @@ -865,7 +885,7 @@ private class ImplItemNodeImpl extends ImplItemNode { TraitItemNode resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) } } -private class StructItemNode extends TypeItemNode instanceof Struct { +private class StructItemNode extends TypeItemNode, CallableItemNode instanceof Struct { override string getName() { result = Struct.super.getName().getText() } override Namespace getNamespace() { @@ -877,6 +897,10 @@ private class StructItemNode extends TypeItemNode instanceof Struct { override Visibility getVisibility() { result = Struct.super.getVisibility() } + override int getNumberOfParameters() { + result = super.getFieldList().(TupleFieldList).getNumberOfFields() + } + override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) } override predicate hasCanonicalPath(Crate c) { this.hasCanonicalPathPrefix(c) } @@ -1687,6 +1711,14 @@ private ItemNode resolvePathCand(RelevantPath path) { or not pathUsesNamespace(path, _) and not path = any(MacroCall mc).getPath() + ) and + ( + not path = CallExprImpl::getFunctionPath(_) + or + exists(CallExpr ce | + path = CallExprImpl::getFunctionPath(ce) and + result.(CallableItemNode).getNumberOfParameters() = ce.getNumberOfArgs() + ) ) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 16c0b30332e..48281bd4846 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -230,7 +230,7 @@ module Consistency { // Suppress the inconsistency if `n` is a self parameter and the type // mention for the self type has multiple types for a path. not exists(ImplItemNode impl, TypePath selfTypePath | - n = impl.getAnAssocItem().(Function).getParamList().getSelfParam() and + n = impl.getAnAssocItem().(Function).getSelfParam() and strictcount(impl.(Impl).getSelfTy().(TypeMention).resolveTypeAt(selfTypePath)) > 1 ) } @@ -948,7 +948,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { ) or exists(SelfParam self | - self = pragma[only_bind_into](this.getParamList().getSelfParam()) and + self = pragma[only_bind_into](this.getSelfParam()) and dpos.isSelf() and result = inferAnnotatedType(self, path) // `self` parameter with type annotation ) @@ -972,7 +972,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { exists(ImplOrTraitItemNode i | this = i.getAnAssocItem() and dpos.isSelf() and - not this.getParamList().hasSelfParam() + not this.hasSelfParam() | result = TSelfTypeParameter(i) and path.isEmpty() @@ -1900,7 +1900,7 @@ private predicate methodCandidate(Type type, string name, int arity, Impl impl) type = impl.getSelfTy().(TypeMention).resolveType() and exists(Function f | f = impl.(ImplItemNode).getASuccessor(name) and - f.getParamList().hasSelfParam() and + f.hasSelfParam() and arity = f.getParamList().getNumberOfParams() ) } @@ -2222,7 +2222,7 @@ private module BlanketImplementation { ) { isCanonicalImpl(impl) and blanketImplementationTraitBound(impl, traitBound) and - f.getParamList().hasSelfParam() and + f.hasSelfParam() and arity = f.getParamList().getNumberOfParams() and ( f = impl.getAssocItem(name) @@ -2332,7 +2332,7 @@ private Function resolveMethodCallTarget(MethodCall mc) { pragma[nomagic] private predicate assocFuncResolutionDependsOnArgument(Function f, Impl impl, int pos) { functionResolutionDependsOnArgument(impl, _, f, pos, _, _) and - not f.getParamList().hasSelfParam() + not f.hasSelfParam() } private class FunctionCallExpr extends CallImpl::CallExprCall { diff --git a/rust/ql/test/query-tests/security/CWE-327/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-327/CONSISTENCY/PathResolutionConsistency.expected index 50dd9e9f0ed..b9925a323cc 100644 --- a/rust/ql/test/query-tests/security/CWE-327/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/query-tests/security/CWE-327/CONSISTENCY/PathResolutionConsistency.expected @@ -1,7 +1,2 @@ multipleCallTargets -| test_cipher.rs:20:27:20:48 | ...::new(...) | -| test_cipher.rs:26:27:26:48 | ...::new(...) | -| test_cipher.rs:29:27:29:48 | ...::new(...) | -| test_cipher.rs:36:30:36:59 | ...::new(...) | -| test_cipher.rs:39:30:39:63 | ...::new(...) | | test_cipher.rs:114:23:114:50 | ...::new(...) | diff --git a/rust/ql/test/query-tests/security/CWE-798/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-798/CONSISTENCY/PathResolutionConsistency.expected deleted file mode 100644 index b0ca6300065..00000000000 --- a/rust/ql/test/query-tests/security/CWE-798/CONSISTENCY/PathResolutionConsistency.expected +++ /dev/null @@ -1,10 +0,0 @@ -multipleCallTargets -| test_cipher.rs:15:30:15:77 | ...::new(...) | -| test_cipher.rs:19:30:19:80 | ...::new(...) | -| test_cipher.rs:22:30:22:98 | ...::new(...) | -| test_cipher.rs:26:30:26:101 | ...::new(...) | -| test_cipher.rs:30:30:30:102 | ...::new(...) | -| test_cipher.rs:38:30:38:81 | ...::new(...) | -| test_cipher.rs:42:30:42:80 | ...::new(...) | -| test_cipher.rs:47:30:47:85 | ...::new(...) | -| test_cipher.rs:51:31:51:83 | ...::new(...) | diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index d16be723b8f..3b52014e1fc 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -1,15 +1,9 @@ #select | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | -| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | -| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | -| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | -| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | -| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key | | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key | @@ -22,40 +16,34 @@ edges | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 | +| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 Sink:MaD:6 | -| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | +| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | -| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:9 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | -| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:9 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | -| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:8 | +| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:7 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | @@ -65,41 +53,39 @@ edges | test_cookie.rs:17:9:17:14 | array1 [element] | test_cookie.rs:18:27:18:32 | array1 [element] | provenance | | | test_cookie.rs:17:28:17:34 | [0; 64] [element] | test_cookie.rs:17:9:17:14 | array1 [element] | provenance | | | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:28:17:34 | [0; 64] [element] | provenance | | -| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | +| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:6 Sink:MaD:6 | | test_cookie.rs:18:27:18:32 | array1 [element] | test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | provenance | | | test_cookie.rs:21:9:21:14 | array2 [element] | test_cookie.rs:22:27:22:32 | array2 [element] | provenance | | | test_cookie.rs:21:28:21:34 | [0; 64] [element] | test_cookie.rs:21:9:21:14 | array2 [element] | provenance | | | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:28:21:34 | [0; 64] [element] | provenance | | -| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | +| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:6 Sink:MaD:6 | | test_cookie.rs:22:27:22:32 | array2 [element] | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | provenance | | | test_cookie.rs:38:9:38:14 | array2 [element] | test_cookie.rs:42:34:42:39 | array2 [element] | provenance | | | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | test_cookie.rs:38:9:38:14 | array2 [element] | provenance | | -| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | provenance | MaD:9 | +| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | provenance | MaD:8 | | test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | provenance | | | test_cookie.rs:42:34:42:39 | array2 [element] | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | | test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:11 | +| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:10 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | | | test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | models | 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key | | 2 | Sink: ::from; Argument[0]; credentials-key | | 3 | Sink: ::new; Argument[0]; credentials-key | -| 4 | Sink: ::new; Argument[1]; credentials-iv | -| 5 | Sink: ::new; Argument[0]; credentials-key | -| 6 | Sink: ::new; Argument[1]; credentials-iv | -| 7 | Sink: ::from; Argument[0].Reference; credentials-key | -| 8 | Source: core::mem::zeroed; ReturnValue.Element; constant-source | -| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value | -| 10 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | -| 11 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | +| 4 | Sink: ::new; Argument[0]; credentials-key | +| 5 | Sink: ::new; Argument[1]; credentials-iv | +| 6 | Sink: ::from; Argument[0].Reference; credentials-key | +| 7 | Source: core::mem::zeroed; ReturnValue.Element; constant-source | +| 8 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value | +| 9 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 10 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | | test_cipher.rs:18:30:18:32 | 0u8 | semmle.label | 0u8 | | test_cipher.rs:19:30:19:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:19:30:19:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | @@ -107,7 +93,6 @@ nodes | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | | test_cipher.rs:25:30:25:32 | 0u8 | semmle.label | 0u8 | | test_cipher.rs:26:30:26:40 | ...::new | semmle.label | ...::new | -| test_cipher.rs:26:30:26:40 | ...::new | semmle.label | ...::new | | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | @@ -115,13 +100,11 @@ nodes | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | | test_cipher.rs:29:30:29:32 | 0u8 | semmle.label | 0u8 | | test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | -| test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | | test_cipher.rs:37:9:37:14 | const7 | semmle.label | const7 | | test_cipher.rs:37:27:37:74 | [...] | semmle.label | [...] | | test_cipher.rs:38:30:38:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:38:30:38:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | | test_cipher.rs:38:73:38:79 | &const7 [&ref] | semmle.label | &const7 [&ref] | | test_cipher.rs:38:74:38:79 | const7 | semmle.label | const7 | @@ -129,14 +112,12 @@ nodes | test_cipher.rs:41:28:41:76 | &... [&ref] | semmle.label | &... [&ref] | | test_cipher.rs:41:29:41:76 | [...] | semmle.label | [...] | | test_cipher.rs:42:30:42:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:42:30:42:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | | test_cipher.rs:42:73:42:78 | const8 [&ref] | semmle.label | const8 [&ref] | | test_cipher.rs:50:9:50:15 | const10 [element] | semmle.label | const10 [element] | | test_cipher.rs:50:37:50:52 | ...::zeroed | semmle.label | ...::zeroed | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | semmle.label | ...::zeroed(...) [element] | | test_cipher.rs:51:31:51:48 | ...::new | semmle.label | ...::new | -| test_cipher.rs:51:31:51:48 | ...::new | semmle.label | ...::new | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | semmle.label | &const10 [&ref, element] | | test_cipher.rs:51:75:51:81 | const10 [element] | semmle.label | const10 [element] | From 6e0ce9a88557150e68e504bcbc3b958079a9908c Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Wed, 24 Sep 2025 13:30:11 +0100 Subject: [PATCH 53/90] Add changelog entry for CodeQL 2.23.1 release --- .../codeql-changelog/codeql-cli-2.23.1.rst | 176 ++++++++++++++++++ .../codeql-changelog/index.rst | 1 + 2 files changed, 177 insertions(+) create mode 100644 docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst new file mode 100644 index 00000000000..3b70843b651 --- /dev/null +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -0,0 +1,176 @@ +.. _codeql-cli-2.23.1: + +========================== +CodeQL 2.23.1 (2025-09-23) +========================== + +.. contents:: Contents + :depth: 2 + :local: + :backlinks: none + +This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__. + +Security Coverage +----------------- + +CodeQL 2.23.1 runs a total of 478 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 135 queries (covering 35 more CWE). 3 security queries have been added with this release. + +CodeQL CLI +---------- + +New Features +~~~~~~~~~~~~ + +* CodeQL now adds the sources and sinks of path alerts to the :code:`relatedLocations` property of SARIF results if they are not included as the primary location or within the alert message. This means that path alerts will show on PRs if a source or sink is added or modified, even for queries that don't follow the common convention of selecting the sink as the primary location and mentioning the source in the alert message. + +* CodeQL now populates file coverage information for GitHub Actions on + \ `the tool status page for code scanning `__. + +Query Packs +----------- + +Bug Fixes +~~~~~~~~~ + +C/C++ +""""" + +* The predicate :code:`occurenceCount` in the file module :code:`MagicConstants` has been deprecated. Use :code:`occurrenceCount` instead. +* The predicate :code:`additionalAdditionOrSubstractionCheckForLeapYear` in the file module :code:`LeapYear` has been deprecated. Use :code:`additionalAdditionOrSubtractionCheckForLeapYear` instead. + +C# +"" + +* The message for :code:`csharp/diagnostic/database-quality` has been updated to include detailed database health metrics. Additionally, the threshold for reporting database health issues has been lowered from 95% to 85% (if any metric falls below this percentage). These changes are visible on the tool status page. + +Java/Kotlin +""""""""""" + +* The message for :code:`java/diagnostic/database-quality` has been updated to include detailed database health metrics. Additionally, the threshold for reporting database health issues has been lowered from 95% to 85% (if any metric falls below this percentage). These changes are visible on the tool status page. + +Rust +"""" + +* The message for :code:`rust/diagnostic/database-quality` has been updated to include detailed database health metrics. These changes are visible on the tool status page. + +Major Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* The queries :code:`cpp/wrong-type-format-argument`, :code:`cpp/comparison-with-wider-type`, :code:`cpp/integer-multiplication-cast-to-long`, :code:`cpp/implicit-function-declaration` and :code:`cpp/suspicious-add-sizeof` have had their precisions reduced from :code:`high` to :code:`medium`. They will also now give alerts for projects built with :code:`build-mode: none`. +* The queries :code:`cpp/wrong-type-format-argument`, :code:`cpp/comparison-with-wider-type`, :code:`cpp/integer-multiplication-cast-to-long` and :code:`cpp/suspicious-add-sizeof` are no longer included in the :code:`code-scanning` suite. + +Java/Kotlin +""""""""""" + +* The implementation of :code:`java/dereferenced-value-may-be-null` has been completely replaced with a new general control-flow reachability library. This improves precision by reducing false positives. However, since the entire calculation has been reworked, there can be small corner cases where precision regressions might occur and new false positives may occur, but these cases should be rare. + +JavaScript/TypeScript +""""""""""""""""""""" + +* Added support for TypeScript 5.9 +* Added support for :code:`import defer` syntax in JavaScript and TypeScript. + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +C# +"" + +* The query :code:`cs/call-to-object-tostring` has been improved to remove false positives for enum types. + +JavaScript/TypeScript +""""""""""""""""""""" + +* Data flow is now tracked through the :code:`Promise.try` and :code:`Array.prototype.with` functions. +* Query :code:`js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. +* The query :code:`js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as :code:`Object.keys()`. +* The query "Permissive CORS configuration" (:code:`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. + +Python +"""""" + +* The queries :code:`py/missing-call-to-init`, :code:`py/missing-calls-to-del`, :code:`py/multiple-calls-to-init`, and :code:`py/multiple-calls-to-del` queries have been modernized; no longer relying on outdated libraries, producing more precise results with more descriptive alert messages, and improved documentation. + +GitHub Actions +"""""""""""""" + +* Actions analysis now reports file coverage information on the CodeQL status page. + +Deprecated Queries +~~~~~~~~~~~~~~~~~~ + +C# +"" + +* The query :code:`cs/captured-foreach-variable` has been deprecated as the semantics of capturing a 'foreach' variable and using it outside the loop has been stable since C# version 5. + +New Queries +~~~~~~~~~~~ + +Rust +"""" + +* Added a new query, :code:`rust/request-forgery`, for detecting server-side request forgery vulnerabilities. + +Language Libraries +------------------ + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Golang +"""""" + +* The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\` to the beginning. + +Java/Kotlin +""""""""""" + +* Improved support for various assertion libraries, in particular JUnit. This affects the control-flow graph slightly, and in turn affects several queries (mainly quality queries). Most queries should see improved precision (new true positives and fewer false positives), in particular :code:`java/constant-comparison`, :code:`java/index-out-of-bounds`, :code:`java/dereferenced-value-may-be-null`, and :code:`java/useless-null-check`. Some medium precision queries like :code:`java/toctou-race-condition` and :code:`java/unreleased-lock` may see mixed result changes (both slight improvements and slight regressions). +* Added taint flow model for :code:`java.crypto.KDF`. +* Added taint flow model for :code:`java.lang.ScopedValue`. + +JavaScript/TypeScript +""""""""""""""""""""" + +* Added modeling for promisification libraries :code:`@gar/promisify`, :code:`es6-promisify`, :code:`util.promisify`, :code:`thenify-all`, :code:`call-me-maybe`, :code:`@google-cloud/promisify`, and :code:`util-promisify`. +* Data flow is now tracked through promisified user-defined functions. + +Swift +""""" + +* Updated to allow analysis of Swift 6.1.3. + +Rust +"""" + +* Added cryptography related models for the :code:`cookie` and :code:`biscotti` crates. + +Deprecated APIs +~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* The predicate :code:`getAContructorCall` in the class :code:`SslContextClass` has been deprecated. Use :code:`getAConstructorCall` instead. + +New Features +~~~~~~~~~~~~ + +C/C++ +""""" + +* Added predicates :code:`getTransitiveNumberOfVlaDimensionStmts`, :code:`getTransitiveVlaDimensionStmt`, and :code:`getParentVlaDecl` to :code:`VlaDeclStmt` for handling :code:`VlaDeclStmt`\ s whose base type is defined in terms of another :code:`VlaDeclStmt` via a :code:`typedef`. + +Java/Kotlin +""""""""""" + +* The Java extractor and QL libraries now support Java 25. +* Added support for Java 25 compact source files (JEP 512). The new predicate :code:`Class.isImplicit()` identifies classes that are implicitly declared when using compact source files, and the new predicate :code:`CompilationUnit.isCompactSourceFile()` identifies compilation units that contain compact source files. +* Added support for Java 25 module import declarations. +* Add :code:`ModuleImportDeclaration` class. diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst index 87cd03ebfaf..41230fc72f1 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/index.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst @@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here Date: Fri, 5 Sep 2025 20:27:45 +0100 Subject: [PATCH 54/90] Improve logging to include proxy vars --- go/extractor/util/registryproxy.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index 301d45896d2..fb140cba728 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -113,11 +113,6 @@ func getEnvVars() []string { // Applies private package proxy related environment variables to `cmd`. func ApplyProxyEnvVars(cmd *exec.Cmd) { - slog.Debug( - "Applying private registry proxy environment variables", - slog.String("cmd_args", strings.Join(cmd.Args, " ")), - ) - // If we haven't done so yet, check whether the proxy environment variables are set // and extract information from them. if !proxy_vars_checked { @@ -131,4 +126,10 @@ func ApplyProxyEnvVars(cmd *exec.Cmd) { if proxy_vars != nil { cmd.Env = append(os.Environ(), proxy_vars...) } + + slog.Debug( + "Applying private registry proxy environment variables", + slog.String("cmd_args", strings.Join(cmd.Args, " ")), + slog.String("proxy_vars", strings.Join(proxy_vars, ",")), + ) } From 23a04613c08ef2c5ef75309c4336c4561321461b Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 4 Sep 2025 17:40:38 +0100 Subject: [PATCH 55/90] Set lower-case variants of `HTTP_PROXY` and `HTTPS_PROXY` --- go/extractor/util/registryproxy.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index fb140cba728..c3faab4900a 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -53,7 +53,13 @@ func getEnvVars() []string { if proxy_host, proxy_host_set := os.LookupEnv(PROXY_HOST); proxy_host_set && proxy_host != "" { if proxy_port, proxy_port_set := os.LookupEnv(PROXY_PORT); proxy_port_set && proxy_port != "" { proxy_address = fmt.Sprintf("http://%s:%s", proxy_host, proxy_port) - result = append(result, fmt.Sprintf("HTTP_PROXY=%s", proxy_address), fmt.Sprintf("HTTPS_PROXY=%s", proxy_address)) + result = append( + result, + fmt.Sprintf("HTTP_PROXY=%s", proxy_address), + fmt.Sprintf("HTTPS_PROXY=%s", proxy_address), + fmt.Sprintf("http_proxy=%s", proxy_address), + fmt.Sprintf("https_proxy=%s", proxy_address), + ) slog.Info("Found private registry proxy", slog.String("proxy_address", proxy_address)) } From 895399ff0569686e0b7995e7fadc7ab82e811716 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 4 Sep 2025 15:31:59 +0100 Subject: [PATCH 56/90] Rename `proxy_configs` to `goproxy_servers` and only store URLs --- go/extractor/util/registryproxy.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index c3faab4900a..7ebc3cb508d 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -26,9 +26,8 @@ var proxy_address string // The path to the temporary file that stores the proxy certificate, if any. var proxy_cert_file string -// An array of registry configurations that are relevant to Go. -// This excludes other registry configurations that may be available, but are not relevant to Go. -var proxy_configs []RegistryConfig +// An array of goproxy server URLs. +var goproxy_servers []string // Stores the environment variables that we wish to pass on to `go` commands. var proxy_vars []string = nil @@ -97,16 +96,16 @@ func getEnvVars() []string { // filter others out at this point. for _, cfg := range val { if cfg.Type == GOPROXY_SERVER { - proxy_configs = append(proxy_configs, cfg) + goproxy_servers = append(goproxy_servers, cfg.URL) slog.Info("Found GOPROXY server", slog.String("url", cfg.URL)) } } - if len(proxy_configs) > 0 { + if len(goproxy_servers) > 0 { goproxy_val := "https://proxy.golang.org,direct" - for _, cfg := range proxy_configs { - goproxy_val = cfg.URL + "," + goproxy_val + for _, url := range goproxy_servers { + goproxy_val = url + "," + goproxy_val } result = append(result, fmt.Sprintf("GOPROXY=%s", goproxy_val), "GOPRIVATE=", "GONOPROXY=") From a8fa1a76c482146e9cc59c1d58309e6c0eb02f90 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 4 Sep 2025 15:52:53 +0100 Subject: [PATCH 57/90] Use `git_source` configurations for `GOPRIVATE` --- go/extractor/util/registryproxy.go | 17 ++++++++++++++- go/extractor/util/registryproxy_test.go | 28 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index 7ebc3cb508d..9aa50ca4cc3 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -14,6 +14,7 @@ const PROXY_PORT = "CODEQL_PROXY_PORT" const PROXY_CA_CERTIFICATE = "CODEQL_PROXY_CA_CERTIFICATE" const PROXY_URLS = "CODEQL_PROXY_URLS" const GOPROXY_SERVER = "goproxy_server" +const GIT_SOURCE = "git_source" type RegistryConfig struct { Type string `json:"type"` @@ -29,6 +30,9 @@ var proxy_cert_file string // An array of goproxy server URLs. var goproxy_servers []string +// An array of Git URLs. +var git_sources []string + // Stores the environment variables that we wish to pass on to `go` commands. var proxy_vars []string = nil @@ -98,9 +102,14 @@ func getEnvVars() []string { if cfg.Type == GOPROXY_SERVER { goproxy_servers = append(goproxy_servers, cfg.URL) slog.Info("Found GOPROXY server", slog.String("url", cfg.URL)) + } else if cfg.Type == GIT_SOURCE { + git_sources = append(git_sources, cfg.URL) + slog.Info("Found Git source", slog.String("url", cfg.URL)) } } + goprivate := []string{} + if len(goproxy_servers) > 0 { goproxy_val := "https://proxy.golang.org,direct" @@ -108,8 +117,14 @@ func getEnvVars() []string { goproxy_val = url + "," + goproxy_val } - result = append(result, fmt.Sprintf("GOPROXY=%s", goproxy_val), "GOPRIVATE=", "GONOPROXY=") + result = append(result, fmt.Sprintf("GOPROXY=%s", goproxy_val), "GONOPROXY=") } + + if len(git_sources) > 0 { + goprivate = append(goprivate, git_sources...) + } + + result = append(result, fmt.Sprintf("GOPRIVATE=%s", strings.Join(goprivate, ","))) } } diff --git a/go/extractor/util/registryproxy_test.go b/go/extractor/util/registryproxy_test.go index a21b1a215c1..ef63bd9d3f8 100644 --- a/go/extractor/util/registryproxy_test.go +++ b/go/extractor/util/registryproxy_test.go @@ -47,3 +47,31 @@ func TestParseRegistryConfigs(t *testing.T) { t.Fatalf("Expected `URL` to be `https://proxy.example.com/mod`, but got `%s`", first.URL) } } + +func TestParseRegistryConfigsMultiple(t *testing.T) { + multiple := parseRegistryConfigsSuccess(t, "[{ \"type\": \"git_source\", \"url\": \"https://github.com/github\" }, { \"type\": \"goproxy_server\", \"url\": \"https://proxy.example.com/mod\" }]") + + if len(multiple) != 2 { + t.Fatalf("Expected `parseRegistryConfigs` to return two configurations, but got %d.", len(multiple)) + } + + first := multiple[0] + + if first.Type != "git_source" { + t.Fatalf("Expected `Type` to be `git_source`, but got `%s`", first.Type) + } + + if first.URL != "https://github.com/github" { + t.Fatalf("Expected `URL` to be `https://github.com/github`, but got `%s`", first.URL) + } + + second := multiple[1] + + if second.Type != "goproxy_server" { + t.Fatalf("Expected `Type` to be `goproxy_server`, but got `%s`", second.Type) + } + + if second.URL != "https://proxy.example.com/mod" { + t.Fatalf("Expected `URL` to be `https://proxy.example.com/mod`, but got `%s`", second.URL) + } +} From 4ef8ff9a0fe87940510a2dffe2e1defdfd64c5f2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 5 Sep 2025 20:35:14 +0100 Subject: [PATCH 58/90] Append `*` to `git_source` URL if not present Since `GOPRIVATE` / `GONOPROXY` expect a glob pattern --- go/extractor/util/registryproxy.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index 9aa50ca4cc3..0ba49cb55d6 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -103,7 +103,11 @@ func getEnvVars() []string { goproxy_servers = append(goproxy_servers, cfg.URL) slog.Info("Found GOPROXY server", slog.String("url", cfg.URL)) } else if cfg.Type == GIT_SOURCE { - git_sources = append(git_sources, cfg.URL) + if strings.HasSuffix(cfg.URL, "*") { + git_sources = append(git_sources, cfg.URL) + } else { + git_sources = append(git_sources, cfg.URL+"*") + } slog.Info("Found Git source", slog.String("url", cfg.URL)) } } From bc38b79c9a185d589e16f38f634f878d2995c029 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 5 Sep 2025 22:38:06 +0100 Subject: [PATCH 59/90] Convert URLs to expected format --- go/extractor/util/registryproxy.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index 0ba49cb55d6..3909f9e5cf1 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "log/slog" + "net/url" "os" "os/exec" "strings" @@ -103,12 +104,14 @@ func getEnvVars() []string { goproxy_servers = append(goproxy_servers, cfg.URL) slog.Info("Found GOPROXY server", slog.String("url", cfg.URL)) } else if cfg.Type == GIT_SOURCE { - if strings.HasSuffix(cfg.URL, "*") { - git_sources = append(git_sources, cfg.URL) + parsed, err := url.Parse(cfg.URL) + if err == nil && parsed.Hostname() != "" { + git_source := parsed.Hostname() + parsed.Path + "*" + git_sources = append(git_sources, git_source) + slog.Info("Found Git source", slog.String("source", git_source)) } else { - git_sources = append(git_sources, cfg.URL+"*") + slog.Warn("Not a valid URL for Git source", slog.String("url", cfg.URL)) } - slog.Info("Found Git source", slog.String("url", cfg.URL)) } } From 8c8499229d3dd32440a39909b069235dbbd21e83 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 4 Sep 2025 18:05:38 +0100 Subject: [PATCH 60/90] Configure `git` to use the certificate, if needed --- go/extractor/util/registryproxy.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/go/extractor/util/registryproxy.go b/go/extractor/util/registryproxy.go index 3909f9e5cf1..1f20832e8d8 100644 --- a/go/extractor/util/registryproxy.go +++ b/go/extractor/util/registryproxy.go @@ -129,6 +129,18 @@ func getEnvVars() []string { if len(git_sources) > 0 { goprivate = append(goprivate, git_sources...) + + if proxy_cert_file != "" { + slog.Info("Configuring `git` to use proxy certificate", slog.String("path", proxy_cert_file)) + cmd := exec.Command("git", "config", "--global", "http.sslCAInfo", proxy_cert_file) + + out, cmdErr := cmd.CombinedOutput() + slog.Info(string(out)) + + if cmdErr != nil { + slog.Error("Failed to configure `git` to accept the certificate file", slog.String("error", cmdErr.Error())) + } + } } result = append(result, fmt.Sprintf("GOPRIVATE=%s", strings.Join(goprivate, ","))) From 8ad6952ddaa99736b3ac42a6504b78841cc616f3 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Wed, 24 Sep 2025 15:58:09 +0100 Subject: [PATCH 61/90] Fix escape character in changelog for Go query --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 3b70843b651..18623d63c45 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\` to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\\` to the beginning. Java/Kotlin """"""""""" From f3ef6ef3c978b8585e917661b1030c5dd581a4f2 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Wed, 24 Sep 2025 16:00:40 +0100 Subject: [PATCH 62/90] Fix formatting issue in changelog for Go query --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 18623d63c45..95952ee4ac9 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\\` to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:\ to the beginning. Java/Kotlin """"""""""" From 6c488e6e71d4ae10227ebe496f7e29b68dc2b347 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Wed, 24 Sep 2025 16:01:38 +0100 Subject: [PATCH 63/90] Fix formatting in codeql-cli-2.23.1.rst --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 95952ee4ac9..67f4ee93e9f 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:\ to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:\`` to the beginning. Java/Kotlin """"""""""" From 86fe68bb61367e57e4831d7ea93eaf6ca65b1888 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Wed, 24 Sep 2025 16:12:17 +0100 Subject: [PATCH 64/90] Fix formatting in changelog for Go path injection query 2 people + 2 models managed to tackle this insurmountable task. --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 67f4ee93e9f..3767c877b5a 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:\`` to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\ ` to the beginning. Java/Kotlin """"""""""" From e41b5f2bc0ef6507c0a2873a8b592bd3cd01c681 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 25 Sep 2025 09:52:22 +0200 Subject: [PATCH 65/90] C++: Update tests after extractor changes --- cpp/ql/test/library-tests/permissive/accesses.expected | 1 - cpp/ql/test/library-tests/permissive/calls.expected | 1 - cpp/ql/test/library-tests/permissive/permissive.cpp | 8 -------- 3 files changed, 10 deletions(-) delete mode 100644 cpp/ql/test/library-tests/permissive/permissive.cpp diff --git a/cpp/ql/test/library-tests/permissive/accesses.expected b/cpp/ql/test/library-tests/permissive/accesses.expected index f3e66dcedaf..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/permissive/accesses.expected +++ b/cpp/ql/test/library-tests/permissive/accesses.expected @@ -1 +0,0 @@ -| permissive.cpp:6:5:6:7 | str | diff --git a/cpp/ql/test/library-tests/permissive/calls.expected b/cpp/ql/test/library-tests/permissive/calls.expected index 9d780e76405..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/permissive/calls.expected +++ b/cpp/ql/test/library-tests/permissive/calls.expected @@ -1 +0,0 @@ -| permissive.cpp:6:3:6:3 | call to f | permissive.cpp:2:13:2:13 | f | diff --git a/cpp/ql/test/library-tests/permissive/permissive.cpp b/cpp/ql/test/library-tests/permissive/permissive.cpp deleted file mode 100644 index 15f5b94ef61..00000000000 --- a/cpp/ql/test/library-tests/permissive/permissive.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// semmle-extractor-options: --edg --permissive -static void f(char* foo) {} - -static void g(void) { - const char* str = "foo"; - f(str); -} - From 2a814dd37cf7e3d0025b79cf2831b28cd2a92ac3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 23 Sep 2025 09:30:05 +0200 Subject: [PATCH 66/90] Rust: Model union, never, and pointer types --- .../rust/elements/internal/UnionImpl.qll | 7 ++ rust/ql/lib/codeql/rust/internal/Type.qll | 64 ++++++++++++++++++- .../codeql/rust/internal/TypeInference.qll | 5 ++ .../lib/codeql/rust/internal/TypeMention.qll | 18 ++++++ .../TypeInferenceConsistency.expected | 2 - .../type-inference/type-inference.expected | 2 + .../PathResolutionConsistency.expected | 3 + .../PathResolutionConsistency.expected | 7 ++ 8 files changed, 105 insertions(+), 3 deletions(-) delete mode 100644 rust/ql/test/extractor-tests/macro-expansion/CONSISTENCY/TypeInferenceConsistency.expected create mode 100644 rust/ql/test/query-tests/security/CWE-696/CONSISTENCY/PathResolutionConsistency.expected create mode 100644 rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected diff --git a/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll index 17551c4834e..712e39e6685 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll @@ -21,6 +21,13 @@ module Impl { * ``` */ class Union extends Generated::Union { + /** Gets the record field named `name`, if any. */ + pragma[nomagic] + StructField getStructField(string name) { + result = this.getStructFieldList().getAField() and + result.getName().getText() = name + } + override string toStringImpl() { result = "union " + this.getName().getText() } } } diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index eaa7e83fc6d..29e6ed283bc 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -42,11 +42,14 @@ newtype TType = TStruct(Struct s) or TEnum(Enum e) or TTrait(Trait t) or + TUnion(Union u) or TArrayType() or // todo: add size? TRefType() or // todo: add mut? TImplTraitType(ImplTraitTypeRepr impl) or TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or TSliceType() or + TNeverType() or + TPtrType() or TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or TTypeParamTypeParameter(TypeParam t) or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or @@ -57,7 +60,8 @@ newtype TType = } or TRefTypeParameter() or TSelfTypeParameter(Trait t) or - TSliceTypeParameter() + TSliceTypeParameter() or + TPtrTypeParameter() private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) { implTrait.isInReturnPos() and @@ -224,6 +228,31 @@ class TraitType extends Type, TTrait { override Location getLocation() { result = trait.getLocation() } } +/** A union type. */ +class UnionType extends StructOrEnumType, TUnion { + private Union union; + + UnionType() { this = TUnion(union) } + + override ItemNode asItemNode() { result = union } + + override StructField getStructField(string name) { result = union.getStructField(name) } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getPositionalTypeParameter(int i) { + result = TTypeParamTypeParameter(union.getGenericParamList().getTypeParam(i)) + } + + override TypeMention getTypeParameterDefault(int i) { + result = union.getGenericParamList().getTypeParam(i).getDefaultType() + } + + override string toString() { result = union.getName().getText() } + + override Location getLocation() { result = union.getLocation() } +} + /** * An array type. * @@ -374,6 +403,33 @@ class SliceType extends Type, TSliceType { override Location getLocation() { result instanceof EmptyLocation } } +class NeverType extends Type, TNeverType { + override StructField getStructField(string name) { none() } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getPositionalTypeParameter(int i) { none() } + + override string toString() { result = "!" } + + override Location getLocation() { result instanceof EmptyLocation } +} + +class PtrType extends Type, TPtrType { + override StructField getStructField(string name) { none() } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getPositionalTypeParameter(int i) { + i = 0 and + result = TPtrTypeParameter() + } + + override string toString() { result = "*" } + + override Location getLocation() { result instanceof EmptyLocation } +} + /** A type parameter. */ abstract class TypeParameter extends Type { override StructField getStructField(string name) { none() } @@ -529,6 +585,12 @@ class SliceTypeParameter extends TypeParameter, TSliceTypeParameter { override Location getLocation() { result instanceof EmptyLocation } } +class PtrTypeParameter extends TypeParameter, TPtrTypeParameter { + override string toString() { result = "*T" } + + override Location getLocation() { result instanceof EmptyLocation } +} + /** * The implicit `Self` type parameter of a trait, that refers to the * implementing type of the trait. diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 16c0b30332e..2d204469d32 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -99,6 +99,11 @@ private module Input1 implements InputSig1 { id1 = 0 and id2 = 2 or + tp0 instanceof PtrTypeParameter and + kind = 0 and + id1 = 0 and + id2 = 3 + or kind = 1 and id1 = 0 and id2 = diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index c36e1984237..ba7f4b4659d 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -241,6 +241,8 @@ class NonAliasPathTypeMention extends PathTypeMention { else result = TTrait(trait) ) or + result = TUnion(resolved) + or result = TTypeParamTypeParameter(resolved) or result = TAssociatedTypeTypeParameter(resolved) @@ -387,3 +389,19 @@ class DynTypeBoundListMention extends TypeMention instanceof TypeBoundList { ) } } + +class NeverTypeReprMention extends TypeMention, NeverTypeRepr { + override Type resolveTypeAt(TypePath path) { result = TNeverType() and path.isEmpty() } +} + +class PtrTypeReprMention extends TypeMention instanceof PtrTypeRepr { + override Type resolveTypeAt(TypePath path) { + path.isEmpty() and + result = TPtrType() + or + exists(TypePath suffix | + result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and + path = TypePath::cons(TPtrTypeParameter(), suffix) + ) + } +} diff --git a/rust/ql/test/extractor-tests/macro-expansion/CONSISTENCY/TypeInferenceConsistency.expected b/rust/ql/test/extractor-tests/macro-expansion/CONSISTENCY/TypeInferenceConsistency.expected deleted file mode 100644 index 416404c2bd1..00000000000 --- a/rust/ql/test/extractor-tests/macro-expansion/CONSISTENCY/TypeInferenceConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -illFormedTypeMention -| macro_expansion.rs:99:7:99:19 | MyDeriveUnion | diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 1a9a6456ce8..09fbdf17a8b 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2250,6 +2250,7 @@ inferType | main.rs:1127:43:1127:82 | MacroExpr | | main.rs:1124:15:1124:17 | Snd | | main.rs:1127:50:1127:81 | "PairNone has no second elemen... | | file://:0:0:0:0 | & | | main.rs:1127:50:1127:81 | "PairNone has no second elemen... | &T | {EXTERNAL LOCATION} | str | +| main.rs:1127:50:1127:81 | ...::panic_fmt(...) | | file://:0:0:0:0 | ! | | main.rs:1127:50:1127:81 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | main.rs:1127:50:1127:81 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | main.rs:1127:50:1127:81 | MacroExpr | | main.rs:1124:15:1124:17 | Snd | @@ -2261,6 +2262,7 @@ inferType | main.rs:1128:43:1128:81 | MacroExpr | | main.rs:1124:15:1124:17 | Snd | | main.rs:1128:50:1128:80 | "PairFst has no second element... | | file://:0:0:0:0 | & | | main.rs:1128:50:1128:80 | "PairFst has no second element... | &T | {EXTERNAL LOCATION} | str | +| main.rs:1128:50:1128:80 | ...::panic_fmt(...) | | file://:0:0:0:0 | ! | | main.rs:1128:50:1128:80 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments | | main.rs:1128:50:1128:80 | MacroExpr | | {EXTERNAL LOCATION} | Arguments | | main.rs:1128:50:1128:80 | MacroExpr | | main.rs:1124:15:1124:17 | Snd | diff --git a/rust/ql/test/query-tests/security/CWE-696/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-696/CONSISTENCY/PathResolutionConsistency.expected new file mode 100644 index 00000000000..16bbea0aba3 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-696/CONSISTENCY/PathResolutionConsistency.expected @@ -0,0 +1,3 @@ +multipleCallTargets +| test.rs:117:9:117:20 | ptr.is_null() | +| test.rs:117:9:117:21 | ptr.is_null() | diff --git a/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected new file mode 100644 index 00000000000..1abeb1aeb87 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected @@ -0,0 +1,7 @@ +multipleCallTargets +| main.rs:242:44:242:78 | ... .cast() | +| main.rs:245:44:245:78 | ... .cast() | +| main.rs:248:44:248:78 | ... .cast() | +| main.rs:251:14:251:48 | ... .cast() | +| main.rs:254:14:254:48 | ... .cast() | +| main.rs:257:14:257:48 | ... .cast() | From 109b6a1d7944ea63a67707f7d3531070ceb30624 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 25 Sep 2025 11:34:34 +0200 Subject: [PATCH 67/90] ControlFlow: Split only on relevant values. --- .../codeql/controlflow/ControlFlow.qll | 306 +++++++----------- .../controlflow/codeql/controlflow/Guards.qll | 3 + 2 files changed, 128 insertions(+), 181 deletions(-) diff --git a/shared/controlflow/codeql/controlflow/ControlFlow.qll b/shared/controlflow/codeql/controlflow/ControlFlow.qll index bfb878e6756..ca0de9d4744 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlow.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlow.qll @@ -80,6 +80,9 @@ signature module InputSig; - private predicate possibleClosedRange(SourceVariable var, int low, int high) { - possibleRangeBound(var, low, false) and - possibleRangeBound(var, high, true) and - low < high - } - - private newtype TGuardValueExt = - AnyValue() or - BaseValue(GuardValue gv) { possibleValue(_, gv) } or - IntRange(int low, int high) { possibleClosedRange(_, low, high) } - - private class GuardValueExt extends TGuardValueExt { - string toString() { - result = "Any" and this = AnyValue() - or - result = this.asBase().toString() - or - exists(int low, int high | - this = IntRange(low, high) and result = "[" + low + ", " + high + "]" - ) - } - - GuardValue asBase() { this = BaseValue(result) } - } - - private class TGuardValueOrAny = AnyValue or BaseValue; - - private class GuardValueOrAny extends GuardValueExt, TGuardValueOrAny { } - - private GuardValueExt mkRange(int low, int high) { - result = IntRange(low, high) - or - low = high and - result.asBase().asIntValue() = low - } - - private GuardValueExt intersectBase1(GuardValue gv1, GuardValue gv2) { - exists(SourceVariable var | - possibleValue(var, gv1) and - possibleValue(var, gv2) - | - smaller(gv1, gv2) and result.asBase() = gv1 - or - exists(int low, int high | - gv1.isIntRange(low, false) and - gv2.isIntRange(high, true) and - result = mkRange(low, high) - ) - or - exists(int bound, boolean upper, int d | - gv1.isIntRange(bound, upper) and - gv2.getDualValue().asIntValue() = bound and - result.asBase().isIntRange(bound + d, upper) - | - upper = true and d = -1 - or - upper = false and d = 1 - ) - ) - } - - private GuardValueExt intersectBase2(GuardValueExt v1, GuardValue v2) { - result = intersectBase1(v1.asBase(), v2) - or - result = intersectBase1(v2, v1.asBase()) - } + private class GuardValueOption = GuardValueOption::Option; + /** + * Gets the best constraint of `v1` and `v2`. If both are non-singletons, + * then we arbitrarily choose `v1`. This operation approximates intersection. + */ bindingset[v1, v2] pragma[inline_late] - private GuardValueExt intersectRange(GuardValueExt v1, GuardValue v2) { - exists(int low, int high | v1 = IntRange(low, high) | - exists(int bound, boolean upper | v2.isIntRange(bound, upper) | - upper = true and result = mkRange(low, high.minimum(bound)) - or - upper = false and result = mkRange(low.maximum(bound), high) - ) - or - exists(int k | - v2.asIntValue() = k and - result.asBase() = v2 and - low <= k and - k <= high - ) - or - not v2.isIntRange(_, _) and not exists(v2.asIntValue()) and result = v1 - ) - } - - bindingset[v1, v2] - pragma[inline_late] - private GuardValueExt intersect(GuardValueExt v1, GuardValue v2) { - v1 = AnyValue() and result.asBase() = v2 - or - result = intersectBase2(v1, v2) - or - result = v1 and - v1 instanceof BaseValue and - not exists(intersectBase2(v1, v2)) - or - result = intersectRange(v1, v2) - } - - bindingset[v1, gv2] - private predicate disjointValuesExt(GuardValueExt v1, GuardValue gv2) { - disjointValues(v1.asBase(), gv2) - or - exists(int low, int high | v1 = IntRange(low, high) | - gv2.asIntValue() < low - or - high < gv2.asIntValue() - or - exists(int bound, boolean upper | gv2.isIntRange(bound, upper) | - upper = true and bound < low - or - upper = false and high < bound - ) - ) + private GuardValueOption intersect(GuardValueOption v1, GuardValue v2) { + if v2.isSingleton() + then result.asSome() = v2 + else + if v1.isNone() + then result.asSome() = v2 + else result = v1 } /** An input configuration for control flow reachability. */ @@ -558,6 +449,7 @@ module Make< * Holds if the edge from `bb1` to `bb2` implies that `def` has a value * that is considered a barrier. */ + pragma[nomagic] private predicate ssaValueBarrierEdge(SsaDefinition def, BasicBlock bb1, BasicBlock bb2) { exists(GuardValue v | ssaControlsBranchEdge(def, bb1, bb2, v) and @@ -565,6 +457,11 @@ module Make< ) } + pragma[nomagic] + private predicate phiBlock(BasicBlock bb, SourceVariable v) { + exists(SsaPhiNode phi | phi.getBasicBlock() = bb and phi.getSourceVariable() = v) + } + /** Holds if `def1` in `bb1` may step to `def2` in `bb2`. */ private predicate step(SsaDefinition def1, BasicBlock bb1, SsaDefinition def2, BasicBlock bb2) { not sinkBlock(def1, bb1, _) and @@ -577,7 +474,7 @@ module Make< ssaRelevantAtEndOfBlock(def1, bb1) and bb1.getASuccessor() = bb2 and v = def1.getSourceVariable() and - not exists(SsaPhiNode phi | phi.getBasicBlock() = bb2 and phi.getSourceVariable() = v) and + not phiBlock(bb2, v) and def1 = def2 ) or @@ -687,8 +584,8 @@ module Make< * Holds if the edge from `bb1` to `bb2` implies that `def` has the value * `gv` and that the edge is relevant for computing reachability of `src`. * - * If multiple values may be implied by this edge, then we only include the - * most precise ones. + * If multiple values may be implied by this edge, including a singleton, + * then we only include the singleton. * * The underlying variable of `t` is `var`. */ @@ -697,7 +594,11 @@ module Make< BasicBlock bb2 ) { ssaControlsBranchEdge(t, bb1, bb2, gv) and - not exists(GuardValue gv0 | ssaControlsBranchEdge(t, bb1, bb2, gv0) and smaller(gv0, gv)) and + ( + exists(GuardValue gv0 | ssaControlsBranchEdge(t, bb1, bb2, gv0) and gv0.isSingleton()) + implies + gv.isSingleton() + ) and pathEdge(src, bb1, bb2) and t.getSourceVariable() = var } @@ -711,18 +612,36 @@ module Make< exists(BasicBlock pred | pathEdge(src, pred, entry) and entry.strictlyDominates(pred)) } + /** + * Gets either `gv` or its dual value. This is intended as a mostly unique + * representation of the set of values `gv` and `gv.getDualValue()`. + */ + private GuardValue getPrimary(GuardValue gv) { + exists(GuardValue dual | dual = gv.getDualValue() | + if dual.isSingleton() then result = dual else result = gv + ) + } + /** * Holds if precision may be improved by splitting control flow on the * value of `var` during the reachability computation of `src`. + * + * The `condgv`/`condgv.getDualValue()` separation of the values of `var` + * determines whether a possibly relevant edge may be taken or not. */ - private predicate relevantSplit(SourceVariable src, SourceVariable var) { + private predicate relevantSplit(SourceVariable src, SourceVariable var, GuardValue condgv) { // `var` may be a relevant split if we encounter 2+ conditional edges // that imply information about `var`. - 2 <= strictcount(BasicBlock bb1 | ssaControlsPathEdge(src, _, var, _, bb1, _)) + exists(GuardValue gv | + ssaControlsPathEdge(src, _, var, gv, _, _) and + condgv = getPrimary(gv) and + 2 <= strictcount(BasicBlock bb1 | ssaControlsPathEdge(src, _, var, _, bb1, _)) + ) or // Or if we encounter a conditional edge that imply a value that's // incompatible with an initial or later assigned value. exists(GuardValue gv1, GuardValue gv2, BasicBlock bb | + condgv = getPrimary(gv1) and ssaControlsPathEdge(src, _, var, gv1, _, _) and initSsaValue(var, bb, _, gv2) and disjointValues(gv1, gv2) and @@ -731,8 +650,11 @@ module Make< or // Or if we encounter a conditional edge in a loop that imply a value for // `var` that may be unchanged from one iteration to the next. - exists(SsaDefinition def, BasicBlock bb1, BasicBlock bb2, BasicBlock loopEntry | - ssaControlsPathEdge(src, def, var, _, bb1, bb2) and + exists( + SsaDefinition def, BasicBlock bb1, BasicBlock bb2, BasicBlock loopEntry, GuardValue gv + | + ssaControlsPathEdge(src, def, var, gv, bb1, bb2) and + condgv = getPrimary(gv) and loopEntryBlock(src, loopEntry) and loopEntry.strictlyDominates(bb1) and bb2.getASuccessor*() = loopEntry @@ -755,6 +677,18 @@ module Make< def = max(SsaDefinition d, int i | d.definesAt(var, bb, i) | d order by i) } + /** + * Holds if `gv` is relatable to the `condgv`/`condgv.getDualValue()` pair + * in the sense that a conditional branch based on `condgv` may be + * determined by `gv`. + */ + bindingset[gv, condgv] + pragma[inline_late] + private predicate relatable(GuardValue gv, GuardValue condgv) { + disjointValues(gv, condgv) or + disjointValues(gv, condgv.getDualValue()) + } + /** * Holds if `bb1` to `bb2` is a relevant edge for computing reachability of * `src`, and `var` is a relevant splitting variable that gets (re-)defined @@ -763,17 +697,20 @@ module Make< * `val` is the best known value for `t` in `bb2`. */ private predicate stepSsaValueRedef( - SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, SsaDefinition t, - GuardValueOrAny val + SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, + SsaDefinition t, GuardValueOption val ) { pathEdge(src, bb1, bb2) and - relevantSplit(src, var) and + relevantSplit(src, var, condgv) and lastDefInBlock(var, t, bb2) and not t instanceof SsaPhiNode and ( - ssaHasValue(t, val.asBase()) + exists(GuardValue gv | + ssaHasValue(t, gv) and + if relatable(gv, condgv) then val.asSome() = gv else val.isNone() + ) or - not ssaHasValue(t, _) and val = AnyValue() + not ssaHasValue(t, _) and val.isNone() ) } @@ -786,18 +723,21 @@ module Make< * `val` is the best value for `t1`/`t2` implied by taking this edge. */ private predicate stepSsaValuePhi( - SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, SsaDefinition t1, - SsaDefinition t2, GuardValueOrAny val + SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, + SsaDefinition t1, SsaDefinition t2, GuardValueOption val ) { pathEdge(src, bb1, bb2) and - relevantSplit(src, var) and + relevantSplit(src, var, condgv) and lastDefInBlock(var, t2, bb2) and t2.(SsaPhiNode).hasInputFromBlock(t1, bb1) and ( - ssaControlsPathEdge(src, t1, _, val.asBase(), bb1, bb2) + exists(GuardValue gv | + ssaControlsPathEdge(src, t1, _, gv, bb1, bb2) and + if relatable(gv, condgv) then val.asSome() = gv else val.isNone() + ) or not ssaControlsPathEdge(src, t1, _, _, bb1, bb2) and - val = AnyValue() + val.isNone() ) } @@ -810,13 +750,14 @@ module Make< * value `val`. */ private predicate stepSsaValueNoRedef( - SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, SsaDefinition t, - GuardValue val + SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, + SsaDefinition t, GuardValue val ) { pathEdge(src, bb1, bb2) and - relevantSplit(src, var) and + relevantSplit(src, var, condgv) and not lastDefInBlock(var, _, bb2) and - ssaControlsPathEdge(src, t, var, val, bb1, bb2) + ssaControlsPathEdge(src, t, var, val, bb1, bb2) and + relatable(val, condgv) } /** @@ -827,64 +768,67 @@ module Make< */ private predicate sourceReachesBlockWithTrackedVar( SsaDefinition srcDef, BasicBlock srcBb, SsaDefinition def, BasicBlock bb, FinallyStack fs, - SsaDefOption tracked, GuardValueExt val, SourceVariable var + SsaDefOption tracked, GuardValueOption val, SourceVariable var, GuardValue condgv ) { sourceBlock(srcDef, srcBb, _) and def = srcDef and bb = srcBb and fs = TNil() and - relevantSplit(def.getSourceVariable(), var) and + relevantSplit(def.getSourceVariable(), var, condgv) and ( // tracking variable is not yet live not ssaLiveAtEndOfBlock(var, _, bb) and tracked.isNone() and - val = AnyValue() + val.isNone() or // tracking variable is live but without known value ssaLiveAtEndOfBlock(var, tracked.asSome(), bb) and not initSsaValue(var, bb, _, _) and - val = AnyValue() + val.isNone() or - // tracking variable has known value - initSsaValue(var, bb, tracked.asSome(), val.asBase()) + // tracking variable has known value, track it if it is relatable to condgv + exists(GuardValue gv | initSsaValue(var, bb, tracked.asSome(), gv) | + if relatable(gv, condgv) then val.asSome() = gv else val.isNone() + ) ) or exists( SourceVariable src, SsaDefinition middef, BasicBlock midbb, FinallyStack midfs, - SsaDefOption tracked0, GuardValueExt val0 + SsaDefOption tracked0, GuardValueOption val0 | - sourceReachesBlockWithTrackedVar(srcDef, srcBb, middef, midbb, midfs, tracked0, val0, var) and + sourceReachesBlockWithTrackedVar(srcDef, srcBb, middef, midbb, midfs, tracked0, val0, var, + condgv) and src = srcDef.getSourceVariable() and step(middef, midbb, def, bb) and stepFinallyStack(midbb, bb, midfs, fs) and - pathBlock(src, bb) and + pathBlock(pragma[only_bind_into](src), bb) and not exists(GuardValue gv | ssaControlsPathEdge(src, tracked0.asSome(), _, gv, midbb, bb) and - disjointValuesExt(val0, gv) + disjointValues(val0.asSome(), gv) ) | // tracking variable is redefined - stepSsaValueRedef(src, midbb, bb, var, tracked.asSome(), val) + stepSsaValueRedef(src, midbb, bb, var, condgv, tracked.asSome(), val) or - exists(GuardValueOrAny val1 | + exists(GuardValueOption val1 | // tracking variable has a phi node, and maybe value information from the edge - stepSsaValuePhi(src, midbb, bb, var, tracked0.asSome(), tracked.asSome(), val1) + stepSsaValuePhi(src, midbb, bb, var, condgv, tracked0.asSome(), tracked.asSome(), val1) | - val = val0 and val1 = AnyValue() + val = val0 and val1.isNone() or - val = intersect(val0, val1.asBase()) + val = intersect(val0, val1.asSome()) ) or exists(GuardValue val1 | // tracking variable is unchanged, and has value information from the edge - stepSsaValueNoRedef(src, midbb, bb, var, tracked0.asSome(), val1) and + stepSsaValueNoRedef(src, midbb, bb, var, condgv, tracked0.asSome(), val1) and tracked = tracked0 and val = intersect(val0, val1) ) or // tracking variable is unchanged, and has no value information from the edge not lastDefInBlock(var, _, bb) and - not stepSsaValueNoRedef(src, midbb, bb, var, tracked0.asSome(), _) and + not stepSsaValueNoRedef(src, midbb, bb, var, condgv, tracked0.asSome(), _) and tracked = tracked0 and val = val0 ) @@ -903,8 +847,8 @@ module Make< sourceReachesBlock(srcDef, srcBb, sinkDef, sinkBb, _) and sinkBlock(sinkDef, sinkBb, sink) and srcVar = srcDef.getSourceVariable() and - forall(SourceVariable t | relevantSplit(srcVar, t) | - sourceReachesBlockWithTrackedVar(srcDef, srcBb, sinkDef, sinkBb, _, _, _, t) + forall(SourceVariable t, GuardValue condgv | relevantSplit(srcVar, t, condgv) | + sourceReachesBlockWithTrackedVar(srcDef, srcBb, sinkDef, sinkBb, _, _, _, t, condgv) ) ) } @@ -920,8 +864,8 @@ module Make< sourceBlock(srcDef, srcBb, src) and sourceEscapesSink(srcDef, srcBb, escDef, escBb) and srcVar = srcDef.getSourceVariable() and - forall(SourceVariable t | relevantSplit(srcVar, t) | - sourceReachesBlockWithTrackedVar(srcDef, srcBb, escDef, escBb, _, _, _, t) + forall(SourceVariable t, GuardValue condgv | relevantSplit(srcVar, t, condgv) | + sourceReachesBlockWithTrackedVar(srcDef, srcBb, escDef, escBb, _, _, _, t, condgv) ) ) } diff --git a/shared/controlflow/codeql/controlflow/Guards.qll b/shared/controlflow/codeql/controlflow/Guards.qll index 0bbfb29e4e6..668fb60655c 100644 --- a/shared/controlflow/codeql/controlflow/Guards.qll +++ b/shared/controlflow/codeql/controlflow/Guards.qll @@ -259,6 +259,9 @@ module Make< ) } + /** Holds if this value represents a single concrete value. */ + predicate isSingleton() { this = TValue(_, true) } + /** Holds if this value represents `null`. */ predicate isNullValue() { this.isNullness(true) } From b22227d0f4b084d41eb7a026975a8562f926fd2c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:30:57 +0100 Subject: [PATCH 68/90] Add .orig files to .gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index fe4a5de9672..4dbe45b8d28 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,6 @@ node_modules/ # some upgrade/downgrade checks create these files **/upgrades/*/*.dbscheme.stats **/downgrades/*/*.dbscheme.stats + +# Mergetool files +*.orig From e9cccb46c067ffb046218711f693c90fc51d5beb Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 25 Sep 2025 15:19:40 +0100 Subject: [PATCH 69/90] Go: mistyped-exponentiation: notice constants with likely-bitmask values --- go/ql/src/InconsistentCode/MistypedExponentiation.ql | 6 +++++- .../InconsistentCode/MistypedExponentiation/main.go | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/go/ql/src/InconsistentCode/MistypedExponentiation.ql b/go/ql/src/InconsistentCode/MistypedExponentiation.ql index b445a713ce6..91fb63d319c 100644 --- a/go/ql/src/InconsistentCode/MistypedExponentiation.ql +++ b/go/ql/src/InconsistentCode/MistypedExponentiation.ql @@ -13,12 +13,16 @@ import go +private Expr getConstantInitialiser(Expr e) { + exists(DeclaredConstant c | e = c.getAReference() | result = c.getInit()) +} + /** Holds if `e` is not 0 and is either an octal or hexadecimal literal, or the number one. */ predicate maybeXorBitPattern(Expr e) { // 0 makes no sense as an xor bit pattern not e.getNumericValue() = 0 and // include octal and hex literals - e.(IntLit).getText().matches("0%") + [e, getConstantInitialiser(e)].(IntLit).getText().matches("0%") or e.getNumericValue() = 1 } diff --git a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go index 2449ccdac62..b8b4be44847 100644 --- a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go +++ b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go @@ -22,6 +22,13 @@ func main() { mask := (((1 << 10) - 1) ^ 7) // OK + const ( + c1 = 0x1234 + c2 = 0x5678 + ) + + fmt.Println(c1 ^ c2) // OK + // This is not ok, but isn't detected because the multiplication binds tighter // than the xor operator and so the query doesn't see a constant on the left // hand side of ^. From 9e7a5214f31abbede39a6ba776664e61dea405be Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 25 Sep 2025 15:40:26 +0100 Subject: [PATCH 70/90] Change note --- go/ql/src/change-notes/2025-09-25-exponentiation-constants.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 go/ql/src/change-notes/2025-09-25-exponentiation-constants.md diff --git a/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md b/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md new file mode 100644 index 00000000000..cb6c5e43346 --- /dev/null +++ b/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query `go/mistyped-exponentiation` now recognises constants whose initialisers are hex or octal constants, making them likely targets of the `^` bitwise-xor operator. From 656a7bc37862ffeb31eadacdd65f071ea8130e42 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Sep 2025 17:25:03 +0100 Subject: [PATCH 71/90] Rust: Add missing Cargo.lock files to query tests. --- .../test/query-tests/diagnostics/Cargo.lock | 7 + .../query-tests/security/CWE-798/Cargo.lock | 726 ++++++++++++++++++ 2 files changed, 733 insertions(+) create mode 100644 rust/ql/test/query-tests/diagnostics/Cargo.lock create mode 100644 rust/ql/test/query-tests/security/CWE-798/Cargo.lock diff --git a/rust/ql/test/query-tests/diagnostics/Cargo.lock b/rust/ql/test/query-tests/diagnostics/Cargo.lock new file mode 100644 index 00000000000..b9856cfaf77 --- /dev/null +++ b/rust/ql/test/query-tests/diagnostics/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "test" +version = "0.0.1" diff --git a/rust/ql/test/query-tests/security/CWE-798/Cargo.lock b/rust/ql/test/query-tests/security/CWE-798/Cargo.lock new file mode 100644 index 00000000000..6d0fce1423e --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-798/Cargo.lock @@ -0,0 +1,726 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "biscotti" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddb6f28a3d15d18cace7a8010282a4d9cee1452dcd33f5861c173b4a31095b79" +dependencies = [ + "aes-gcm-siv", + "anyhow", + "base64", + "hkdf", + "hmac", + "jiff", + "percent-encoding", + "rand 0.9.2", + "serde", + "sha2", + "subtle", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "aes-gcm", + "base64", + "hmac", + "rand 0.8.5", + "sha2", + "subtle", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", + "windows-sys", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rabbit" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931a21d28d73d260f6743712e0f04292413fc6d004bb278bb9022302221a05d5" +dependencies = [ + "cipher", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "serde" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test" +version = "0.0.1" +dependencies = [ + "aes", + "aes-gcm", + "base64", + "biscotti", + "cfb-mode", + "cipher", + "cookie", + "getrandom 0.2.16", + "getrandom 0.3.3", + "rabbit", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" From ff554055a6c24bb2e2f428f6f9d8c51851e201a2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 08:43:35 +0100 Subject: [PATCH 72/90] Rust: Correct 'from' model to taint. --- rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml index a92ed8fc235..b0b63fa0201 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml @@ -12,7 +12,7 @@ extensions: - ["::into", "Argument[self].Element", "ReturnValue.Element", "taint", "manual"] - ["::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"] # From - - ["<_ as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"] + - ["<_ as core::convert::From>::from", "Argument[0]", "ReturnValue", "taint", "manual"] # Iterator - ["::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"] - ["::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"] From 7a74efcc824783ab1e40fe4c29a2f9885e734f8c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Sep 2025 09:57:13 +0200 Subject: [PATCH 73/90] Update rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll Co-authored-by: Simon Friis Vindum --- rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll index 712e39e6685..40680f3edc9 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll @@ -21,7 +21,7 @@ module Impl { * ``` */ class Union extends Generated::Union { - /** Gets the record field named `name`, if any. */ + /** Gets the struct field named `name`, if any. */ pragma[nomagic] StructField getStructField(string name) { result = this.getStructFieldList().getAField() and From 74a350a4325c597bc3c9e774e2477ad9c9b2ba18 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:41:59 +0100 Subject: [PATCH 74/90] Rust: Effect on tests. --- .../strings/inline-taint-flow.expected | 2 +- .../library-tests/dataflow/strings/main.rs | 2 +- .../security/CWE-022/TaintedPath.expected | 2 +- .../HardcodedCryptographicValue.expected | 34 +++++++------------ 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected index ea6e06ef616..e6241590137 100644 --- a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected @@ -1,5 +1,5 @@ models -| 1 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value | +| 1 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; taint | | 2 | Summary: ::from; Argument[0].Reference; ReturnValue; value | | 3 | Summary: ::add; Argument[self]; ReturnValue; value | | 4 | Summary: ::as_str; Argument[self]; ReturnValue; value | diff --git a/rust/ql/test/library-tests/dataflow/strings/main.rs b/rust/ql/test/library-tests/dataflow/strings/main.rs index 772a45f1993..ca9db9a9026 100644 --- a/rust/ql/test/library-tests/dataflow/strings/main.rs +++ b/rust/ql/test/library-tests/dataflow/strings/main.rs @@ -50,7 +50,7 @@ fn string_add_reference() { fn string_from() { let s1 = source_slice(36); let s2 = String::from(s1); - sink(s2); // $ hasValueFlow=36 + sink(s2); // $ hasTaintFlow=36 } fn string_to_string() { diff --git a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected index 8e2a7d13dda..a1f9b448ac7 100644 --- a/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected +++ b/rust/ql/test/query-tests/security/CWE-022/TaintedPath.expected @@ -123,7 +123,7 @@ models | 6 | Sink: std::fs::read_to_string; Argument[0]; path-injection | | 7 | Source: std::env::args; ReturnValue.Element; commandargs | | 8 | Summary: <_ as core::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value | -| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value | +| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; taint | | 10 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | | 11 | Summary: ::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | | 12 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index d16be723b8f..0c423a29a6d 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -14,7 +14,6 @@ | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key | | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key | -| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key | | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key | edges | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | @@ -23,39 +22,39 @@ edges | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 Sink:MaD:6 | -| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:9 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:9 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:8 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | @@ -72,13 +71,8 @@ edges | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:28:21:34 | [0; 64] [element] | provenance | | | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | | test_cookie.rs:22:27:22:32 | array2 [element] | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | provenance | | -| test_cookie.rs:38:9:38:14 | array2 [element] | test_cookie.rs:42:34:42:39 | array2 [element] | provenance | | -| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | test_cookie.rs:38:9:38:14 | array2 [element] | provenance | | -| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | provenance | MaD:9 | -| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | provenance | | -| test_cookie.rs:42:34:42:39 | array2 [element] | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | | test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:11 | +| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:10 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | | | test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | models @@ -90,9 +84,8 @@ models | 6 | Sink: ::new; Argument[1]; credentials-iv | | 7 | Sink: ::from; Argument[0].Reference; credentials-key | | 8 | Source: core::mem::zeroed; ReturnValue.Element; constant-source | -| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value | -| 10 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | -| 11 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | +| 9 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 10 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | | test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | @@ -158,15 +151,12 @@ nodes | test_cookie.rs:22:16:22:24 | ...::from | semmle.label | ...::from | | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | semmle.label | &array2 [&ref, element] | | test_cookie.rs:22:27:22:32 | array2 [element] | semmle.label | array2 [element] | -| test_cookie.rs:38:9:38:14 | array2 [element] | semmle.label | array2 [element] | -| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | semmle.label | ...::from(...) [element] | -| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | semmle.label | [0u8; 64] [element] | -| test_cookie.rs:38:29:38:31 | 0u8 | semmle.label | 0u8 | -| test_cookie.rs:42:14:42:32 | ...::from | semmle.label | ...::from | -| test_cookie.rs:42:34:42:39 | array2 [element] | semmle.label | array2 [element] | | test_cookie.rs:49:9:49:14 | array3 [element] | semmle.label | array3 [element] | | test_cookie.rs:49:23:49:25 | 0u8 | semmle.label | 0u8 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] | | test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from | | test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] | subpaths +testFailures +| test_cookie.rs:38:40:38:86 | //... | Missing result: Alert[rust/hard-coded-cryptographic-value] | +| test_cookie.rs:42:43:42:51 | //... | Missing result: Sink | From 3a03bb5a0bce190b7cd60df209bf96aa63556c30 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:03:38 +0100 Subject: [PATCH 75/90] Rust: Repair rust/hard-coded-cryptographic-value, which had an unintentional dependence on the taint flow. --- .../HardcodedCryptographicValueExtensions.qll | 8 +- .../HardcodedCryptographicValue.expected | 170 +++++++++--------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 785a7f815bc..bc487e42ef0 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -69,11 +69,15 @@ module HardcodedCryptographicValue { /** * An array initialized from a list of literals, considered as a single flow source. For example: * ``` - * `[0, 0, 0, 0]` + * [0, 0, 0, 0] + * [0; 10] * ``` */ private class ArrayListSource extends Source { - ArrayListSource() { this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr } + ArrayListSource() { + this.asExpr().getExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr or + this.asExpr().getExpr().(ArrayRepeatExpr).getRepeatOperand() instanceof LiteralExpr + } } /** diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index 0c423a29a6d..09e2ebdef34 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -1,78 +1,77 @@ #select -| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | -| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | -| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | -| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | -| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | -| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | +| test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | +| test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:19:30:19:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:19:30:19:47 | ...::new | a key | +| test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | +| test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:26:30:26:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:26:30:26:40 | ...::new | a key | +| test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | +| test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:30:30:30:40 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:30:30:30:40 | ...::new | an initialization vector | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:38:30:38:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:38:30:38:47 | ...::new | a key | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:42:30:42:47 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:42:30:42:47 | ...::new | a key | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key | -| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | -| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key | -| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key | +| test_cipher.rs:73:19:73:26 | [0u8; 32] | test_cipher.rs:73:19:73:26 | [0u8; 32] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key | +| test_cookie.rs:17:28:17:34 | [0; 64] | test_cookie.rs:17:28:17:34 | [0; 64] | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key | +| test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key | | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key | edges -| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | | -| test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | | -| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | | -| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | -| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | | -| test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | | -| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | | -| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | -| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | | -| test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | | -| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | | -| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 Sink:MaD:6 | -| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | +| test_cipher.rs:18:9:18:14 | const1 [&ref] | test_cipher.rs:19:73:19:78 | const1 [&ref] | provenance | | +| test_cipher.rs:18:28:18:36 | &... [&ref] | test_cipher.rs:18:9:18:14 | const1 [&ref] | provenance | | +| test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:28:18:36 | &... [&ref] | provenance | | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | +| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:25:9:25:14 | const4 [&ref] | test_cipher.rs:26:66:26:71 | const4 [&ref] | provenance | | +| test_cipher.rs:25:28:25:36 | &... [&ref] | test_cipher.rs:25:9:25:14 | const4 [&ref] | provenance | | +| test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:28:25:36 | &... [&ref] | provenance | | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 | +| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:10 | +| test_cipher.rs:29:9:29:14 | const5 [&ref] | test_cipher.rs:30:95:30:100 | const5 [&ref] | provenance | | +| test_cipher.rs:29:28:29:36 | &... [&ref] | test_cipher.rs:29:9:29:14 | const5 [&ref] | provenance | | +| test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:28:29:36 | &... [&ref] | provenance | | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 | +| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:10 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:9 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:10 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:9 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:8 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:9 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | -| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | | -| test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | | -| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | | -| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | | -| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | -| test_cookie.rs:17:9:17:14 | array1 [element] | test_cookie.rs:18:27:18:32 | array1 [element] | provenance | | -| test_cookie.rs:17:28:17:34 | [0; 64] [element] | test_cookie.rs:17:9:17:14 | array1 [element] | provenance | | -| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:28:17:34 | [0; 64] [element] | provenance | | -| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | -| test_cookie.rs:18:27:18:32 | array1 [element] | test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | provenance | | -| test_cookie.rs:21:9:21:14 | array2 [element] | test_cookie.rs:22:27:22:32 | array2 [element] | provenance | | -| test_cookie.rs:21:28:21:34 | [0; 64] [element] | test_cookie.rs:21:9:21:14 | array2 [element] | provenance | | -| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:28:21:34 | [0; 64] [element] | provenance | | -| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | -| test_cookie.rs:22:27:22:32 | array2 [element] | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | provenance | | +| test_cipher.rs:73:9:73:14 | const2 [&ref] | test_cipher.rs:74:46:74:51 | const2 [&ref] | provenance | | +| test_cipher.rs:73:18:73:26 | &... [&ref] | test_cipher.rs:73:9:73:14 | const2 [&ref] | provenance | | +| test_cipher.rs:73:19:73:26 | [0u8; 32] | test_cipher.rs:73:18:73:26 | &... [&ref] | provenance | | +| test_cipher.rs:74:46:74:51 | const2 [&ref] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:1 Sink:MaD:1 | +| test_cookie.rs:17:9:17:14 | array1 | test_cookie.rs:18:27:18:32 | array1 | provenance | | +| test_cookie.rs:17:28:17:34 | [0; 64] | test_cookie.rs:17:9:17:14 | array1 | provenance | | +| test_cookie.rs:18:26:18:32 | &array1 [&ref] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | +| test_cookie.rs:18:27:18:32 | array1 | test_cookie.rs:18:26:18:32 | &array1 [&ref] | provenance | | +| test_cookie.rs:21:9:21:14 | array2 | test_cookie.rs:22:27:22:32 | array2 | provenance | | +| test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:9:21:14 | array2 | provenance | | +| test_cookie.rs:22:26:22:32 | &array2 [&ref] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 | +| test_cookie.rs:22:27:22:32 | array2 | test_cookie.rs:22:26:22:32 | &array2 [&ref] | provenance | | +| test_cookie.rs:38:9:38:14 | array2 | test_cookie.rs:42:34:42:39 | array2 | provenance | | +| test_cookie.rs:38:18:38:37 | ...::from(...) | test_cookie.rs:38:9:38:14 | array2 | provenance | | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:9 | +| test_cookie.rs:42:34:42:39 | array2 | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | | test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:10 | +| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:11 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | | | test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | models @@ -84,33 +83,31 @@ models | 6 | Sink: ::new; Argument[1]; credentials-iv | | 7 | Sink: ::from; Argument[0].Reference; credentials-key | | 8 | Source: core::mem::zeroed; ReturnValue.Element; constant-source | -| 9 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | -| 10 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | +| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; taint | +| 10 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 11 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | nodes -| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | -| test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | -| test_cipher.rs:18:30:18:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:18:9:18:14 | const1 [&ref] | semmle.label | const1 [&ref] | +| test_cipher.rs:18:28:18:36 | &... [&ref] | semmle.label | &... [&ref] | +| test_cipher.rs:18:29:18:36 | [0u8; 16] | semmle.label | [0u8; 16] | | test_cipher.rs:19:30:19:47 | ...::new | semmle.label | ...::new | | test_cipher.rs:19:30:19:47 | ...::new | semmle.label | ...::new | -| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | -| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | semmle.label | const1 [&ref, element] | -| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | -| test_cipher.rs:25:28:25:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | -| test_cipher.rs:25:30:25:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | +| test_cipher.rs:19:73:19:78 | const1 [&ref] | semmle.label | const1 [&ref] | +| test_cipher.rs:25:9:25:14 | const4 [&ref] | semmle.label | const4 [&ref] | +| test_cipher.rs:25:28:25:36 | &... [&ref] | semmle.label | &... [&ref] | +| test_cipher.rs:25:29:25:36 | [0u8; 16] | semmle.label | [0u8; 16] | | test_cipher.rs:26:30:26:40 | ...::new | semmle.label | ...::new | | test_cipher.rs:26:30:26:40 | ...::new | semmle.label | ...::new | -| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | -| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | semmle.label | const4 [&ref, element] | -| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | -| test_cipher.rs:29:28:29:36 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | semmle.label | [0u8; 16] [element] | -| test_cipher.rs:29:30:29:32 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | +| test_cipher.rs:26:66:26:71 | const4 [&ref] | semmle.label | const4 [&ref] | +| test_cipher.rs:29:9:29:14 | const5 [&ref] | semmle.label | const5 [&ref] | +| test_cipher.rs:29:28:29:36 | &... [&ref] | semmle.label | &... [&ref] | +| test_cipher.rs:29:29:29:36 | [0u8; 16] | semmle.label | [0u8; 16] | | test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | | test_cipher.rs:30:30:30:40 | ...::new | semmle.label | ...::new | -| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | -| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | semmle.label | const5 [&ref, element] | +| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | semmle.label | ...::from_slice(...) [&ref] | +| test_cipher.rs:30:95:30:100 | const5 [&ref] | semmle.label | const5 [&ref] | | test_cipher.rs:37:9:37:14 | const7 | semmle.label | const7 | | test_cipher.rs:37:27:37:74 | [...] | semmle.label | [...] | | test_cipher.rs:38:30:38:47 | ...::new | semmle.label | ...::new | @@ -133,30 +130,29 @@ nodes | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | semmle.label | ...::from_slice(...) [&ref, element] | | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | semmle.label | &const10 [&ref, element] | | test_cipher.rs:51:75:51:81 | const10 [element] | semmle.label | const10 [element] | -| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | -| test_cipher.rs:73:18:73:26 | &... [&ref, element] | semmle.label | &... [&ref, element] | -| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | semmle.label | [0u8; 32] [element] | -| test_cipher.rs:73:20:73:22 | 0u8 | semmle.label | 0u8 | +| test_cipher.rs:73:9:73:14 | const2 [&ref] | semmle.label | const2 [&ref] | +| test_cipher.rs:73:18:73:26 | &... [&ref] | semmle.label | &... [&ref] | +| test_cipher.rs:73:19:73:26 | [0u8; 32] | semmle.label | [0u8; 32] | | test_cipher.rs:74:23:74:44 | ...::new_from_slice | semmle.label | ...::new_from_slice | -| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | semmle.label | const2 [&ref, element] | -| test_cookie.rs:17:9:17:14 | array1 [element] | semmle.label | array1 [element] | -| test_cookie.rs:17:28:17:34 | [0; 64] [element] | semmle.label | [0; 64] [element] | -| test_cookie.rs:17:29:17:29 | 0 | semmle.label | 0 | +| test_cipher.rs:74:46:74:51 | const2 [&ref] | semmle.label | const2 [&ref] | +| test_cookie.rs:17:9:17:14 | array1 | semmle.label | array1 | +| test_cookie.rs:17:28:17:34 | [0; 64] | semmle.label | [0; 64] | | test_cookie.rs:18:16:18:24 | ...::from | semmle.label | ...::from | -| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | semmle.label | &array1 [&ref, element] | -| test_cookie.rs:18:27:18:32 | array1 [element] | semmle.label | array1 [element] | -| test_cookie.rs:21:9:21:14 | array2 [element] | semmle.label | array2 [element] | -| test_cookie.rs:21:28:21:34 | [0; 64] [element] | semmle.label | [0; 64] [element] | -| test_cookie.rs:21:29:21:29 | 0 | semmle.label | 0 | +| test_cookie.rs:18:26:18:32 | &array1 [&ref] | semmle.label | &array1 [&ref] | +| test_cookie.rs:18:27:18:32 | array1 | semmle.label | array1 | +| test_cookie.rs:21:9:21:14 | array2 | semmle.label | array2 | +| test_cookie.rs:21:28:21:34 | [0; 64] | semmle.label | [0; 64] | | test_cookie.rs:22:16:22:24 | ...::from | semmle.label | ...::from | -| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | semmle.label | &array2 [&ref, element] | -| test_cookie.rs:22:27:22:32 | array2 [element] | semmle.label | array2 [element] | +| test_cookie.rs:22:26:22:32 | &array2 [&ref] | semmle.label | &array2 [&ref] | +| test_cookie.rs:22:27:22:32 | array2 | semmle.label | array2 | +| test_cookie.rs:38:9:38:14 | array2 | semmle.label | array2 | +| test_cookie.rs:38:18:38:37 | ...::from(...) | semmle.label | ...::from(...) | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | semmle.label | [0u8; 64] | +| test_cookie.rs:42:14:42:32 | ...::from | semmle.label | ...::from | +| test_cookie.rs:42:34:42:39 | array2 | semmle.label | array2 | | test_cookie.rs:49:9:49:14 | array3 [element] | semmle.label | array3 [element] | | test_cookie.rs:49:23:49:25 | 0u8 | semmle.label | 0u8 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] | | test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from | | test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] | subpaths -testFailures -| test_cookie.rs:38:40:38:86 | //... | Missing result: Alert[rust/hard-coded-cryptographic-value] | -| test_cookie.rs:42:43:42:51 | //... | Missing result: Sink | From 2f96e32ec995fd8fecabd88c475f1a245a1fc3a4 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 10:08:31 +0100 Subject: [PATCH 76/90] Update 2.1.0.md --- javascript/ql/src/change-notes/released/2.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/change-notes/released/2.1.0.md b/javascript/ql/src/change-notes/released/2.1.0.md index e0ef5ddd6e1..6b5696816cf 100644 --- a/javascript/ql/src/change-notes/released/2.1.0.md +++ b/javascript/ql/src/change-notes/released/2.1.0.md @@ -10,4 +10,4 @@ * Data flow is now tracked through the `Promise.try` and `Array.prototype.with` functions. * Query `js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. * The query `js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as `Object.keys()`. -* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. +* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who submitted the original experimental query! From 09833e2541e36e678993b9fa613113dba0fac32f Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 10:09:30 +0100 Subject: [PATCH 77/90] Update CHANGELOG for query promotion and acknowledgment Promote 'Permissive CORS configuration' query to default suite and acknowledge contributor. --- javascript/ql/src/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index 619bc14bf29..4067c050c2a 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -10,7 +10,7 @@ * Data flow is now tracked through the `Promise.try` and `Array.prototype.with` functions. * Query `js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. * The query `js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as `Object.keys()`. -* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. +* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who [submitted the original experimental query](https://github.com/github/codeql/pull/14342)! ## 2.0.3 From ba520c60d23a6e7bbd091eade91b5d6544525e41 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 10:11:03 +0100 Subject: [PATCH 78/90] Update 2.1.0.md --- javascript/ql/src/change-notes/released/2.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/change-notes/released/2.1.0.md b/javascript/ql/src/change-notes/released/2.1.0.md index 6b5696816cf..c95b5add20b 100644 --- a/javascript/ql/src/change-notes/released/2.1.0.md +++ b/javascript/ql/src/change-notes/released/2.1.0.md @@ -10,4 +10,4 @@ * Data flow is now tracked through the `Promise.try` and `Array.prototype.with` functions. * Query `js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. * The query `js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as `Object.keys()`. -* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who submitted the original experimental query! +* The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who [submitted the original experimental query](https://github.com/github/codeql/pull/14342)! From 4c7b66c66af102eaf2ecf7bcb2f5090cdeee88b6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 26 Sep 2025 13:11:45 +0200 Subject: [PATCH 79/90] Address review comments --- .../rust/elements/internal/CallableImpl.qll | 10 ++++++ .../codeql/rust/internal/PathResolution.qll | 31 +++++++------------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll index 46489cab981..9448de795d3 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/CallableImpl.qll @@ -27,5 +27,15 @@ module Impl { * Holds if `getSelfParam()` exists. */ predicate hasSelfParam() { exists(this.getSelfParam()) } + + /** + * Gets the number of parameters of this callable, including `self` if it exists. + */ + int getNumberOfParamsInclSelf() { + exists(int arr | + arr = this.getNumberOfParams() and + if this.hasSelfParam() then result = arr + 1 else result = arr + ) + } } } diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 4b368308878..f1574ff38f3 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -605,13 +605,13 @@ private class EnumItemNode extends TypeItemNode instanceof Enum { } } -/** An item that can be called with arguments. */ -abstract class CallableItemNode extends ItemNode { - /** Gets the number of parameters of this item. */ - abstract int getNumberOfParameters(); +/** An item that can be referenced with arguments. */ +abstract class ParameterizableItemNode extends ItemNode { + /** Gets the arity this item. */ + abstract int getArity(); } -private class VariantItemNode extends CallableItemNode instanceof Variant { +private class VariantItemNode extends ParameterizableItemNode instanceof Variant { override string getName() { result = Variant.super.getName().getText() } override Namespace getNamespace() { @@ -624,9 +624,7 @@ private class VariantItemNode extends CallableItemNode instanceof Variant { override Visibility getVisibility() { result = super.getEnum().getVisibility() } - override int getNumberOfParameters() { - result = super.getFieldList().(TupleFieldList).getNumberOfFields() - } + override int getArity() { result = super.getFieldList().(TupleFieldList).getNumberOfFields() } override predicate hasCanonicalPath(Crate c) { this.hasCanonicalPathPrefix(c) } @@ -649,7 +647,7 @@ private class VariantItemNode extends CallableItemNode instanceof Variant { } } -class FunctionItemNode extends AssocItemNode, CallableItemNode instanceof Function { +class FunctionItemNode extends AssocItemNode, ParameterizableItemNode instanceof Function { override string getName() { result = Function.super.getName().getText() } override predicate hasImplementation() { Function.super.hasImplementation() } @@ -660,12 +658,7 @@ class FunctionItemNode extends AssocItemNode, CallableItemNode instanceof Functi override Visibility getVisibility() { result = Function.super.getVisibility() } - override int getNumberOfParameters() { - exists(int arr | - arr = super.getNumberOfParams() and - if super.hasSelfParam() then result = arr + 1 else result = arr - ) - } + override int getArity() { result = super.getNumberOfParamsInclSelf() } } abstract class ImplOrTraitItemNode extends ItemNode { @@ -885,7 +878,7 @@ private class ImplItemNodeImpl extends ImplItemNode { TraitItemNode resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) } } -private class StructItemNode extends TypeItemNode, CallableItemNode instanceof Struct { +private class StructItemNode extends TypeItemNode, ParameterizableItemNode instanceof Struct { override string getName() { result = Struct.super.getName().getText() } override Namespace getNamespace() { @@ -897,9 +890,7 @@ private class StructItemNode extends TypeItemNode, CallableItemNode instanceof S override Visibility getVisibility() { result = Struct.super.getVisibility() } - override int getNumberOfParameters() { - result = super.getFieldList().(TupleFieldList).getNumberOfFields() - } + override int getArity() { result = super.getFieldList().(TupleFieldList).getNumberOfFields() } override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) } @@ -1717,7 +1708,7 @@ private ItemNode resolvePathCand(RelevantPath path) { or exists(CallExpr ce | path = CallExprImpl::getFunctionPath(ce) and - result.(CallableItemNode).getNumberOfParameters() = ce.getNumberOfArgs() + result.(ParameterizableItemNode).getArity() = ce.getNumberOfArgs() ) ) } From 2c29f210046a362db85023cbb4a08d7d12865f1d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 26 Sep 2025 13:59:53 +0200 Subject: [PATCH 80/90] Shared: Address review comments. --- .../codeql/controlflow/ControlFlow.qll | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/shared/controlflow/codeql/controlflow/ControlFlow.qll b/shared/controlflow/codeql/controlflow/ControlFlow.qll index ca0de9d4744..7fd6ec70bfc 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlow.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlow.qll @@ -278,7 +278,7 @@ module Make< exists(Expr e | def.getDefinition() = e and exprHasValue(e, gv) and - (exists(GuardValue gv0 | exprHasValue(e, gv0) and gv0.isSingleton()) implies gv.isSingleton()) + (any(GuardValue gv0 | exprHasValue(e, gv0)).isSingleton() implies gv.isSingleton()) ) } @@ -595,7 +595,7 @@ module Make< ) { ssaControlsBranchEdge(t, bb1, bb2, gv) and ( - exists(GuardValue gv0 | ssaControlsBranchEdge(t, bb1, bb2, gv0) and gv0.isSingleton()) + any(GuardValue gv0 | ssaControlsBranchEdge(t, bb1, bb2, gv0)).isSingleton() implies gv.isSingleton() ) and @@ -694,7 +694,7 @@ module Make< * `src`, and `var` is a relevant splitting variable that gets (re-)defined * in `bb2` by `t`, which is not a phi node. * - * `val` is the best known value for `t` in `bb2`. + * `val` is the best known value that is relatable to `condgv` for `t` in `bb2`. */ private predicate stepSsaValueRedef( SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, @@ -720,7 +720,8 @@ module Make< * `t2`, in `bb2` taking input from `t1` along this edge. Furthermore, * there is no further redefinition of `var` in `bb2`. * - * `val` is the best value for `t1`/`t2` implied by taking this edge. + * `val` is the best value that is relatable to `condgv` for `t1`/`t2` + * implied by taking this edge. */ private predicate stepSsaValuePhi( SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, @@ -747,7 +748,7 @@ module Make< * redefinition along this edge nor in `bb2`. * * Additionally, this edge implies that the SSA definition `t` of `var` has - * value `val`. + * value `val` and that `val` is relatable to `condgv`. */ private predicate stepSsaValueNoRedef( SourceVariable src, BasicBlock bb1, BasicBlock bb2, SourceVariable var, GuardValue condgv, @@ -763,6 +764,12 @@ module Make< /** * Holds if the source `srcDef` in `srcBb` may reach `def` in `bb`. The * taken path takes splitting based on the value of `var` into account. + * + * When multiple `GuardValue`s can be chosen for `var`, we prioritize those + * that are relatable to `condgv`, as that will help determine whether a + * particular edge may be taken or not. Singleton values are prioritized + * highly as they are in principle relatable to every other `GuardValue`. + * * The pair `(tracked, val)` is the current SSA definition and known value * for `var` in `bb`. */ From 3e9332edfa722f7df6e3ceb0e45b230f0036f605 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 13:16:45 +0100 Subject: [PATCH 81/90] Fix formatting in codeql-cli-2.23.1.rst --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 3767c877b5a..920638fdc87 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:`\ ` to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:``\`` to the beginning. Java/Kotlin """"""""""" From a4f5e9aaf5277a72e4a1aa995fc2de00b982dbfb Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 13:46:12 +0100 Subject: [PATCH 82/90] Update changelog for CodeQL CLI 2.23.1 Added acknowledgment for the original contributor of the 'Permissive CORS configuration' query and clarified the detection of path injection in Go. --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index 920638fdc87..c93bd8af0c3 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -88,7 +88,7 @@ JavaScript/TypeScript * Data flow is now tracked through the :code:`Promise.try` and :code:`Array.prototype.with` functions. * Query :code:`js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. * The query :code:`js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as :code:`Object.keys()`. -* The query "Permissive CORS configuration" (:code:`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. +* The query "Permissive CORS configuration" (:code:`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who [submitted the original experimental query](https://github.com/github/codeql/pull/14342)! Python """""" @@ -126,7 +126,7 @@ Golang """""" * The second argument of the :code:`CreateTemp` function, from the :code:`os` package, is no longer a path-injection sink due to proper sanitization by Go. -* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or :code:``\`` to the beginning. +* The query "Uncontrolled data used in path expression" (:code:`go/path-injection`) now detects sanitizing a path by adding :code:`os.PathSeparator` or ``\`` to the beginning. Java/Kotlin """"""""""" From 5a0bae27ac97393c76c1470cfccc0828dabb33e5 Mon Sep 17 00:00:00 2001 From: Florin Coada Date: Fri, 26 Sep 2025 13:57:57 +0100 Subject: [PATCH 83/90] Update changelog for CodeQL CLI 2.23.1 --- .../codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst index c93bd8af0c3..1c4ac199687 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.23.1.rst @@ -88,7 +88,7 @@ JavaScript/TypeScript * Data flow is now tracked through the :code:`Promise.try` and :code:`Array.prototype.with` functions. * Query :code:`js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test. * The query :code:`js/remote-property-injection` now detects property injection vulnerabilities through object enumeration patterns such as :code:`Object.keys()`. -* The query "Permissive CORS configuration" (:code:`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who [submitted the original experimental query](https://github.com/github/codeql/pull/14342)! +* The query "Permissive CORS configuration" (:code:`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. Thank you to @maikypedia who `submitted the original experimental query `__! Python """""" From 27b6f12b3c0414dc1a498a8c564da7dac37f99c4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 14:30:27 +0100 Subject: [PATCH 84/90] Rust: Use the suggested cleaner implementation for getStmtOrExpr. --- rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll index 648a4eab9b8..9120728dcbc 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll @@ -33,7 +33,7 @@ module Impl { AstNode getStmtOrExpr(int index) { result = this.getStatement(index) or - index = max(int i | i = -1 or exists(this.getStatement(i))) + 1 and + index = this.getNumberOfStatements() and result = this.getTailExpr() } From 4570d7e46e205703ef46e4c997601ce322567e6f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 14:32:05 +0100 Subject: [PATCH 85/90] Rust: Replace getBlockChildNode with uses of getStmtOrExpr. --- .../controlflow/internal/ControlFlowGraphImpl.qll | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index ddc4dae9b95..609a68fc392 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -266,15 +266,8 @@ module ExprTrees { } } - private AstNode getBlockChildNode(BlockExpr b, int i) { - result = b.getStmtList().getStatement(i) - or - i = b.getStmtList().getNumberOfStatements() and - result = b.getStmtList().getTailExpr() - } - class AsyncBlockExprTree extends StandardTree, PreOrderTree, PostOrderTree, AsyncBlockExpr { - override AstNode getChildNode(int i) { result = getBlockChildNode(this, i) } + override AstNode getChildNode(int i) { result = this.getStmtList().getStmtOrExpr(i) } override predicate propagatesAbnormal(AstNode child) { none() } } @@ -282,7 +275,7 @@ module ExprTrees { class BlockExprTree extends StandardPostOrderTree, BlockExpr { BlockExprTree() { not this.isAsync() } - override AstNode getChildNode(int i) { result = getBlockChildNode(this, i) } + override AstNode getChildNode(int i) { result = this.getStmtList().getStmtOrExpr(i) } override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) } } From 1236e2b8295cc3202e19ec76c433c374cb54bbb4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 26 Sep 2025 14:55:06 +0100 Subject: [PATCH 86/90] Rust: Add references to alternatives in the getStmtOrExpr methods. --- .../ql/lib/codeql/rust/elements/internal/StmtListImpl.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll index 9120728dcbc..d56b4c49ce2 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StmtListImpl.qll @@ -29,6 +29,10 @@ module Impl { class StmtList extends Generated::StmtList { /** * Gets the `index`th statement or expression of this statement list (0-based). + * + * This includes both the statements and any tail expression in the statement list. To access + * just the statements, use `getStatement`. To access just the tail expression, if any, + * use `getTailExpr`. */ AstNode getStmtOrExpr(int index) { result = this.getStatement(index) @@ -39,6 +43,10 @@ module Impl { /** * Gets any of the statements or expressions of this statement list. + * + * This includes both the statements and any tail expression in the statement list. To access + * just the statements, use `getAStatement`. To access just the tail expression, if any, + * use `getTailExpr`. */ final AstNode getAStmtOrExpr() { result = this.getStmtOrExpr(_) } From f5f61193a03b0c1697e28138503f3977d98fdac5 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com> Date: Fri, 26 Sep 2025 15:33:26 +0100 Subject: [PATCH 87/90] Delete change note --- go/ql/src/change-notes/2025-09-25-exponentiation-constants.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 go/ql/src/change-notes/2025-09-25-exponentiation-constants.md diff --git a/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md b/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md deleted file mode 100644 index cb6c5e43346..00000000000 --- a/go/ql/src/change-notes/2025-09-25-exponentiation-constants.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The query `go/mistyped-exponentiation` now recognises constants whose initialisers are hex or octal constants, making them likely targets of the `^` bitwise-xor operator. From d2130a589be81b1575495e4e1da96b350d1bbbd5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 10:28:45 +0000 Subject: [PATCH 88/90] Release preparation for version 2.23.2 --- actions/ql/lib/CHANGELOG.md | 4 ++++ actions/ql/lib/change-notes/released/0.4.18.md | 3 +++ actions/ql/lib/codeql-pack.release.yml | 2 +- actions/ql/lib/qlpack.yml | 2 +- actions/ql/src/CHANGELOG.md | 4 ++++ actions/ql/src/change-notes/released/0.6.10.md | 3 +++ actions/ql/src/codeql-pack.release.yml | 2 +- actions/ql/src/qlpack.yml | 2 +- cpp/ql/lib/CHANGELOG.md | 4 ++++ cpp/ql/lib/change-notes/released/5.6.1.md | 3 +++ cpp/ql/lib/codeql-pack.release.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/CHANGELOG.md | 4 ++++ cpp/ql/src/change-notes/released/1.5.1.md | 3 +++ cpp/ql/src/codeql-pack.release.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++ .../Solorigate/lib/change-notes/released/1.7.49.md | 3 +++ .../ql/campaigns/Solorigate/lib/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++ .../Solorigate/src/change-notes/released/1.7.49.md | 3 +++ .../ql/campaigns/Solorigate/src/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/CHANGELOG.md | 4 ++++ csharp/ql/lib/change-notes/released/5.2.5.md | 3 +++ csharp/ql/lib/codeql-pack.release.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/CHANGELOG.md | 7 +++++++ .../change-notes/2025-09-16-code-quality-doc-query.md | 4 ---- .../1.4.1.md} | 8 +++++--- csharp/ql/src/codeql-pack.release.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/consistency-queries/CHANGELOG.md | 4 ++++ .../consistency-queries/change-notes/released/1.0.32.md | 3 +++ go/ql/consistency-queries/codeql-pack.release.yml | 2 +- go/ql/consistency-queries/qlpack.yml | 2 +- go/ql/lib/CHANGELOG.md | 4 ++++ go/ql/lib/change-notes/released/4.3.5.md | 3 +++ go/ql/lib/codeql-pack.release.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/CHANGELOG.md | 4 ++++ go/ql/src/change-notes/released/1.4.6.md | 3 +++ go/ql/src/codeql-pack.release.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/CHANGELOG.md | 4 ++++ java/ql/lib/change-notes/released/7.7.1.md | 3 +++ java/ql/lib/codeql-pack.release.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/CHANGELOG.md | 4 ++++ java/ql/src/change-notes/released/1.8.1.md | 3 +++ java/ql/src/codeql-pack.release.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/CHANGELOG.md | 8 ++++++++ javascript/ql/lib/change-notes/2025-07-28-dynamodb.md | 4 ---- .../ql/lib/change-notes/2025-09-17-graphql-enhance.md | 4 ---- .../lib/change-notes/2025-09-19-graphql-type-object.md | 4 ---- javascript/ql/lib/change-notes/released/2.6.12.md | 7 +++++++ javascript/ql/lib/codeql-pack.release.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/CHANGELOG.md | 4 ++++ javascript/ql/src/change-notes/released/2.1.1.md | 3 +++ javascript/ql/src/codeql-pack.release.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/CHANGELOG.md | 4 ++++ misc/suite-helpers/change-notes/released/1.0.32.md | 3 +++ misc/suite-helpers/codeql-pack.release.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/CHANGELOG.md | 6 ++++++ .../4.0.16.md} | 9 +++++---- python/ql/lib/codeql-pack.release.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/CHANGELOG.md | 8 ++++++++ .../ql/src/change-notes/2025-08-19-signature-mismatch.md | 5 ----- ...-19-fix-unmatchable-dollar-and-caret-in-assertions.md | 5 ----- python/ql/src/change-notes/released/1.6.6.md | 7 +++++++ python/ql/src/codeql-pack.release.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/CHANGELOG.md | 6 ++++++ .../5.1.0.md} | 9 +++++---- ruby/ql/lib/codeql-pack.release.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/CHANGELOG.md | 4 ++++ ruby/ql/src/change-notes/released/1.4.6.md | 3 +++ ruby/ql/src/codeql-pack.release.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- rust/ql/lib/CHANGELOG.md | 9 +++++++++ .../{2025-09-19-parameter-mad.md => released/0.1.17.md} | 9 +++++---- rust/ql/lib/codeql-pack.release.yml | 2 +- rust/ql/lib/qlpack.yml | 2 +- rust/ql/src/CHANGELOG.md | 6 ++++++ rust/ql/src/change-notes/2025-09-15-non-https-url.md | 4 ---- rust/ql/src/change-notes/released/0.1.17.md | 5 +++++ rust/ql/src/codeql-pack.release.yml | 2 +- rust/ql/src/qlpack.yml | 2 +- shared/concepts/CHANGELOG.md | 4 ++++ shared/concepts/change-notes/released/0.0.6.md | 3 +++ shared/concepts/codeql-pack.release.yml | 2 +- shared/concepts/qlpack.yml | 2 +- shared/controlflow/CHANGELOG.md | 4 ++++ shared/controlflow/change-notes/released/2.0.16.md | 3 +++ shared/controlflow/codeql-pack.release.yml | 2 +- shared/controlflow/qlpack.yml | 2 +- shared/dataflow/CHANGELOG.md | 4 ++++ shared/dataflow/change-notes/released/2.0.16.md | 3 +++ shared/dataflow/codeql-pack.release.yml | 2 +- shared/dataflow/qlpack.yml | 2 +- shared/mad/CHANGELOG.md | 4 ++++ shared/mad/change-notes/released/1.0.32.md | 3 +++ shared/mad/codeql-pack.release.yml | 2 +- shared/mad/qlpack.yml | 2 +- shared/quantum/CHANGELOG.md | 4 ++++ shared/quantum/change-notes/released/0.0.10.md | 3 +++ shared/quantum/codeql-pack.release.yml | 2 +- shared/quantum/qlpack.yml | 2 +- shared/rangeanalysis/CHANGELOG.md | 4 ++++ shared/rangeanalysis/change-notes/released/1.0.32.md | 3 +++ shared/rangeanalysis/codeql-pack.release.yml | 2 +- shared/rangeanalysis/qlpack.yml | 2 +- shared/regex/CHANGELOG.md | 4 ++++ shared/regex/change-notes/released/1.0.32.md | 3 +++ shared/regex/codeql-pack.release.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/CHANGELOG.md | 4 ++++ shared/ssa/change-notes/released/2.0.8.md | 3 +++ shared/ssa/codeql-pack.release.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/threat-models/CHANGELOG.md | 4 ++++ shared/threat-models/change-notes/released/1.0.32.md | 3 +++ shared/threat-models/codeql-pack.release.yml | 2 +- shared/threat-models/qlpack.yml | 2 +- shared/tutorial/CHANGELOG.md | 4 ++++ shared/tutorial/change-notes/released/1.0.32.md | 3 +++ shared/tutorial/codeql-pack.release.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typeflow/CHANGELOG.md | 4 ++++ shared/typeflow/change-notes/released/1.0.32.md | 3 +++ shared/typeflow/codeql-pack.release.yml | 2 +- shared/typeflow/qlpack.yml | 2 +- shared/typeinference/CHANGELOG.md | 4 ++++ shared/typeinference/change-notes/released/0.0.13.md | 3 +++ shared/typeinference/codeql-pack.release.yml | 2 +- shared/typeinference/qlpack.yml | 2 +- shared/typetracking/CHANGELOG.md | 4 ++++ shared/typetracking/change-notes/released/2.0.16.md | 3 +++ shared/typetracking/codeql-pack.release.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/CHANGELOG.md | 4 ++++ shared/typos/change-notes/released/1.0.32.md | 3 +++ shared/typos/codeql-pack.release.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/CHANGELOG.md | 4 ++++ shared/util/change-notes/released/2.0.19.md | 3 +++ shared/util/codeql-pack.release.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/xml/CHANGELOG.md | 4 ++++ shared/xml/change-notes/released/1.0.32.md | 3 +++ shared/xml/codeql-pack.release.yml | 2 +- shared/xml/qlpack.yml | 2 +- shared/yaml/CHANGELOG.md | 4 ++++ shared/yaml/change-notes/released/1.0.32.md | 3 +++ shared/yaml/codeql-pack.release.yml | 2 +- shared/yaml/qlpack.yml | 2 +- swift/ql/lib/CHANGELOG.md | 4 ++++ swift/ql/lib/change-notes/released/5.0.8.md | 3 +++ swift/ql/lib/codeql-pack.release.yml | 2 +- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/CHANGELOG.md | 4 ++++ swift/ql/src/change-notes/released/1.2.6.md | 3 +++ swift/ql/src/codeql-pack.release.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 171 files changed, 409 insertions(+), 127 deletions(-) create mode 100644 actions/ql/lib/change-notes/released/0.4.18.md create mode 100644 actions/ql/src/change-notes/released/0.6.10.md create mode 100644 cpp/ql/lib/change-notes/released/5.6.1.md create mode 100644 cpp/ql/src/change-notes/released/1.5.1.md create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.49.md create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.49.md create mode 100644 csharp/ql/lib/change-notes/released/5.2.5.md delete mode 100644 csharp/ql/src/change-notes/2025-09-16-code-quality-doc-query.md rename csharp/ql/src/change-notes/{2025-09-17-nullguard-pattern.md => released/1.4.1.md} (55%) create mode 100644 go/ql/consistency-queries/change-notes/released/1.0.32.md create mode 100644 go/ql/lib/change-notes/released/4.3.5.md create mode 100644 go/ql/src/change-notes/released/1.4.6.md create mode 100644 java/ql/lib/change-notes/released/7.7.1.md create mode 100644 java/ql/src/change-notes/released/1.8.1.md delete mode 100644 javascript/ql/lib/change-notes/2025-07-28-dynamodb.md delete mode 100644 javascript/ql/lib/change-notes/2025-09-17-graphql-enhance.md delete mode 100644 javascript/ql/lib/change-notes/2025-09-19-graphql-type-object.md create mode 100644 javascript/ql/lib/change-notes/released/2.6.12.md create mode 100644 javascript/ql/src/change-notes/released/2.1.1.md create mode 100644 misc/suite-helpers/change-notes/released/1.0.32.md rename python/ql/lib/change-notes/{2025-08-11-jump-step-global-nested.md => released/4.0.16.md} (68%) delete mode 100644 python/ql/src/change-notes/2025-08-19-signature-mismatch.md delete mode 100644 python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md create mode 100644 python/ql/src/change-notes/released/1.6.6.md rename ruby/ql/lib/change-notes/{2025-09-15-grape-framework-support.md => released/5.1.0.md} (70%) create mode 100644 ruby/ql/src/change-notes/released/1.4.6.md rename rust/ql/lib/change-notes/{2025-09-19-parameter-mad.md => released/0.1.17.md} (85%) delete mode 100644 rust/ql/src/change-notes/2025-09-15-non-https-url.md create mode 100644 rust/ql/src/change-notes/released/0.1.17.md create mode 100644 shared/concepts/change-notes/released/0.0.6.md create mode 100644 shared/controlflow/change-notes/released/2.0.16.md create mode 100644 shared/dataflow/change-notes/released/2.0.16.md create mode 100644 shared/mad/change-notes/released/1.0.32.md create mode 100644 shared/quantum/change-notes/released/0.0.10.md create mode 100644 shared/rangeanalysis/change-notes/released/1.0.32.md create mode 100644 shared/regex/change-notes/released/1.0.32.md create mode 100644 shared/ssa/change-notes/released/2.0.8.md create mode 100644 shared/threat-models/change-notes/released/1.0.32.md create mode 100644 shared/tutorial/change-notes/released/1.0.32.md create mode 100644 shared/typeflow/change-notes/released/1.0.32.md create mode 100644 shared/typeinference/change-notes/released/0.0.13.md create mode 100644 shared/typetracking/change-notes/released/2.0.16.md create mode 100644 shared/typos/change-notes/released/1.0.32.md create mode 100644 shared/util/change-notes/released/2.0.19.md create mode 100644 shared/xml/change-notes/released/1.0.32.md create mode 100644 shared/yaml/change-notes/released/1.0.32.md create mode 100644 swift/ql/lib/change-notes/released/5.0.8.md create mode 100644 swift/ql/src/change-notes/released/1.2.6.md diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md index 60f6a45ea94..e6ae9a82059 100644 --- a/actions/ql/lib/CHANGELOG.md +++ b/actions/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.18 + +No user-facing changes. + ## 0.4.17 No user-facing changes. diff --git a/actions/ql/lib/change-notes/released/0.4.18.md b/actions/ql/lib/change-notes/released/0.4.18.md new file mode 100644 index 00000000000..a6a7b2e276b --- /dev/null +++ b/actions/ql/lib/change-notes/released/0.4.18.md @@ -0,0 +1,3 @@ +## 0.4.18 + +No user-facing changes. diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml index d5b31a0cac9..1a848f92899 100644 --- a/actions/ql/lib/codeql-pack.release.yml +++ b/actions/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.17 +lastReleaseVersion: 0.4.18 diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index 266007af096..bfebfa99d04 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.18-dev +version: 0.4.18 library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md index 78b4591c521..534ba89566b 100644 --- a/actions/ql/src/CHANGELOG.md +++ b/actions/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.10 + +No user-facing changes. + ## 0.6.9 ### Minor Analysis Improvements diff --git a/actions/ql/src/change-notes/released/0.6.10.md b/actions/ql/src/change-notes/released/0.6.10.md new file mode 100644 index 00000000000..048cd0c98ba --- /dev/null +++ b/actions/ql/src/change-notes/released/0.6.10.md @@ -0,0 +1,3 @@ +## 0.6.10 + +No user-facing changes. diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml index f03da398190..c2eebb652b0 100644 --- a/actions/ql/src/codeql-pack.release.yml +++ b/actions/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.9 +lastReleaseVersion: 0.6.10 diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index e4a69c7cd61..9dba67fea76 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.10-dev +version: 0.6.10 library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index cfe24937b74..0909c8e3c88 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.6.1 + +No user-facing changes. + ## 5.6.0 ### Deprecated APIs diff --git a/cpp/ql/lib/change-notes/released/5.6.1.md b/cpp/ql/lib/change-notes/released/5.6.1.md new file mode 100644 index 00000000000..368d902c7fe --- /dev/null +++ b/cpp/ql/lib/change-notes/released/5.6.1.md @@ -0,0 +1,3 @@ +## 5.6.1 + +No user-facing changes. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index df73323b21f..2dcac412aa9 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 5.6.0 +lastReleaseVersion: 5.6.1 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 63500a12a2f..23bf4d8fc9e 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 5.6.1-dev +version: 5.6.1 groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 0cafbd23191..39549ed1bdc 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.5.1 + +No user-facing changes. + ## 1.5.0 ### Major Analysis Improvements diff --git a/cpp/ql/src/change-notes/released/1.5.1.md b/cpp/ql/src/change-notes/released/1.5.1.md new file mode 100644 index 00000000000..7b24a64aca3 --- /dev/null +++ b/cpp/ql/src/change-notes/released/1.5.1.md @@ -0,0 +1,3 @@ +## 1.5.1 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 639f80c4341..c5775c46013 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.5.0 +lastReleaseVersion: 1.5.1 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 8b6b27302cc..7322e2571d1 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.5.1-dev +version: 1.5.1 groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 41b8b166a6c..bcfd38e1494 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.49 + +No user-facing changes. + ## 1.7.48 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.49.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.49.md new file mode 100644 index 00000000000..431bff76c0b --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.49.md @@ -0,0 +1,3 @@ +## 1.7.49 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index f5fe8023097..fe16fdfefdc 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.48 +lastReleaseVersion: 1.7.49 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index bc2dd9a229c..02e6cddfc17 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.7.49-dev +version: 1.7.49 groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 41b8b166a6c..bcfd38e1494 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.49 + +No user-facing changes. + ## 1.7.48 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.49.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.49.md new file mode 100644 index 00000000000..431bff76c0b --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.49.md @@ -0,0 +1,3 @@ +## 1.7.49 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index f5fe8023097..fe16fdfefdc 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.7.48 +lastReleaseVersion: 1.7.49 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 82cad1a6472..84e6c8ef7e0 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.7.49-dev +version: 1.7.49 groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index cb639225e7d..095eab5cdba 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.2.5 + +No user-facing changes. + ## 5.2.4 No user-facing changes. diff --git a/csharp/ql/lib/change-notes/released/5.2.5.md b/csharp/ql/lib/change-notes/released/5.2.5.md new file mode 100644 index 00000000000..bd0e1157099 --- /dev/null +++ b/csharp/ql/lib/change-notes/released/5.2.5.md @@ -0,0 +1,3 @@ +## 5.2.5 + +No user-facing changes. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index fc4dc64578b..63222f8b4a0 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 5.2.4 +lastReleaseVersion: 5.2.5 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index f5795e12558..aba9ee98b5a 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 5.2.5-dev +version: 5.2.5 groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index e044a3dbb4f..e432045f72e 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.4.1 + +### Minor Analysis Improvements + +* The modeling of null guards based on complex pattern expressions has been improved, which in turn improves the query `cs/dereferenced-value-may-be-null` by removing false positives. +* Remove the query `cs/xmldoc/missing-summary` from the `code-quality` suite (align with other languages). + ## 1.4.0 ### Deprecated Queries diff --git a/csharp/ql/src/change-notes/2025-09-16-code-quality-doc-query.md b/csharp/ql/src/change-notes/2025-09-16-code-quality-doc-query.md deleted file mode 100644 index 8972be616b9..00000000000 --- a/csharp/ql/src/change-notes/2025-09-16-code-quality-doc-query.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Remove the query `cs/xmldoc/missing-summary` from the `code-quality` suite (align with other languages). diff --git a/csharp/ql/src/change-notes/2025-09-17-nullguard-pattern.md b/csharp/ql/src/change-notes/released/1.4.1.md similarity index 55% rename from csharp/ql/src/change-notes/2025-09-17-nullguard-pattern.md rename to csharp/ql/src/change-notes/released/1.4.1.md index 49b76c25b0b..48b31092714 100644 --- a/csharp/ql/src/change-notes/2025-09-17-nullguard-pattern.md +++ b/csharp/ql/src/change-notes/released/1.4.1.md @@ -1,4 +1,6 @@ ---- -category: minorAnalysis ---- +## 1.4.1 + +### Minor Analysis Improvements + * The modeling of null guards based on complex pattern expressions has been improved, which in turn improves the query `cs/dereferenced-value-may-be-null` by removing false positives. +* Remove the query `cs/xmldoc/missing-summary` from the `code-quality` suite (align with other languages). diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index b8b2e97d508..43ccf4467be 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.4.0 +lastReleaseVersion: 1.4.1 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 724ec4c0097..7ecdec07f35 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.4.1-dev +version: 1.4.1 groups: - csharp - queries diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md index d5040623557..331bb4c220e 100644 --- a/go/ql/consistency-queries/CHANGELOG.md +++ b/go/ql/consistency-queries/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/go/ql/consistency-queries/change-notes/released/1.0.32.md b/go/ql/consistency-queries/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/go/ql/consistency-queries/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/go/ql/consistency-queries/codeql-pack.release.yml +++ b/go/ql/consistency-queries/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index 3a3f60920be..3b1e2d9586b 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.32-dev +version: 1.0.32 groups: - go - queries diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 50d61186f73..adf218a99e4 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.3.5 + +No user-facing changes. + ## 4.3.4 ### Minor Analysis Improvements diff --git a/go/ql/lib/change-notes/released/4.3.5.md b/go/ql/lib/change-notes/released/4.3.5.md new file mode 100644 index 00000000000..e386c2fbd98 --- /dev/null +++ b/go/ql/lib/change-notes/released/4.3.5.md @@ -0,0 +1,3 @@ +## 4.3.5 + +No user-facing changes. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index f755e0936a7..d6a08512942 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 4.3.4 +lastReleaseVersion: 4.3.5 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 1e8bdd280f7..bc9bf12c80c 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 4.3.5-dev +version: 4.3.5 groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index c3b9c32ff32..65d6436fce3 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.6 + +No user-facing changes. + ## 1.4.5 No user-facing changes. diff --git a/go/ql/src/change-notes/released/1.4.6.md b/go/ql/src/change-notes/released/1.4.6.md new file mode 100644 index 00000000000..5146f9e1cbf --- /dev/null +++ b/go/ql/src/change-notes/released/1.4.6.md @@ -0,0 +1,3 @@ +## 1.4.6 + +No user-facing changes. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index a74b6b08d86..3b00bbce928 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.4.5 +lastReleaseVersion: 1.4.6 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 9320b29d8e8..816d4b95867 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.4.6-dev +version: 1.4.6 groups: - go - queries diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index a6b4649e42e..0e74414917b 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.7.1 + +No user-facing changes. + ## 7.7.0 ### New Features diff --git a/java/ql/lib/change-notes/released/7.7.1.md b/java/ql/lib/change-notes/released/7.7.1.md new file mode 100644 index 00000000000..7349fc621cc --- /dev/null +++ b/java/ql/lib/change-notes/released/7.7.1.md @@ -0,0 +1,3 @@ +## 7.7.1 + +No user-facing changes. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 5c876a864fc..c94dbb3cd65 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.7.0 +lastReleaseVersion: 7.7.1 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 3009b1b327f..7d0153cc566 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 7.7.1-dev +version: 7.7.1 groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index 022442a1628..1e6df88fc31 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.8.1 + +No user-facing changes. + ## 1.8.0 ### Major Analysis Improvements diff --git a/java/ql/src/change-notes/released/1.8.1.md b/java/ql/src/change-notes/released/1.8.1.md new file mode 100644 index 00000000000..0b1a7cdad10 --- /dev/null +++ b/java/ql/src/change-notes/released/1.8.1.md @@ -0,0 +1,3 @@ +## 1.8.1 + +No user-facing changes. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index dc8a37cc443..28a7c123ae8 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.0 +lastReleaseVersion: 1.8.1 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index 01bf070bb07..bbfafc65503 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.8.1-dev +version: 1.8.1 groups: - java - queries diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index b98534e791d..975d14e1098 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.6.12 + +### Minor Analysis Improvements + +* Added modeling of `GraphQLObjectType` resolver function parameters as remote sources. +* Support for the [graphql](https://www.npmjs.com/package/graphql) library has been improved. Data flow from GraphQL query sources and variables to resolver function parameters is now tracked. +* Added support for the `aws-sdk` and `@aws-sdk/client-dynamodb`, `@aws-sdk/client-athena`, `@aws-sdk/client-s3`, and `@aws-sdk/client-rds-data` packages. + ## 2.6.11 ### Minor Analysis Improvements diff --git a/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md b/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md deleted file mode 100644 index bbf5d57163a..00000000000 --- a/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added support for the `aws-sdk` and `@aws-sdk/client-dynamodb`, `@aws-sdk/client-athena`, `@aws-sdk/client-s3`, and `@aws-sdk/client-rds-data` packages. diff --git a/javascript/ql/lib/change-notes/2025-09-17-graphql-enhance.md b/javascript/ql/lib/change-notes/2025-09-17-graphql-enhance.md deleted file mode 100644 index cb0b886a6f7..00000000000 --- a/javascript/ql/lib/change-notes/2025-09-17-graphql-enhance.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Support for the [graphql](https://www.npmjs.com/package/graphql) library has been improved. Data flow from GraphQL query sources and variables to resolver function parameters is now tracked. diff --git a/javascript/ql/lib/change-notes/2025-09-19-graphql-type-object.md b/javascript/ql/lib/change-notes/2025-09-19-graphql-type-object.md deleted file mode 100644 index 6afa4ece331..00000000000 --- a/javascript/ql/lib/change-notes/2025-09-19-graphql-type-object.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added modeling of `GraphQLObjectType` resolver function parameters as remote sources. diff --git a/javascript/ql/lib/change-notes/released/2.6.12.md b/javascript/ql/lib/change-notes/released/2.6.12.md new file mode 100644 index 00000000000..adc136621d8 --- /dev/null +++ b/javascript/ql/lib/change-notes/released/2.6.12.md @@ -0,0 +1,7 @@ +## 2.6.12 + +### Minor Analysis Improvements + +* Added modeling of `GraphQLObjectType` resolver function parameters as remote sources. +* Support for the [graphql](https://www.npmjs.com/package/graphql) library has been improved. Data flow from GraphQL query sources and variables to resolver function parameters is now tracked. +* Added support for the `aws-sdk` and `@aws-sdk/client-dynamodb`, `@aws-sdk/client-athena`, `@aws-sdk/client-s3`, and `@aws-sdk/client-rds-data` packages. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index a31eb42966c..8b34428a845 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.6.11 +lastReleaseVersion: 2.6.12 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 1d05d1003f3..74ccf251956 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.6.12-dev +version: 2.6.12 groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index 4067c050c2a..46aae437f77 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.1 + +No user-facing changes. + ## 2.1.0 ### Major Analysis Improvements diff --git a/javascript/ql/src/change-notes/released/2.1.1.md b/javascript/ql/src/change-notes/released/2.1.1.md new file mode 100644 index 00000000000..f023e9166c2 --- /dev/null +++ b/javascript/ql/src/change-notes/released/2.1.1.md @@ -0,0 +1,3 @@ +## 2.1.1 + +No user-facing changes. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 487a1a58b2b..576c2ea18d6 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.1.0 +lastReleaseVersion: 2.1.1 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 916ad1339b2..cafde25bbf9 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.1.1-dev +version: 2.1.1 groups: - javascript - queries diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 6b54042fef3..4cbaa48190d 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/1.0.32.md b/misc/suite-helpers/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/misc/suite-helpers/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 72c2f165759..7d71d83613d 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.32-dev +version: 1.0.32 groups: shared warnOnImplicitThis: true diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 6a4fefd4446..070309c08a0 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 4.0.16 + +### Minor Analysis Improvements + +* Data flow tracking through global variables now supports nested field access patterns such as `global_var.obj.field`. This improves the precision of taint tracking analysis when data flows through complex global variable structures. + ## 4.0.15 No user-facing changes. diff --git a/python/ql/lib/change-notes/2025-08-11-jump-step-global-nested.md b/python/ql/lib/change-notes/released/4.0.16.md similarity index 68% rename from python/ql/lib/change-notes/2025-08-11-jump-step-global-nested.md rename to python/ql/lib/change-notes/released/4.0.16.md index 4109bb78825..025815a5c02 100644 --- a/python/ql/lib/change-notes/2025-08-11-jump-step-global-nested.md +++ b/python/ql/lib/change-notes/released/4.0.16.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- -* Data flow tracking through global variables now supports nested field access patterns such as `global_var.obj.field`. This improves the precision of taint tracking analysis when data flows through complex global variable structures. \ No newline at end of file +## 4.0.16 + +### Minor Analysis Improvements + +* Data flow tracking through global variables now supports nested field access patterns such as `global_var.obj.field`. This improves the precision of taint tracking analysis when data flows through complex global variable structures. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index eef62765883..916d99df3ad 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 4.0.15 +lastReleaseVersion: 4.0.16 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 61875fc7f4e..5eba946c3cf 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 4.0.16-dev +version: 4.0.16 groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index de3fc1ddf2b..e620dee4fca 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.6.6 + +### Minor Analysis Improvements + +- The queries that check for unmatchable `$` and `^` in regular expressions did not account correctly for occurrences inside lookahead and lookbehind assertions. These occurrences are now handled correctly, eliminating this source of false positives. +* The `py/inheritance/signature-mismatch` query has been modernized. It produces more precise results and more descriptive alert messages. +* The `py/inheritance/incorrect-overriding-signature` query has been deprecated. Its results have been consolidated into the `py/inheritance/signature-mismatch` query. + ## 1.6.5 ### Minor Analysis Improvements diff --git a/python/ql/src/change-notes/2025-08-19-signature-mismatch.md b/python/ql/src/change-notes/2025-08-19-signature-mismatch.md deleted file mode 100644 index 60c3efa32eb..00000000000 --- a/python/ql/src/change-notes/2025-08-19-signature-mismatch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* The `py/inheritance/signature-mismatch` query has been modernized. It produces more precise results and more descriptive alert messages. -* The `py/inheritance/incorrect-overriding-signature` query has been deprecated. Its results have been consolidated into the `py/inheritance/signature-mismatch` query. \ No newline at end of file diff --git a/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md b/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md deleted file mode 100644 index cf63dd9ed4d..00000000000 --- a/python/ql/src/change-notes/2025-09-19-fix-unmatchable-dollar-and-caret-in-assertions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- - -- The queries that check for unmatchable `$` and `^` in regular expressions did not account correctly for occurrences inside lookahead and lookbehind assertions. These occurrences are now handled correctly, eliminating this source of false positives. diff --git a/python/ql/src/change-notes/released/1.6.6.md b/python/ql/src/change-notes/released/1.6.6.md new file mode 100644 index 00000000000..e1b0e3c4955 --- /dev/null +++ b/python/ql/src/change-notes/released/1.6.6.md @@ -0,0 +1,7 @@ +## 1.6.6 + +### Minor Analysis Improvements + +- The queries that check for unmatchable `$` and `^` in regular expressions did not account correctly for occurrences inside lookahead and lookbehind assertions. These occurrences are now handled correctly, eliminating this source of false positives. +* The `py/inheritance/signature-mismatch` query has been modernized. It produces more precise results and more descriptive alert messages. +* The `py/inheritance/incorrect-overriding-signature` query has been deprecated. Its results have been consolidated into the `py/inheritance/signature-mismatch` query. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 03153270557..f8e54f30a67 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.5 +lastReleaseVersion: 1.6.6 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index edf6366c64b..b42e054bdad 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.6.6-dev +version: 1.6.6 groups: - python - queries diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index b9333de9c5d..a62232991b8 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.1.0 + +### New Features + +* Initial modeling for the Ruby Grape framework in `Grape.qll` has been added to detect API endpoints, parameters, and headers within Grape API classes. + ## 5.0.4 No user-facing changes. diff --git a/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md b/ruby/ql/lib/change-notes/released/5.1.0.md similarity index 70% rename from ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md rename to ruby/ql/lib/change-notes/released/5.1.0.md index 08ceed887f2..4958aaac95f 100644 --- a/ruby/ql/lib/change-notes/2025-09-15-grape-framework-support.md +++ b/ruby/ql/lib/change-notes/released/5.1.0.md @@ -1,4 +1,5 @@ ---- -category: feature ---- -* Initial modeling for the Ruby Grape framework in `Grape.qll` has been added to detect API endpoints, parameters, and headers within Grape API classes. \ No newline at end of file +## 5.1.0 + +### New Features + +* Initial modeling for the Ruby Grape framework in `Grape.qll` has been added to detect API endpoints, parameters, and headers within Grape API classes. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 8cb0167caf0..dd8d287d010 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 5.0.4 +lastReleaseVersion: 5.1.0 diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index a2288bd3799..6dd0db034c3 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 5.0.5-dev +version: 5.1.0 groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 40209ec84bd..7811ea73f86 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.6 + +No user-facing changes. + ## 1.4.5 No user-facing changes. diff --git a/ruby/ql/src/change-notes/released/1.4.6.md b/ruby/ql/src/change-notes/released/1.4.6.md new file mode 100644 index 00000000000..5146f9e1cbf --- /dev/null +++ b/ruby/ql/src/change-notes/released/1.4.6.md @@ -0,0 +1,3 @@ +## 1.4.6 + +No user-facing changes. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index a74b6b08d86..3b00bbce928 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.4.5 +lastReleaseVersion: 1.4.6 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 084d64e8b02..ce46bf8c37a 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.4.6-dev +version: 1.4.6 groups: - ruby - queries diff --git a/rust/ql/lib/CHANGELOG.md b/rust/ql/lib/CHANGELOG.md index 809479e5fec..ec04cd624a7 100644 --- a/rust/ql/lib/CHANGELOG.md +++ b/rust/ql/lib/CHANGELOG.md @@ -1,3 +1,12 @@ +## 0.1.17 + +### New Features + +* The models-as-data format for sources now supports access paths of the form + `Argument[i].Parameter[j]`. This denotes that the source passes tainted data to + the `j`th parameter of its `i`th argument (which must be a function or a + closure). + ## 0.1.16 ### Minor Analysis Improvements diff --git a/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md b/rust/ql/lib/change-notes/released/0.1.17.md similarity index 85% rename from rust/ql/lib/change-notes/2025-09-19-parameter-mad.md rename to rust/ql/lib/change-notes/released/0.1.17.md index fa3970790fa..a2707c04150 100644 --- a/rust/ql/lib/change-notes/2025-09-19-parameter-mad.md +++ b/rust/ql/lib/change-notes/released/0.1.17.md @@ -1,7 +1,8 @@ ---- -category: feature ---- +## 0.1.17 + +### New Features + * The models-as-data format for sources now supports access paths of the form `Argument[i].Parameter[j]`. This denotes that the source passes tainted data to the `j`th parameter of its `i`th argument (which must be a function or a - closure). \ No newline at end of file + closure). diff --git a/rust/ql/lib/codeql-pack.release.yml b/rust/ql/lib/codeql-pack.release.yml index a01dca92161..eddeebba7bf 100644 --- a/rust/ql/lib/codeql-pack.release.yml +++ b/rust/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.16 +lastReleaseVersion: 0.1.17 diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 421a604aa3d..3c3ba893b14 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.1.17-dev +version: 0.1.17 groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/CHANGELOG.md b/rust/ql/src/CHANGELOG.md index 48f64efbcdb..29117e66d4c 100644 --- a/rust/ql/src/CHANGELOG.md +++ b/rust/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.1.17 + +### New Queries + +* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties. + ## 0.1.16 ### New Queries diff --git a/rust/ql/src/change-notes/2025-09-15-non-https-url.md b/rust/ql/src/change-notes/2025-09-15-non-https-url.md deleted file mode 100644 index c4ab664f732..00000000000 --- a/rust/ql/src/change-notes/2025-09-15-non-https-url.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: newQuery ---- -* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties. \ No newline at end of file diff --git a/rust/ql/src/change-notes/released/0.1.17.md b/rust/ql/src/change-notes/released/0.1.17.md new file mode 100644 index 00000000000..13cfb719c3c --- /dev/null +++ b/rust/ql/src/change-notes/released/0.1.17.md @@ -0,0 +1,5 @@ +## 0.1.17 + +### New Queries + +* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties. diff --git a/rust/ql/src/codeql-pack.release.yml b/rust/ql/src/codeql-pack.release.yml index a01dca92161..eddeebba7bf 100644 --- a/rust/ql/src/codeql-pack.release.yml +++ b/rust/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.16 +lastReleaseVersion: 0.1.17 diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index 3c122e1853b..09d251a5cb1 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.17-dev +version: 0.1.17 groups: - rust - queries diff --git a/shared/concepts/CHANGELOG.md b/shared/concepts/CHANGELOG.md index bac19b9b77f..cfaa89c5ac2 100644 --- a/shared/concepts/CHANGELOG.md +++ b/shared/concepts/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.6 + +No user-facing changes. + ## 0.0.5 No user-facing changes. diff --git a/shared/concepts/change-notes/released/0.0.6.md b/shared/concepts/change-notes/released/0.0.6.md new file mode 100644 index 00000000000..ccbce856079 --- /dev/null +++ b/shared/concepts/change-notes/released/0.0.6.md @@ -0,0 +1,3 @@ +## 0.0.6 + +No user-facing changes. diff --git a/shared/concepts/codeql-pack.release.yml b/shared/concepts/codeql-pack.release.yml index bb45a1ab018..cf398ce02aa 100644 --- a/shared/concepts/codeql-pack.release.yml +++ b/shared/concepts/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.5 +lastReleaseVersion: 0.0.6 diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index 8b0fc6c6f7a..3924d67029d 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.6-dev +version: 0.0.6 groups: shared library: true dependencies: diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md index 9b9c04fd8d8..df7e781268e 100644 --- a/shared/controlflow/CHANGELOG.md +++ b/shared/controlflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.16 + +No user-facing changes. + ## 2.0.15 No user-facing changes. diff --git a/shared/controlflow/change-notes/released/2.0.16.md b/shared/controlflow/change-notes/released/2.0.16.md new file mode 100644 index 00000000000..221400d393f --- /dev/null +++ b/shared/controlflow/change-notes/released/2.0.16.md @@ -0,0 +1,3 @@ +## 2.0.16 + +No user-facing changes. diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml index 0377ae283a3..c10461a785c 100644 --- a/shared/controlflow/codeql-pack.release.yml +++ b/shared/controlflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.15 +lastReleaseVersion: 2.0.16 diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index 56945c0709d..a0158fea04f 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.16-dev +version: 2.0.16 groups: shared library: true dependencies: diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md index 1a867888e89..13be0b19eb2 100644 --- a/shared/dataflow/CHANGELOG.md +++ b/shared/dataflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.16 + +No user-facing changes. + ## 2.0.15 No user-facing changes. diff --git a/shared/dataflow/change-notes/released/2.0.16.md b/shared/dataflow/change-notes/released/2.0.16.md new file mode 100644 index 00000000000..221400d393f --- /dev/null +++ b/shared/dataflow/change-notes/released/2.0.16.md @@ -0,0 +1,3 @@ +## 2.0.16 + +No user-facing changes. diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml index 0377ae283a3..c10461a785c 100644 --- a/shared/dataflow/codeql-pack.release.yml +++ b/shared/dataflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.15 +lastReleaseVersion: 2.0.16 diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index 4c0a9bdfe8c..3e46004181f 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.0.16-dev +version: 2.0.16 groups: shared library: true dependencies: diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md index e6cf183a1d4..9979556a421 100644 --- a/shared/mad/CHANGELOG.md +++ b/shared/mad/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/mad/change-notes/released/1.0.32.md b/shared/mad/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/mad/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/mad/codeql-pack.release.yml +++ b/shared/mad/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index b6f4e8c2bc1..1aaa401b750 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true dependencies: diff --git a/shared/quantum/CHANGELOG.md b/shared/quantum/CHANGELOG.md index a59e560c415..1857b399fe8 100644 --- a/shared/quantum/CHANGELOG.md +++ b/shared/quantum/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.10 + +No user-facing changes. + ## 0.0.9 No user-facing changes. diff --git a/shared/quantum/change-notes/released/0.0.10.md b/shared/quantum/change-notes/released/0.0.10.md new file mode 100644 index 00000000000..22391080fd4 --- /dev/null +++ b/shared/quantum/change-notes/released/0.0.10.md @@ -0,0 +1,3 @@ +## 0.0.10 + +No user-facing changes. diff --git a/shared/quantum/codeql-pack.release.yml b/shared/quantum/codeql-pack.release.yml index ecdd64fbab8..b740014e5ae 100644 --- a/shared/quantum/codeql-pack.release.yml +++ b/shared/quantum/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.9 +lastReleaseVersion: 0.0.10 diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index 3741ff55855..bf877f51d5f 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.10-dev +version: 0.0.10 groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md index 10466480900..50ea4c310f6 100644 --- a/shared/rangeanalysis/CHANGELOG.md +++ b/shared/rangeanalysis/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/rangeanalysis/change-notes/released/1.0.32.md b/shared/rangeanalysis/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/rangeanalysis/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/rangeanalysis/codeql-pack.release.yml +++ b/shared/rangeanalysis/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index e67c274bf51..5e9de8ad513 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true dependencies: diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index 3b3fcb5a55f..830e0da6f28 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/regex/change-notes/released/1.0.32.md b/shared/regex/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/regex/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 5aebaf9bffb..f69602228c9 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index e7e17bf044b..8e4b1482e78 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.8 + +No user-facing changes. + ## 2.0.7 No user-facing changes. diff --git a/shared/ssa/change-notes/released/2.0.8.md b/shared/ssa/change-notes/released/2.0.8.md new file mode 100644 index 00000000000..4d6867c721b --- /dev/null +++ b/shared/ssa/change-notes/released/2.0.8.md @@ -0,0 +1,3 @@ +## 2.0.8 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index 08d5e959449..7ffb2d9f65b 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.7 +lastReleaseVersion: 2.0.8 diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 8337226f574..bbccd5e094c 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.8-dev +version: 2.0.8 groups: shared library: true dependencies: diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md index d5040623557..331bb4c220e 100644 --- a/shared/threat-models/CHANGELOG.md +++ b/shared/threat-models/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/threat-models/change-notes/released/1.0.32.md b/shared/threat-models/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/threat-models/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/threat-models/codeql-pack.release.yml +++ b/shared/threat-models/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index 8f72fd8ad3f..10ca1546f9f 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.32-dev +version: 1.0.32 library: true groups: shared dataExtensions: diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index f4a80412ca8..6f6d29c2504 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/1.0.32.md b/shared/tutorial/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/tutorial/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index aabb0356b86..ce733dcd8b2 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/CHANGELOG.md b/shared/typeflow/CHANGELOG.md index bf429698022..592596c37d2 100644 --- a/shared/typeflow/CHANGELOG.md +++ b/shared/typeflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/typeflow/change-notes/released/1.0.32.md b/shared/typeflow/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/typeflow/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/typeflow/codeql-pack.release.yml b/shared/typeflow/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/typeflow/codeql-pack.release.yml +++ b/shared/typeflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index 98566858903..d665055f125 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true dependencies: diff --git a/shared/typeinference/CHANGELOG.md b/shared/typeinference/CHANGELOG.md index 83a42fb0551..29ece641a7e 100644 --- a/shared/typeinference/CHANGELOG.md +++ b/shared/typeinference/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.13 + +No user-facing changes. + ## 0.0.12 No user-facing changes. diff --git a/shared/typeinference/change-notes/released/0.0.13.md b/shared/typeinference/change-notes/released/0.0.13.md new file mode 100644 index 00000000000..f679eaf0313 --- /dev/null +++ b/shared/typeinference/change-notes/released/0.0.13.md @@ -0,0 +1,3 @@ +## 0.0.13 + +No user-facing changes. diff --git a/shared/typeinference/codeql-pack.release.yml b/shared/typeinference/codeql-pack.release.yml index 997fb8da83c..044e54e4f7e 100644 --- a/shared/typeinference/codeql-pack.release.yml +++ b/shared/typeinference/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.12 +lastReleaseVersion: 0.0.13 diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index 954a850cf0f..8a7bfdca975 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.13-dev +version: 0.0.13 groups: shared library: true dependencies: diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index 1372c8c89ea..6b132f75a55 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.16 + +No user-facing changes. + ## 2.0.15 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/2.0.16.md b/shared/typetracking/change-notes/released/2.0.16.md new file mode 100644 index 00000000000..221400d393f --- /dev/null +++ b/shared/typetracking/change-notes/released/2.0.16.md @@ -0,0 +1,3 @@ +## 2.0.16 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index 0377ae283a3..c10461a785c 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.15 +lastReleaseVersion: 2.0.16 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 2bf6f01d218..4e24584b50e 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.16-dev +version: 2.0.16 groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index c44b941f9e3..2661fcc9308 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/typos/change-notes/released/1.0.32.md b/shared/typos/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/typos/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index b01883668b7..b13ab265b25 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index d9169a8d5d8..3ded7f7af70 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.19 + +No user-facing changes. + ## 2.0.18 No user-facing changes. diff --git a/shared/util/change-notes/released/2.0.19.md b/shared/util/change-notes/released/2.0.19.md new file mode 100644 index 00000000000..b37b6798b12 --- /dev/null +++ b/shared/util/change-notes/released/2.0.19.md @@ -0,0 +1,3 @@ +## 2.0.19 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index 16342205c73..4aecf1e1f86 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.18 +lastReleaseVersion: 2.0.19 diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 1c1f5670d3e..2352753b472 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.19-dev +version: 2.0.19 groups: shared library: true dependencies: null diff --git a/shared/xml/CHANGELOG.md b/shared/xml/CHANGELOG.md index 59ae3e2581a..2c1d2132c7e 100644 --- a/shared/xml/CHANGELOG.md +++ b/shared/xml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/xml/change-notes/released/1.0.32.md b/shared/xml/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/xml/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/xml/codeql-pack.release.yml b/shared/xml/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/xml/codeql-pack.release.yml +++ b/shared/xml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index 0908201b182..680cc4751ef 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true dependencies: diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md index 2254f38fb9f..31243ec36be 100644 --- a/shared/yaml/CHANGELOG.md +++ b/shared/yaml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.32 + +No user-facing changes. + ## 1.0.31 No user-facing changes. diff --git a/shared/yaml/change-notes/released/1.0.32.md b/shared/yaml/change-notes/released/1.0.32.md new file mode 100644 index 00000000000..05c4073731c --- /dev/null +++ b/shared/yaml/change-notes/released/1.0.32.md @@ -0,0 +1,3 @@ +## 1.0.32 + +No user-facing changes. diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml index f5bdc98ffc8..7bc5c51ba7b 100644 --- a/shared/yaml/codeql-pack.release.yml +++ b/shared/yaml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.31 +lastReleaseVersion: 1.0.32 diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index cbbdd896341..1c625bfdf4a 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.32-dev +version: 1.0.32 groups: shared library: true warnOnImplicitThis: true diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md index 7138ed02a2b..eb3b3da9689 100644 --- a/swift/ql/lib/CHANGELOG.md +++ b/swift/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.0.8 + +No user-facing changes. + ## 5.0.7 ### Minor Analysis Improvements diff --git a/swift/ql/lib/change-notes/released/5.0.8.md b/swift/ql/lib/change-notes/released/5.0.8.md new file mode 100644 index 00000000000..9c73f4b1341 --- /dev/null +++ b/swift/ql/lib/change-notes/released/5.0.8.md @@ -0,0 +1,3 @@ +## 5.0.8 + +No user-facing changes. diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml index accf4086d8a..c608aca6969 100644 --- a/swift/ql/lib/codeql-pack.release.yml +++ b/swift/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 5.0.7 +lastReleaseVersion: 5.0.8 diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 88950de258f..a05b05e1eea 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 5.0.8-dev +version: 5.0.8 groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md index eac65864617..be2f79710a9 100644 --- a/swift/ql/src/CHANGELOG.md +++ b/swift/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.6 + +No user-facing changes. + ## 1.2.5 No user-facing changes. diff --git a/swift/ql/src/change-notes/released/1.2.6.md b/swift/ql/src/change-notes/released/1.2.6.md new file mode 100644 index 00000000000..0832850ff8c --- /dev/null +++ b/swift/ql/src/change-notes/released/1.2.6.md @@ -0,0 +1,3 @@ +## 1.2.6 + +No user-facing changes. diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml index 40355f0807f..24962f7ba24 100644 --- a/swift/ql/src/codeql-pack.release.yml +++ b/swift/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.2.5 +lastReleaseVersion: 1.2.6 diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index f49b81cec75..3dbc93c16d3 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.2.6-dev +version: 1.2.6 groups: - swift - queries From a76d736136b32570135d62649db39ba374627b1e Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Mon, 29 Sep 2025 15:32:52 +0100 Subject: [PATCH 89/90] C#: tweak changelog wording --- csharp/ql/src/CHANGELOG.md | 2 +- csharp/ql/src/change-notes/released/1.4.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index e432045f72e..7fa8992c49a 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -3,7 +3,7 @@ ### Minor Analysis Improvements * The modeling of null guards based on complex pattern expressions has been improved, which in turn improves the query `cs/dereferenced-value-may-be-null` by removing false positives. -* Remove the query `cs/xmldoc/missing-summary` from the `code-quality` suite (align with other languages). +* The query `cs/xmldoc/missing-summary` has been removed from the `code-quality` suite, to align with other languages. ## 1.4.0 diff --git a/csharp/ql/src/change-notes/released/1.4.1.md b/csharp/ql/src/change-notes/released/1.4.1.md index 48b31092714..f161787a108 100644 --- a/csharp/ql/src/change-notes/released/1.4.1.md +++ b/csharp/ql/src/change-notes/released/1.4.1.md @@ -3,4 +3,4 @@ ### Minor Analysis Improvements * The modeling of null guards based on complex pattern expressions has been improved, which in turn improves the query `cs/dereferenced-value-may-be-null` by removing false positives. -* Remove the query `cs/xmldoc/missing-summary` from the `code-quality` suite (align with other languages). +* The query `cs/xmldoc/missing-summary` has been removed from the `code-quality` suite, to align with other languages. From a7a4e43991d0c2290e593d0c7355dad77afa3256 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 15:10:19 +0000 Subject: [PATCH 90/90] Post-release preparation for codeql-cli-2.23.2 --- actions/ql/lib/qlpack.yml | 2 +- actions/ql/src/qlpack.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/consistency-queries/qlpack.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- rust/ql/lib/qlpack.yml | 2 +- rust/ql/src/qlpack.yml | 2 +- shared/concepts/qlpack.yml | 2 +- shared/controlflow/qlpack.yml | 2 +- shared/dataflow/qlpack.yml | 2 +- shared/mad/qlpack.yml | 2 +- shared/quantum/qlpack.yml | 2 +- shared/rangeanalysis/qlpack.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/threat-models/qlpack.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typeflow/qlpack.yml | 2 +- shared/typeinference/qlpack.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/xml/qlpack.yml | 2 +- shared/yaml/qlpack.yml | 2 +- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 41 files changed, 41 insertions(+), 41 deletions(-) diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index bfebfa99d04..80eecfca28d 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.18 +version: 0.4.19-dev library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index 9dba67fea76..2de1276aa82 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.10 +version: 0.6.11-dev library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 23bf4d8fc9e..435d013c47b 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 5.6.1 +version: 5.6.2-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 7322e2571d1..f5193698fdb 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.5.1 +version: 1.5.2-dev groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 02e6cddfc17..3c14c29940c 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.7.49 +version: 1.7.50-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 84e6c8ef7e0..efb3216f3b9 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.7.49 +version: 1.7.50-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index aba9ee98b5a..2f92b5edafd 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 5.2.5 +version: 5.2.6-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 7ecdec07f35..fad06a3e928 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.4.1 +version: 1.4.2-dev groups: - csharp - queries diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index 3b1e2d9586b..70529ff4f90 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.32 +version: 1.0.33-dev groups: - go - queries diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index bc9bf12c80c..20ace6482e4 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 4.3.5 +version: 4.3.6-dev groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 816d4b95867..c85a94a90f5 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.4.6 +version: 1.4.7-dev groups: - go - queries diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 7d0153cc566..dabb65e61ce 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 7.7.1 +version: 7.7.2-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index bbfafc65503..b1ee0395fb2 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.8.1 +version: 1.8.2-dev groups: - java - queries diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 74ccf251956..da942ea28a8 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.6.12 +version: 2.6.13-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index cafde25bbf9..2581f947629 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.1.1 +version: 2.1.2-dev groups: - javascript - queries diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 7d71d83613d..7715f68107e 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.32 +version: 1.0.33-dev groups: shared warnOnImplicitThis: true diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 5eba946c3cf..35ab576bf1a 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 4.0.16 +version: 4.0.17-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index b42e054bdad..08336cbb3eb 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.6.6 +version: 1.6.7-dev groups: - python - queries diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 6dd0db034c3..a503103b95d 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 5.1.0 +version: 5.1.1-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index ce46bf8c37a..a01acd1d674 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.4.6 +version: 1.4.7-dev groups: - ruby - queries diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 3c3ba893b14..61c2ed8e81e 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.1.17 +version: 0.1.18-dev groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index 09d251a5cb1..57d3e972fc6 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.17 +version: 0.1.18-dev groups: - rust - queries diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index 3924d67029d..452f932edef 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.6 +version: 0.0.7-dev groups: shared library: true dependencies: diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index a0158fea04f..660b1e12512 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.16 +version: 2.0.17-dev groups: shared library: true dependencies: diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index 3e46004181f..166ef444b22 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.0.16 +version: 2.0.17-dev groups: shared library: true dependencies: diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 1aaa401b750..d9767452c27 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true dependencies: diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index bf877f51d5f..7dfaa747962 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.10 +version: 0.0.11-dev groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index 5e9de8ad513..85341d10420 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true dependencies: diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index f69602228c9..72347bcd160 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true dependencies: diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index bbccd5e094c..3c1f3fe0278 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.8 +version: 2.0.9-dev groups: shared library: true dependencies: diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index 10ca1546f9f..e28c5f26dd8 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.32 +version: 1.0.33-dev library: true groups: shared dataExtensions: diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index ce733dcd8b2..33dc89bc60c 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index d665055f125..5d257b81fc6 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true dependencies: diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index 8a7bfdca975..5d8f8a6011f 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.13 +version: 0.0.14-dev groups: shared library: true dependencies: diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 4e24584b50e..6bc1e76cfb4 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.16 +version: 2.0.17-dev groups: shared library: true dependencies: diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index b13ab265b25..a045761cd92 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 2352753b472..33bf4527cf0 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.19 +version: 2.0.20-dev groups: shared library: true dependencies: null diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index 680cc4751ef..62fcccb2453 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true dependencies: diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index 1c625bfdf4a..6c49b5f27ba 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.32 +version: 1.0.33-dev groups: shared library: true warnOnImplicitThis: true diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index a05b05e1eea..4ad0623d0f3 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 5.0.8 +version: 5.0.9-dev groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index 3dbc93c16d3..ea5431f192e 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.2.6 +version: 1.2.7-dev groups: - swift - queries