Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 6fea8ab

Browse files
committed
Oauth2 state query: improve code style
No behavioural changes intended.
1 parent 2f175e3 commit 6fea8ab

File tree

3 files changed

+32
-49
lines changed

3 files changed

+32
-49
lines changed

ql/src/Security/CWE-352/ConstantOauth2State.ql

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ class ConstantStateFlowConf extends DataFlow::Configuration {
3939
override predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
4040
}
4141

42+
/**
43+
* Holds if `pred` writes a URL to the `RedirectURL` field of the `succ` `Config` object.
44+
*
45+
* This propagates flow from the RedirectURL field to the whole Config object.
46+
*/
47+
predicate isUrlTaintingConfigStep(DataFlow::Node pred, DataFlow::Node succ) {
48+
exists(Write w, Field f | f.hasQualifiedName("golang.org/x/oauth2", "Config", "RedirectURL") |
49+
w.writesField(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), f, pred)
50+
)
51+
}
52+
4253
/**
4354
* A flow of a URL indicating the OAuth redirect doesn't point to a publicly
4455
* accessible address, to the receiver of an `AuthCodeURL` call.
@@ -53,23 +64,12 @@ class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
5364
// The following are all common ways to indicate out-of-band OAuth2 flow, in which case
5465
// the authenticating party does not redirect but presents a code for the user to copy
5566
// instead.
56-
source.asExpr().(StringLit).getValue() in ["urn:ietf:wg:oauth:2.0:oob",
57-
"urn:ietf:wg:oauth:2.0:oob:auto", "oob", "code"] or
67+
source.getStringValue() in ["urn:ietf:wg:oauth:2.0:oob", "urn:ietf:wg:oauth:2.0:oob:auto",
68+
"oob", "code"] or
5869
// Alternatively some non-web tools will create a temporary local webserver to handle the
5970
// OAuth2 redirect:
60-
source.asExpr().(StringLit).getValue().matches("%://localhost%") or
61-
source.asExpr().(StringLit).getValue().matches("%://127.0.0.1%")
62-
}
63-
64-
/**
65-
* Holds if `pred` writes a URL to the `RedirectURL` field of the `succ` `Config` object.
66-
*
67-
* This propagates flow from the RedirectURL field to the whole Config object.
68-
*/
69-
predicate isUrlTaintingConfigStep(DataFlow::Node pred, DataFlow::Node succ) {
70-
exists(Write w, Field f | f.hasQualifiedName("golang.org/x/oauth2", "Config", "RedirectURL") |
71-
w.writesField(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), f, pred)
72-
)
71+
source.getStringValue().matches("%://localhost%") or
72+
source.getStringValue().matches("%://127.0.0.1%")
7373
}
7474

7575
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
@@ -80,11 +80,7 @@ class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
8080
TaintTracking::referenceStep(pred, succ)
8181
or
8282
// Propagate across Sprintf and similar calls
83-
exists(DataFlow::CallNode c |
84-
c = any(Fmt::Sprinter s).getACall() and
85-
pred = c.getAnArgument() and
86-
succ = c.getResult()
87-
)
83+
TaintTracking::functionModelStep(any(Fmt::Sprinter s), pred, succ)
8884
}
8985

