JS: add additional SystemCommandExecutors

This commit is contained in:
Esben Sparre Andreasen 2019-06-05 14:10:07 +02:00
Родитель 58285c08dd
Коммит 299d4c6e93
5 изменённых файлов: 135 добавлений и 20 удалений

Просмотреть файл

@ -0,0 +1,26 @@
# Improvements to JavaScript analysis
## General improvements
* Support for the following frameworks and libraries has been improved:
- [cross-spawn](https://www.npmjs.com/package/cross-spawn)
- [cross-spawn-async](https://www.npmjs.com/package/cross-spawn-async)
- [exec](https://www.npmjs.com/package/exec)
- [execa](https://www.npmjs.com/package/execa)
- [exec-async](https://www.npmjs.com/package/exec-async)
- [remote-exec](https://www.npmjs.com/package/remote-exec)
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------|----------|-------------|
| | | |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
## Changes to QL libraries

Просмотреть файл

@ -84,6 +84,7 @@ import semmle.javascript.frameworks.React
import semmle.javascript.frameworks.ReactNative
import semmle.javascript.frameworks.Request
import semmle.javascript.frameworks.ShellJS
import semmle.javascript.frameworks.SystemCommandExecutors
import semmle.javascript.frameworks.SQL
import semmle.javascript.frameworks.SocketIO
import semmle.javascript.frameworks.StringFormatters

Просмотреть файл

@ -0,0 +1,49 @@
/**
* Provides concrete classes for data-flow nodes that execute an
* operating system command, for instance by spawning a new process.
*/
import javascript
private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::InvokeNode {
int cmdArg;
SystemCommandExecutors() {
exists(string mod, DataFlow::SourceNode callee |
exists(string method |
mod = "cross-spawn" and method = "sync" and cmdArg = 0
or
mod = "execa" and
(
method = "shell" or
method = "shellSync" or
method = "stdout" or
method = "stderr" or
method = "sync"
) and
cmdArg = 0
|
callee = DataFlow::moduleMember(mod, method)
)
or
(
mod = "cross-spawn" and cmdArg = 0
or
mod = "cross-spawn-async" and cmdArg = 0
or
mod = "exec" and cmdArg = 0
or
mod = "exec-async" and cmdArg = 0
or
mod = "execa" and cmdArg = 0
or
mod = "remote-exec" and cmdArg = 1
) and
callee = DataFlow::moduleImport(mod)
|
this = callee.getACall()
)
}
override DataFlow::Node getACommandArgument() { result = getArgument(cmdArg) }
}

Просмотреть файл

@ -50,6 +50,23 @@ nodes
| execSeries.js:18:34:18:40 | req.url |
| execSeries.js:19:12:19:16 | [cmd] |
| execSeries.js:19:13:19:15 | cmd |
| other.js:5:9:5:49 | cmd |
| other.js:5:15:5:38 | url.par ... , true) |
| other.js:5:15:5:44 | url.par ... ).query |
| other.js:5:15:5:49 | url.par ... ry.path |
| other.js:5:25:5:31 | req.url |
| other.js:7:33:7:35 | cmd |
| other.js:8:28:8:30 | cmd |
| other.js:9:32:9:34 | cmd |
| other.js:10:29:10:31 | cmd |
| other.js:11:29:11:31 | cmd |
| other.js:12:27:12:29 | cmd |
| other.js:14:28:14:30 | cmd |
| other.js:15:34:15:36 | cmd |
| other.js:16:21:16:23 | cmd |
| other.js:17:27:17:29 | cmd |
| other.js:18:22:18:24 | cmd |
| other.js:19:36:19:38 | cmd |
edges
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:17:13:17:15 | cmd |
| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:18:17:18:19 | cmd |
@ -101,6 +118,22 @@ edges
| execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) |
| execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands |
| execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] |
| other.js:5:9:5:49 | cmd | other.js:7:33:7:35 | cmd |
| other.js:5:9:5:49 | cmd | other.js:8:28:8:30 | cmd |
| other.js:5:9:5:49 | cmd | other.js:9:32:9:34 | cmd |
| other.js:5:9:5:49 | cmd | other.js:10:29:10:31 | cmd |
| other.js:5:9:5:49 | cmd | other.js:11:29:11:31 | cmd |
| other.js:5:9:5:49 | cmd | other.js:12:27:12:29 | cmd |
| other.js:5:9:5:49 | cmd | other.js:14:28:14:30 | cmd |
| other.js:5:9:5:49 | cmd | other.js:15:34:15:36 | cmd |
| other.js:5:9:5:49 | cmd | other.js:16:21:16:23 | cmd |
| other.js:5:9:5:49 | cmd | other.js:17:27:17:29 | cmd |
| other.js:5:9:5:49 | cmd | other.js:18:22:18:24 | cmd |
| other.js:5:9:5:49 | cmd | other.js:19:36:19:38 | cmd |
| other.js:5:15:5:38 | url.par ... , true) | other.js:5:15:5:44 | url.par ... ).query |
| other.js:5:15:5:44 | url.par ... ).query | other.js:5:15:5:49 | url.par ... ry.path |
| other.js:5:15:5:49 | url.par ... ry.path | other.js:5:9:5:49 | cmd |
| other.js:5:25:5:31 | req.url | other.js:5:15:5:38 | url.par ... , true) |
#select
| child_process-test.js:17:13:17:15 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:17:13:17:15 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:18:17:18:19 | cmd | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:18:17:18:19 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
@ -115,3 +148,15 @@ edges
| child_process-test.js:51:5:51:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| child_process-test.js:56:3:56:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
| execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value |
| other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:9:32:9:34 | cmd | other.js:5:25:5:31 | req.url | other.js:9:32:9:34 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:10:29:10:31 | cmd | other.js:5:25:5:31 | req.url | other.js:10:29:10:31 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:11:29:11:31 | cmd | other.js:5:25:5:31 | req.url | other.js:11:29:11:31 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:12:27:12:29 | cmd | other.js:5:25:5:31 | req.url | other.js:12:27:12:29 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:14:28:14:30 | cmd | other.js:5:25:5:31 | req.url | other.js:14:28:14:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:15:34:15:36 | cmd | other.js:5:25:5:31 | req.url | other.js:15:34:15:36 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:16:21:16:23 | cmd | other.js:5:25:5:31 | req.url | other.js:16:21:16:23 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:17:27:17:29 | cmd | other.js:5:25:5:31 | req.url | other.js:17:27:17:29 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:18:22:18:24 | cmd | other.js:5:25:5:31 | req.url | other.js:18:22:18:24 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
| other.js:19:36:19:38 | cmd | other.js:5:25:5:31 | req.url | other.js:19:36:19:38 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |

