github / github/codeql

TaintTracking: copy inside range on map produces multiple (incomplete) path variants if struct or field are a pointer

オープン
#9,308 コメント 7 件 リアクション 0 件 担当者 0 名 GitHub で見る
Go
主要言語
CodeQL
スター
10.1k
フォーク
2.1k
平均マージ
2日 15時間
マージ済み PR(30日)
141

説明

## Summary

When a transfer of taint happens in a `range` loop, and the domain is a pointer to a struct and the field is a map, then the results will contain multiple paths.

## Preamble code

```golang
package main

func main() {}

func source() interface{} { return nil }

func sink(v interface{}) {}
func link(in interface{}, out interface{}) {}

type StructWithPointerField struct {
Params *map[string]string
}
type StructWithValueField struct {
Params map[string]string
}
```

## Cases with domain = a field of a struct (spoiler: most produce unexpected results)

```golang
func range_2A() {
src := source().(StructWithValueField)

{
data := make(map[string]interface{})
for key, value := range src.Params {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361815-734c3500-8cdc-11eb-9cb4-310fc1931589.png)

---

```golang
func range_2B() {
src := source().(*StructWithValueField)

{
data := make(map[string]interface{})
for key, value := range src.Params {
data[key] = value
}
sink(data)
}
}
```

nets the following result (multiple paths, which is **UNexpected**):

![image](https://user-images.githubusercontent.com/15271561/112362020-a7bff100-8cdc-11eb-95f2-53af130f276e.png)

---

```golang
func range_2C() {
src := source().(StructWithPointerField)

{
data := make(map[string]interface{})
for key, value := range *src.Params {
data[key] = value
}
sink(data)
}
}
```

nets the following result (multiple paths, which is **UNexpected**):

![image](https://user-images.githubusercontent.com/15271561/112362108-c2926580-8cdc-11eb-8136-84ec7b03a7f7.png)

---

```golang
func range_2D() {
src := source().(*StructWithPointerField)

{
data := make(map[string]interface{})
for key, value := range *src.Params {
data[key] = value
}
sink(data)
}
}
```

nets the following result (multiple paths, which is **UNexpected**):

![image](https://user-images.githubusercontent.com/15271561/112362217-e2298e00-8cdc-11eb-8581-555f2244e844.png)

## Cases with domain = map (spoiler: all satisfy expectations)

```golang
func range_1A() {
src := source().(map[string]string)

{
data := make(map[string]interface{})
for key, value := range src {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112360900-7d216880-8cdb-11eb-89b6-886256eed183.png)

---

```golang
func range_1B() {
src := source().(*map[string]string)

{
data := make(map[string]interface{})
for key, value := range *src {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361042-a510cc00-8cdb-11eb-8903-59fd4edefa16.png)

---

```golang
func range_1C() {
src := source().(*map[*string]string)

{
data := make(map[string]interface{})
for key, value := range *src {
data[*key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361146-bfe34080-8cdb-11eb-84c3-c087ef6f0d18.png)

---

```golang
func range_1D() {
src := source().(*map[string]*string)

{
data := make(map[string]interface{})
for key, value := range *src {
data[key] = *value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361233-d8ebf180-8cdb-11eb-9535-e2c230066d3c.png)

---

```golang
func range_1E() {
src := source().(*map[*string]*string)

{
data := make(map[string]interface{})
for key, value := range *src {
data[*key] = *value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361336-f02adf00-8cdb-11eb-957e-063f31b8eff0.png)

---

```golang
func range_1F() {
src := source().(string)

var (
Map map[string]string
)
link([]byte(src), &Map)

{
data := make(map[string]interface{})
for key, value := range Map {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361430-0afd5380-8cdc-11eb-9e76-053ccf6edad1.png)

---

```golang
func range_1G() {
src := source().(string)

Map := new(map[string]string)
link([]byte(src), Map)

{
data := make(map[string]interface{})
for key, value := range *Map {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361507-21a3aa80-8cdc-11eb-8bd3-00d6eafc31ea.png)

---

```golang
func range_1H() {
src := source().(string)

Map := make(map[string]string)
link([]byte(src), &Map)

{
data := make(map[string]interface{})
for key, value := range Map {
data[key] = value
}
sink(data)
}
}
```

nets the following result (one path, which is expected):

![image](https://user-images.githubusercontent.com/15271561/112361586-3aac5b80-8cdc-11eb-9103-5149e5dbb6f8.png)

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。