Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e183897

Browse files
committed
Implement stdin models
Unfortunately due to how variable and varargs work, these are better done in QL
1 parent 5fb61b0 commit e183897

9 files changed

Lines changed: 120 additions & 0 deletions

File tree

go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ module Fmt {
112112
Scanner() { this.hasQualifiedName("fmt", ["Scan", "Scanf", "Scanln"]) }
113113
}
114114

115+
private class ScannerSource extends SourceNode {
116+
ScannerSource() {
117+
// All of the arguments which are sources are varargs.
118+
this.asExpr() = any(Scanner s).getACall().getAnImplicitVarargsArgument().asExpr()
119+
}
120+
121+
override string getThreatModel() { result = "stdin" }
122+
}
123+
115124
/**
116125
* The `Fscan` function or one of its variants,
117126
* all of which read from a specified `io.Reader`.

go/ql/lib/semmle/go/frameworks/stdlib/Os.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,14 @@ module Os {
4343
input = inp and output = outp
4444
}
4545
}
46+
47+
private class Stdin extends SourceNode {
48+
Stdin() {
49+
exists(Variable osStdin | osStdin.hasQualifiedName("os", "Stdin") |
50+
this.asExpr() = osStdin.getARead().asExpr()
51+
)
52+
}
53+
54+
override string getThreatModel() { result = "stdin" }
55+
}
4656
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module test
2+
3+
go 1.22.6
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extensions:
2+
3+
- addsTo:
4+
pack: codeql/threat-models
5+
extensible: threatModelConfiguration
6+
data:
7+
- ["stdin", true, 0]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import go
2+
import ModelValidation
3+
import TestUtilities.InlineExpectationsTest
4+
5+
module SourceTest implements TestSig {
6+
string getARelevantTag() { result = "source" }
7+
8+
predicate hasActualResult(Location location, string element, string tag, string value) {
9+
exists(ThreatModelFlowSource s |
10+
s.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
11+
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
12+
element = s.toString() and
13+
value = "" and
14+
tag = "source"
15+
)
16+
}
17+
}
18+
19+
import MakeTest<SourceTest>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
testFailures
2+
invalidModelRow
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extensions:
2+
3+
- addsTo:
4+
pack: codeql/threat-models
5+
extensible: threatModelConfiguration
6+
data:
7+
- ["stdin", true, 0]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package test
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
)
8+
9+
func sink(string) {
10+
11+
}
12+
13+
func readStdinBuffer() {
14+
buf := make([]byte, 1024)
15+
n, err := os.Stdin.Read(buf) // $source
16+
if err != nil {
17+
return
18+
}
19+
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
20+
}
21+
22+
func readStdinBuffReader() {
23+
buf := make([]byte, 1024)
24+
r := bufio.NewReader(os.Stdin) // $source
25+
n, err := r.Read(buf)
26+
if err != nil {
27+
return
28+
}
29+
sink(string(buf[:n])) // $hasTaintFlow="type conversion"
30+
}
31+
32+
func scan() {
33+
var username, email string
34+
fmt.Scan(&username, &email) // $source
35+
sink(username) // $hasTaintFlow="username"
36+
}
37+
38+
func scanf() {
39+
var s string
40+
fmt.Scanf("%s", &s) // $source
41+
sink(s) // $hasTaintFlow="s"
42+
}
43+
44+
func scanl() {
45+
var s string
46+
fmt.Scanln(&s) // $source
47+
sink(s) // $hasTaintFlow="s"
48+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import go
2+
import semmle.go.dataflow.ExternalFlow
3+
import ModelValidation
4+
import experimental.frameworks.CleverGo
5+
import TestUtilities.InlineFlowTest
6+
7+
module Config implements DataFlow::ConfigSig {
8+
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
9+
10+
predicate isSink(DataFlow::Node sink) {
11+
sink.asExpr() = any(CallExpr c | c.getTarget().getName() = "sink").getArgument(0)
12+
}
13+
}
14+
15+
import TaintFlowTest<Config>

0 commit comments

Comments
 (0)