Просмотреть файл

@ -1,26 +1,20 @@
var http =require('http'),
url = require('url');
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
let cmd = url.parse(req.url, true).query.path;
var exec = require('exec');
require("cross-spawn").sync(cmd); // NOT OK
require("execa").shell(cmd); // NOT OK
require("execa").shellSync(cmd); // NOT OK
require("execa").stdout(cmd); // NOT OK
require("execa").stderr(cmd); // NOT OK
require("execa").sync(cmd); // NOT OK
exec('foo'); // OK
require('exec')('foo'); // OK
require('exec-async').someFunction('foo'); // OK
require('spawn-async').someFunction('foo'); // OK
require('shelljs').someFunction('foo'); // OK
require('remote-exec').someFunction('foo'); // OK
require('cross-spawn').someFunction('foo'); // OK
// NB :: we do not identify the following as sinks yet!
exec(cmd); // OK (for now)
require('exec')(cmd); // OK (for now)
require('exec-async').someFunction(cmd); // OK (for now)
require('spawn-async').someFunction(cmd); // OK (for now)
require('shelljs').someFunction(cmd); // OK (for now)
require('remote-exec').someFunction(cmd); // OK (for now)
require('cross-spawn').someFunction(cmd); // OK (for now)
require("cross-spawn")(cmd); // NOT OK
require("cross-spawn-async")(cmd); // NOT OK
require("exec")(cmd); // NOT OK
require("exec-async")(cmd); // NOT OK
require("execa")(cmd); // NOT OK
require("remote-exec")(target, cmd); // NOT OK
});