diff --git a/README.org b/README.org index 6dc480b..0803dd4 100644 --- a/README.org +++ b/README.org @@ -60,7 +60,6 @@ #+END_SRC - 5. (recommended for browsing) Install the codeql standard library matching the binary version. This is not needed to write or run queries anymore, but the library has many examples and searching it is much easier after extracting diff --git a/session/session.ql b/session/session.ql index fdde5cd..176edee 100644 --- a/session/session.ql +++ b/session/session.ql @@ -11,6 +11,11 @@ predicate uSource(MethodCallExpr sbts) { // Ultimate sink // ---------------- // db.exec(query); +predicate uSink(MethodCallExpr dbe) { + // sbts.getReceiver().(DotExpr).getPropertyNameExpr().(Identifier).getName() = "toString" + dbe.getMethodName().matches("%exec%") +} + // Intermediate flow sink // ------------------------ diff --git a/solutions/UltimateSink.ql b/solutions/UltimateSink.ql new file mode 100644 index 0000000..176edee --- /dev/null +++ b/solutions/UltimateSink.ql @@ -0,0 +1,43 @@ +import javascript + +// Ultimate source +// ---------------- +// var line = stdinBuffer.toString(); +predicate uSource(MethodCallExpr sbts) { + // sbts.getReceiver().(DotExpr).getPropertyNameExpr().(Identifier).getName() = "toString" + sbts.getMethodName().matches("%toString%") +} + +// Ultimate sink +// ---------------- +// db.exec(query); +predicate uSink(MethodCallExpr dbe) { + // sbts.getReceiver().(DotExpr).getPropertyNameExpr().(Identifier).getName() = "toString" + dbe.getMethodName().matches("%exec%") +} + + +// Intermediate flow sink +// ------------------------ +// Connect +// const db = new sqlite3.Database( +// to its use +// db.exec(query); +// +// class IntermediateSink extends DataFlow::Configuration { +// IntermediateSink() { this = "IntermediateSink" } + +// override predicate isSource(DataFlow::Node nd) { +// exists(JsonParserCall jpc | nd = jpc.getOutput()) +// } + +// override predicate isSink(DataFlow::Node nd) { exists(DataFlow::PropRef pr | nd = pr.getBase()) } +// } + +// from IntermediateSink cfg, DataFlow::Node source, DataFlow::Node sink +// where cfg.hasFlow(source, sink) +// select sink, "Property access on JSON value originating $@.", source, "here" + +from MethodCallExpr sbts +where uSource(sbts) +select sbts \ No newline at end of file diff --git a/tests/UltimateSink/UltimateSink.expected b/tests/UltimateSink/UltimateSink.expected new file mode 100644 index 0000000..0915bb4 --- /dev/null +++ b/tests/UltimateSink/UltimateSink.expected @@ -0,0 +1,2 @@ +WARNING: Unused predicate uSink (/Users/hohn/local/codeql-javascript-multiflow/solutions/UltimateSink.ql:14,11-16) +| add-user.js:4:16:4:37 | stdinBu ... tring() | diff --git a/tests/UltimateSink/UltimateSink.qlref b/tests/UltimateSink/UltimateSink.qlref new file mode 100644 index 0000000..6b030de --- /dev/null +++ b/tests/UltimateSink/UltimateSink.qlref @@ -0,0 +1 @@ +UltimateSink.ql diff --git a/tests/UltimateSink/add-user.js b/tests/UltimateSink/add-user.js new file mode 100644 index 0000000..a4c8b1c --- /dev/null +++ b/tests/UltimateSink/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()