Skip to content

Commit 804c06b

Browse files
author
Esben Sparre Andreasen
committed
JS: add models of logging frameworks
1 parent 87f9ecb commit 804c06b

File tree

5 files changed

+175
-0
lines changed

5 files changed

+175
-0
lines changed

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import semmle.javascript.frameworks.DigitalOcean
5858
import semmle.javascript.frameworks.Electron
5959
import semmle.javascript.frameworks.jQuery
6060
import semmle.javascript.frameworks.LodashUnderscore
61+
import semmle.javascript.frameworks.Logging
6162
import semmle.javascript.frameworks.HttpFrameworks
6263
import semmle.javascript.frameworks.NoSQL
6364
import semmle.javascript.frameworks.PkgCloud
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/**
2+
* Provides classes for working with logging libraries.
3+
*/
4+
5+
import javascript
6+
7+
/**
8+
* A call to a logging mechanism.
9+
*/
10+
abstract class LoggerCall extends DataFlow::CallNode {
11+
12+
/**
13+
* Gets a node that contributes to the logged message.
14+
*/
15+
abstract DataFlow::Node getAMessageComponent();
16+
17+
}
18+
19+
private string getAStandardLoggerMethodName() {
20+
// log level names used in RFC5424, `npm`, `console`
21+
result = "crit" or
22+
result = "debug" or
23+
result = "error" or
24+
result = "emerg" or
25+
result = "fatal" or
26+
result = "info" or
27+
result = "log" or
28+
result = "notice" or
29+
result = "silly" or
30+
result = "trace" or
31+
result = "warn"
32+
}
33+
34+
/**
35+
* Provides classes for working the builtin NodeJS/Browser `console`.
36+
*/
37+
private module Console {
38+
39+
/**
40+
* Gets a data flow source node for the console library.
41+
*/
42+
private DataFlow::SourceNode console() {
43+
result = DataFlow::moduleImport("console") or
44+
result = DataFlow::globalVarRef("console")
45+
}
46+
47+
/**
48+
* A call to the console logging mechanism.
49+
*/
50+
class ConsoleLoggerCall extends LoggerCall {
51+
string name;
52+
53+
ConsoleLoggerCall() {
54+
(
55+
name = getAStandardLoggerMethodName() or
56+
name = "assert"
57+
) and
58+
this = console().getAMethodCall(name)
59+
}
60+
61+
override DataFlow::Node getAMessageComponent() {
62+
if name = "assert" then
63+
result = getArgument([1..getNumArgument()])
64+
else
65+
result = getAnArgument()
66+
}
67+
68+
}
69+
70+
}
71+
72+
/**
73+
* Provides classes for working with [loglevel](https://github.com/pimterry/loglevel).
74+
*/
75+
private module Loglevel {
76+
77+
/**
78+
* A call to the loglevel logging mechanism.
79+
*/
80+
class LoglevelLoggerCall extends LoggerCall {
81+
LoglevelLoggerCall() {
82+
this = DataFlow::moduleMember("loglevel", getAStandardLoggerMethodName()).getACall()
83+
}
84+
85+
override DataFlow::Node getAMessageComponent() {
86+
result = getAnArgument()
87+
}
88+
89+
}
90+
91+
}
92+
93+
94+
/**
95+
* Provides classes for working with [winston](https://github.com/winstonjs/winston).
96+
*/
97+
private module Winston {
98+
99+
/**
100+
* A call to the winston logging mechanism.
101+
*/
102+
class WinstonLoggerCall extends LoggerCall, DataFlow::MethodCallNode {
103+
WinstonLoggerCall() {
104+
this = DataFlow::moduleMember("winston", "createLogger").getACall().getAMethodCall(getAStandardLoggerMethodName())
105+
}
106+
107+
override DataFlow::Node getAMessageComponent() {
108+
if getMethodName() = "log" then
109+
result = getOptionArgument(0, "message")
110+
else
111+
result = getAnArgument()
112+
}
113+
114+
}
115+
116+
}
117+
118+
/**
119+
* Provides classes for working with [log4js](https://github.com/log4js-node/log4js-node).
120+
*/
121+
private module log4js {
122+
123+
/**
124+
* A call to the log4js logging mechanism.
125+
*/
126+
class Log4jsLoggerCall extends LoggerCall {
127+
Log4jsLoggerCall() {
128+
this = DataFlow::moduleMember("log4js", "getLogger").getACall().getAMethodCall(getAStandardLoggerMethodName())
129+
}
130+
131+
override DataFlow::Node getAMessageComponent() {
132+
result = getAnArgument()
133+
}
134+
135+
}
136+
137+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
| tst.js:3:1:3:26 | console ... ", arg) | tst.js:3:13:3:20 | "msg %s" |
2+
| tst.js:3:1:3:26 | console ... ", arg) | tst.js:3:23:3:25 | arg |
3+
| tst.js:4:1:4:28 | console ... ", arg) | tst.js:4:15:4:22 | "msg %s" |
4+
| tst.js:4:1:4:28 | console ... ", arg) | tst.js:4:25:4:27 | arg |
5+
| tst.js:5:1:5:28 | console ... ", arg) | tst.js:5:15:5:22 | "msg %s" |
6+
| tst.js:5:1:5:28 | console ... ", arg) | tst.js:5:25:5:27 | arg |
7+
| tst.js:7:1:7:34 | require ... ", arg) | tst.js:7:21:7:28 | "msg %s" |
8+
| tst.js:7:1:7:34 | require ... ", arg) | tst.js:7:31:7:33 | arg |
9+
| tst.js:9:1:9:38 | require ... ", arg) | tst.js:9:25:9:32 | "msg %s" |
10+
| tst.js:9:1:9:38 | require ... ", arg) | tst.js:9:35:9:37 | arg |
11+
| tst.js:11:1:11:73 | require ... other) | tst.js:11:50:11:63 | "msg with arg" |
12+
| tst.js:12:1:12:53 | require ... ", arg) | tst.js:12:40:12:47 | "msg %s" |
13+
| tst.js:12:1:12:53 | require ... ", arg) | tst.js:12:50:12:52 | arg |
14+
| tst.js:14:1:14:48 | require ... ", arg) | tst.js:14:35:14:42 | "msg %s" |
15+
| tst.js:14:1:14:48 | require ... ", arg) | tst.js:14:45:14:47 | arg |
16+
| tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:22:16:29 | "msg %s" |
17+
| tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:32:16:34 | arg |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from LoggerCall log
4+
select log, log.getAMessageComponent()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
var requiredConsole = require("console");
2+
3+
console.log("msg %s", arg);
4+
console.fatal("msg %s", arg);
5+
console.debug("msg %s", arg);
6+
7+
requiredConsole.log("msg %s", arg);
8+
9+
require("loglevel").log("msg %s", arg);
10+
11+
require("winston").createLogger().log({ message: "msg with arg" }, other);
12+
require("winston").createLogger().info("msg %s", arg);
13+
14+
require("log4js").getLogger().log("msg %s", arg);
15+
16+
console.assert(true, "msg %s", arg);

0 commit comments

Comments
 (0)