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

Commit 0e6feb9

Browse files
committed
Add test for json-iterator package, and support more of its API
Specifically the top-level functions Unmarshal and UnmarshalFromString are just convenience wrappers around the type API, which is the usual documented way to use the library.
1 parent e19f476 commit 0e6feb9

File tree

8 files changed

+468
-3
lines changed

8 files changed

+468
-3
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
/**
2-
* Provides classes modelling taint propagation through the `json-iterator` package.
2+
* Provides classes modelling taint propagation through marshalling and encoding functions.
33
*/
44

55
import go
66

7-
/** Models json-iterator's Unmarshal function, propagating taint from the JSON input to the decoded object. */
7+
/** A model of json-iterator's `Unmarshal` function, propagating taint from the JSON input to the decoded object. */
88
private class JsonIteratorUnmarshalFunction extends TaintTracking::FunctionModel,
99
UnmarshalingFunction::Range {
1010
JsonIteratorUnmarshalFunction() {
11-
this.hasQualifiedName("github.com/json-iterator/go", "Unmarshal")
11+
this.hasQualifiedName("github.com/json-iterator/go", ["Unmarshal", "UnmarshalFromString"])
12+
or
13+
exists(Method m |
14+
m.hasQualifiedName("github.com/json-iterator/go", "API", ["Unmarshal", "UnmarshalFromString"]) and
15+
this.(Method).implements(m)
16+
)
1217
}
1318

1419
override DataFlow::FunctionInput getAnInput() { result.isParameter(0) }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module jsonittest
2+
3+
go 1.14
4+
5+
require (
6+
github.com/json-iterator/go v1.1.10
7+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| jsoniter.go:28:15:28:24 | selection of field | jsoniter.go:23:20:23:38 | call to getUntrustedBytes : slice type | jsoniter.go:28:15:28:24 | selection of field | This command depends on $@. | jsoniter.go:23:20:23:38 | call to getUntrustedBytes | a user-provided value |
2+
| jsoniter.go:32:15:32:25 | selection of field | jsoniter.go:23:20:23:38 | call to getUntrustedBytes : slice type | jsoniter.go:32:15:32:25 | selection of field | This command depends on $@. | jsoniter.go:23:20:23:38 | call to getUntrustedBytes | a user-provided value |
3+
| jsoniter.go:36:15:36:25 | selection of field | jsoniter.go:24:21:24:40 | call to getUntrustedString : string | jsoniter.go:36:15:36:25 | selection of field | This command depends on $@. | jsoniter.go:24:21:24:40 | call to getUntrustedString | a user-provided value |
4+
| jsoniter.go:40:15:40:25 | selection of field | jsoniter.go:24:21:24:40 | call to getUntrustedString : string | jsoniter.go:40:15:40:25 | selection of field | This command depends on $@. | jsoniter.go:24:21:24:40 | call to getUntrustedString | a user-provided value |
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package jsonittest
2+
3+
import (
4+
jsoniter "github.com/json-iterator/go"
5+
"os/exec"
6+
)
7+
8+
func getUntrustedString() string {
9+
return "trouble"
10+
}
11+
12+
func getUntrustedBytes() []byte {
13+
return []byte{}
14+
}
15+
16+
type myData struct {
17+
field string
18+
}
19+
20+
func main() {
21+
22+
var json = jsoniter.ExampleConfig{}
23+
untrustedInput := getUntrustedBytes()
24+
untrustedString := getUntrustedString()
25+
26+
data := myData{}
27+
json.Unmarshal(untrustedInput, &data)
28+
exec.Command(data.field)
29+
30+
data2 := myData{}
31+
jsoniter.Unmarshal(untrustedInput, &data2)
32+
exec.Command(data2.field)
33+
34+
data3 := myData{}
35+
json.UnmarshalFromString(untrustedString, &data3)
36+
exec.Command(data3.field)
37+
38+
data4 := myData{}
39+
jsoniter.UnmarshalFromString(untrustedString, &data4)
40+
exec.Command(data4.field)
41+
42+
}
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.security.CommandInjection
3+
4+
class UntrustedFunction extends Function {
5+
UntrustedFunction() { this.getName() = ["getUntrustedString", "getUntrustedBytes"] }
6+
}
7+
8+
class UntrustedSource extends DataFlow::Node, UntrustedFlowSource::Range {
9+
UntrustedSource() { this = any(UntrustedFunction f).getACall() }
10+
}
11+
12+
from CommandInjection::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
13+
where cfg.hasFlowPath(source, sink)
14+
select sink.getNode(), source, sink, "This command depends on $@.", source.getNode(),
15+
"a user-provided value"

ql/test/library-tests/semmle/go/frameworks/Encoding/vendor/github.com/json-iterator/go/LICENSE

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)