From 18b8c9e98cf49babe0b474dbed3ff76a36cb8c5c Mon Sep 17 00:00:00 2001 From: Michael Hohn Date: Sun, 26 Nov 2023 14:06:44 -0800 Subject: [PATCH] Add flow config from 'new db()' to 'db.exec()' --- cruft/snapshot-query | 3 +- session/session.ql | 57 +++++++++-------- solutions/IdentifyFlowSink.ql | 52 ++++++++++++++++ .../IdentifyFlowSink.expected | 61 +++++++++++++++++++ tests/IdentifyFlowSink/IdentifyFlowSink.qlref | 1 + tests/IdentifyFlowSink/add-user.js | 47 ++++++++++++++ 6 files changed, 196 insertions(+), 25 deletions(-) create mode 100644 solutions/IdentifyFlowSink.ql create mode 100644 tests/IdentifyFlowSink/IdentifyFlowSink.expected create mode 100644 tests/IdentifyFlowSink/IdentifyFlowSink.qlref create mode 100644 tests/IdentifyFlowSink/add-user.js diff --git a/cruft/snapshot-query b/cruft/snapshot-query index 89c5222..eb5e94b 100755 --- a/cruft/snapshot-query +++ b/cruft/snapshot-query @@ -27,6 +27,7 @@ git add tests/$qname/$qname.qlref # snapshot the session cp add-user.js tests/$qname/ +git add tests/$qname/add-user.js + cp session/session.ql solutions/$qname.ql git add solutions/$qname.ql - diff --git a/session/session.ql b/session/session.ql index 176edee..e9ad544 100644 --- a/session/session.ql +++ b/session/session.ql @@ -1,43 +1,52 @@ +/** + * @kind path-problem + */ + import javascript +import DataFlow::PathGraph // Ultimate source // ---------------- // var line = stdinBuffer.toString(); -predicate uSource(MethodCallExpr sbts) { - // sbts.getReceiver().(DotExpr).getPropertyNameExpr().(Identifier).getName() = "toString" - sbts.getMethodName().matches("%toString%") -} +predicate uSource(MethodCallExpr sbts) { sbts.getMethodName().matches("%toString%") } // Ultimate sink // ---------------- // db.exec(query); -predicate uSink(MethodCallExpr dbe) { - // sbts.getReceiver().(DotExpr).getPropertyNameExpr().(Identifier).getName() = "toString" - dbe.getMethodName().matches("%exec%") -} +predicate uSink(MethodCallExpr dbe) { dbe.getMethodName().matches("%exec%") } - -// Intermediate flow sink +// Flow sink origin // ------------------------ // Connect // const db = new sqlite3.Database( // to its use // db.exec(query); -// -// class IntermediateSink extends DataFlow::Configuration { -// IntermediateSink() { this = "IntermediateSink" } +// +class FlowSinkOrigin extends DataFlow::FlowLabel { + FlowSinkOrigin() { this = "FlowSinkOrigin" } +} -// override predicate isSource(DataFlow::Node nd) { -// exists(JsonParserCall jpc | nd = jpc.getOutput()) -// } +class IdentifyFlowSink extends DataFlow::Configuration { + IdentifyFlowSink() { this = "IdentifyFlowSink" } -// override predicate isSink(DataFlow::Node nd) { exists(DataFlow::PropRef pr | nd = pr.getBase()) } -// } + override predicate isSource(DataFlow::Node nd, DataFlow::FlowLabel lbl) { + // const db = new sqlite3.Database( + exists(NewExpr newdb | + newdb.getCalleeName() = "Database" and + nd.asExpr() = newdb + ) + } -// from IntermediateSink cfg, DataFlow::Node source, DataFlow::Node sink -// where cfg.hasFlow(source, sink) -// select sink, "Property access on JSON value originating $@.", source, "here" + override predicate isSink(DataFlow::Node nd, DataFlow::FlowLabel lbl) { + // db.exec(query); + exists(Expr db, MethodCallExpr exec | + exec.getMethodName() = "exec" and + db = exec.getReceiver() and + nd.asExpr() = db + ) + } +} -from MethodCallExpr sbts -where uSource(sbts) -select sbts \ No newline at end of file +from IdentifyFlowSink cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink, source, sink, "Database originating $@", source, "here" diff --git a/solutions/IdentifyFlowSink.ql b/solutions/IdentifyFlowSink.ql new file mode 100644 index 0000000..e9ad544 --- /dev/null +++ b/solutions/IdentifyFlowSink.ql @@ -0,0 +1,52 @@ +/** + * @kind path-problem + */ + +import javascript +import DataFlow::PathGraph + +// Ultimate source +// ---------------- +// var line = stdinBuffer.toString(); +predicate uSource(MethodCallExpr sbts) { sbts.getMethodName().matches("%toString%") } + +// Ultimate sink +// ---------------- +// db.exec(query); +predicate uSink(MethodCallExpr dbe) { dbe.getMethodName().matches("%exec%") } + +// Flow sink origin +// ------------------------ +// Connect +// const db = new sqlite3.Database( +// to its use +// db.exec(query); +// +class FlowSinkOrigin extends DataFlow::FlowLabel { + FlowSinkOrigin() { this = "FlowSinkOrigin" } +} + +class IdentifyFlowSink extends DataFlow::Configuration { + IdentifyFlowSink() { this = "IdentifyFlowSink" } + + override predicate isSource(DataFlow::Node nd, DataFlow::FlowLabel lbl) { + // const db = new sqlite3.Database( + exists(NewExpr newdb | + newdb.getCalleeName() = "Database" and + nd.asExpr() = newdb + ) + } + + override predicate isSink(DataFlow::Node nd, DataFlow::FlowLabel lbl) { + // db.exec(query); + exists(Expr db, MethodCallExpr exec | + exec.getMethodName() = "exec" and + db = exec.getReceiver() and + nd.asExpr() = db + ) + } +} + +from IdentifyFlowSink cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink, source, sink, "Database originating $@", source, "here" diff --git a/tests/IdentifyFlowSink/IdentifyFlowSink.expected b/tests/IdentifyFlowSink/IdentifyFlowSink.expected new file mode 100644 index 0000000..8b09988 --- /dev/null +++ b/tests/IdentifyFlowSink/IdentifyFlowSink.expected @@ -0,0 +1,61 @@ +WARNING: Unused predicate uSink (/Users/hohn/local/codeql-javascript-multiflow/solutions/IdentifyFlowSink.ql:16,11-16) +WARNING: Unused predicate uSource (/Users/hohn/local/codeql-javascript-multiflow/solutions/IdentifyFlowSink.ql:11,11-18) +WARNING: Unused variable lbl (/Users/hohn/local/codeql-javascript-multiflow/solutions/IdentifyFlowSink.ql:32,70-73) +WARNING: Unused variable lbl (/Users/hohn/local/codeql-javascript-multiflow/solutions/IdentifyFlowSink.ql:40,68-71) +nodes +| add-user.js:16:11:26:10 | db | +| add-user.js:16:11:26:10 | db | +| add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | +| add-user.js:16:16:26:10 | new sql ... }) | +| add-user.js:16:16:26:10 | new sql ... }) | +| add-user.js:16:16:26:10 | new sql ... }) | +| add-user.js:28:12:28:13 | db | +| add-user.js:28:12:28:13 | db | +| add-user.js:28:12:28:13 | db | +| add-user.js:31:21:31:22 | db | +| add-user.js:31:21:31:22 | db | +| add-user.js:31:21:31:22 | db | +| add-user.js:35:5:35:6 | db | +| add-user.js:35:5:35:6 | db | +| add-user.js:35:5:35:6 | db | +| add-user.js:35:5:35:6 | db | +| add-user.js:43:9:43:25 | db | +| add-user.js:43:9:43:25 | db | +| add-user.js:43:9:43:25 | db | +| add-user.js:43:14:43:25 | connect_db() | +| add-user.js:43:14:43:25 | connect_db() | +| add-user.js:43:14:43:25 | connect_db() | +| add-user.js:44:16:44:17 | db | +| add-user.js:44:16:44:17 | db | +| add-user.js:44:16:44:17 | db | +edges +| add-user.js:16:11:26:10 | db | add-user.js:28:12:28:13 | db | +| add-user.js:16:11:26:10 | db | add-user.js:28:12:28:13 | db | +| add-user.js:16:11:26:10 | db | add-user.js:28:12:28:13 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:16:16:26:10 | new sql ... }) | add-user.js:16:11:26:10 | db | +| add-user.js:28:12:28:13 | db | add-user.js:43:14:43:25 | connect_db() | +| add-user.js:28:12:28:13 | db | add-user.js:43:14:43:25 | connect_db() | +| add-user.js:28:12:28:13 | db | add-user.js:43:14:43:25 | connect_db() | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:31:21:31:22 | db | add-user.js:35:5:35:6 | db | +| add-user.js:43:9:43:25 | db | add-user.js:44:16:44:17 | db | +| add-user.js:43:9:43:25 | db | add-user.js:44:16:44:17 | db | +| add-user.js:43:9:43:25 | db | add-user.js:44:16:44:17 | db | +| add-user.js:43:14:43:25 | connect_db() | add-user.js:43:9:43:25 | db | +| add-user.js:43:14:43:25 | connect_db() | add-user.js:43:9:43:25 | db | +| add-user.js:43:14:43:25 | connect_db() | add-user.js:43:9:43:25 | db | +| add-user.js:44:16:44:17 | db | add-user.js:31:21:31:22 | db | +| add-user.js:44:16:44:17 | db | add-user.js:31:21:31:22 | db | +| add-user.js:44:16:44:17 | db | add-user.js:31:21:31:22 | db | +#select +| add-user.js:35:5:35:6 | db | add-user.js:16:16:26:10 | new sql ... }) | add-user.js:35:5:35:6 | db | Database originating $@ | add-user.js:16:16:26:10 | new sql ... }) | here | diff --git a/tests/IdentifyFlowSink/IdentifyFlowSink.qlref b/tests/IdentifyFlowSink/IdentifyFlowSink.qlref new file mode 100644 index 0000000..2d2be1d --- /dev/null +++ b/tests/IdentifyFlowSink/IdentifyFlowSink.qlref @@ -0,0 +1 @@ +IdentifyFlowSink.ql diff --git a/tests/IdentifyFlowSink/add-user.js b/tests/IdentifyFlowSink/add-user.js new file mode 100644 index 0000000..a4c8b1c --- /dev/null +++ b/tests/IdentifyFlowSink/add-user.js @@ -0,0 +1,47 @@ +function get_user_info() { + var fs = require("fs"); + var stdinBuffer = fs.readFileSync(process.stdin.fd); + var line = stdinBuffer.toString(); + console.log(line); + line = line.replace(/(\r\n|\n|\r)/gm, ""); + return line +} + +function get_new_id() { + return Math.floor(Math.random() * 12345); +} + +function connect_db() { + const sqlite3 = require('sqlite3').verbose(); + const db = new sqlite3.Database( + 'users.sqlite', + sqlite3.OPEN_READWRITE | sqlite3.OPEN_FULLMUTEX, + err => { + if (err){ + console.log(err); + throw err; + } else { + console.log('DB opened'); + } + }); + + return db; +} + +function write_info(db, id, info) { + db.serialize(); + const query = `INSERT INTO users VALUES (${id}, "${info}")`; + console.log(query); + db.exec(query); + db.close(); +} + +let add_user = () => { + console.log("Running add-user"); + var info = get_user_info(); + var id = get_new_id(); + var db = connect_db(); + write_info(db, id, info); +} + +add_user()