TaintTracking: copy inside range on map produces multiple (incomplete) path variants if struct or field are a pointer
- Vorherrschende Sprache
- CodeQL
- Sterne
- 10.1k
- Forks
- 2.1k
- Ø Merge
- 2 T. 15 Std.
- Gemergte PRs (30 T.)
- 141
Beschreibung
## 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):

---
```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**):

---
```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**):

---
```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**):

## 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):

---
```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):

---
```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):

---
```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):

---
```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):

---
```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):

---
```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):

---
```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):

Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.