9086
predicate isSink(DataFlow::Node sink, DataFlow::CallNode call) {
@@ -113,8 +109,6 @@ class FlowToPrint extends DataFlow::Configuration {
113109
FlowToPrint() { this = "FlowToPrint" }
114110

115111
predicate isSink(DataFlow::Node sink, DataFlow::CallNode call) {
116-
exists(Fmt::Printer printer | call = printer.getACall() | sink = call.getArgument(_))
117-
or
118112
exists(LoggerCall logCall | call = logCall | sink = logCall.getAMessageComponent())
119113
}
120114

@@ -135,26 +129,32 @@ predicate resultFlowsToPrinter(DataFlow::CallNode authCodeURLCall) {
135129

136130
/** Get a data-flow node that reads the value of `os.Stdin`. */
137131
DataFlow::Node getAStdinNode() {
138-
result = any(ValueEntity v | v.hasQualifiedName("os", "Stdin")).getARead()
132+
exists(ValueEntity v |
133+
v.hasQualifiedName("os", "Stdin") and result = globalValueNumber(v.getARead()).getANode()
134+
)
139135
}
140136

141137
/**
142138
* Gets a call to a scanner function that reads from `os.Stdin`, or which creates a scanner
143139
* instance wrapping `os.Stdin`.
144140
*/
145141
DataFlow::CallNode getAScannerCall() {
146-
result instanceof Fmt::ScannerCall or
147-
result.(Fmt::FScannerCall).getReader() = getAStdinNode() or
148-
result.(Bufio::NewScannerCall).getReader() = getAStdinNode()
142+
result = any(Fmt::Scanner f).getACall()
143+
or
144+
exists(Fmt::FScanner f |
145+
result = f.getACall() and f.getReader().getNode(result) = getAStdinNode()
146+
)
147+
or
148+
exists(Bufio::NewScanner f |
149+
result = f.getACall() and f.getReader().getNode(result) = getAStdinNode()
150+
)
149151
}
150152

151153
/**
152154
* Holds if the provided `CallNode` is within the same root as a call
153155
* to a scanner that reads from `os.Stdin`.
154156
*/
155-
predicate containsCallToStdinScanner(FuncDef funcDef) {
156-
exists(DataFlow::CallNode call | call = getAScannerCall() | call.getRoot() = funcDef)
157-
}
157+
predicate containsCallToStdinScanner(FuncDef funcDef) { getAScannerCall().getRoot() = funcDef }
158158

159159
/**
160160
* Holds if the `authCodeURLCall` seems to be done within a terminal

ql/src/semmle/go/frameworks/Stdlib.qll

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,28 +107,18 @@ module Fmt {
107107
Scanner() { this.hasQualifiedName("fmt", ["Scan", "Scanf", "Scanln"]) }
108108
}
109109

110-
/** A call to a `Scanner`. */
111-
class ScannerCall extends DataFlow::CallNode {
112-
ScannerCall() { this.getTarget() instanceof Scanner }
113-
}
114-
115110
/**
116111
* The `Fscan` function or one of its variants,
117112
* all of which read from a specified io.Reader
118113
*/
119114
class FScanner extends Function {
120115
FScanner() { this.hasQualifiedName("fmt", ["Fscan", "Fscanf", "Fscanln"]) }
121-
}
122-
123-
/** A call to a `FScanner`. */
124-
class FScannerCall extends DataFlow::CallNode {
125-
FScannerCall() { this.getTarget() instanceof FScanner }
126116

127117
/**
128118
* Returns the node corresponding to the io.Reader
129119
* argument provided in the call.
130120
*/
131-
DataFlow::Node getReader() { result = this.getArgument(0) }
121+
FunctionInput getReader() { result.isParameter(0) }
132122
}
133123
}
134124

ql/src/semmle/go/frameworks/stdlib/Bufio.qll

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,12 @@ module Bufio {
1111
*/
1212
class NewScanner extends Function {
1313
NewScanner() { this.hasQualifiedName("bufio", "NewScanner") }
14-
}
15-
16-
/**
17-
* A call to `bufio.NewScanner`.
18-
*/
19-
class NewScannerCall extends DataFlow::CallNode {
20-
NewScannerCall() { this.getTarget() instanceof NewScanner }
2114

2215
/**
23-
* Returns the node corresponding to the `io.Reader`
16+
* Gets the input corresponding to the `io.Reader`
2417
* argument provided in the call.
2518
*/
26-
DataFlow::Node getReader() { result = this.getArgument(0) }
19+
FunctionInput getReader() { result.isParameter(0) }
2720
}
2821

2922
private class FunctionModels extends TaintTracking::FunctionModel {

0 commit comments

Comments
 (0)