Skip to content

Commit f6c97a5

Browse files
committed
Add extra sanitizer Part.FileName()
1 parent db92372 commit f6c97a5

File tree

3 files changed

+54
-16
lines changed

3 files changed

+54
-16
lines changed

go/ql/lib/semmle/go/security/TaintedPathCustomizations.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,24 @@ module TaintedPath {
108108
}
109109
}
110110

111+
/**
112+
* A call to `mime/multipart.Part.FileName`, considered as a sanitizer
113+
* against path traversal.
114+
*
115+
* `Part.FileName` calls `path/filepath.Base` on its return value. In
116+
* general `path/filepath.Base` is not a sanitizer for path traversal, but in
117+
* this specific case where the output is going to be used as a filename
118+
* rather than a directory name, it is adequate.
119+
*/
120+
class MimeMultipartPartFileNameSanitizer extends Sanitizer {
121+
MimeMultipartPartFileNameSanitizer() {
122+
this =
123+
any(Method m | m.hasQualifiedName("mime/multipart", "Part", "FileName"))
124+
.getACall()
125+
.getResult()
126+
}
127+
}
128+
111129
/**
112130
* A check of the form `!strings.Contains(nd, "..")`, considered as a sanitizer guard for
113131
* path traversal.
Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
edges
2-
| TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:13:18:13:30 | call to Query | provenance | |
3-
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:16:29:16:40 | tainted_path | provenance | |
4-
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:20:57:20:68 | tainted_path | provenance | |
5-
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:67:39:67:56 | ...+... | provenance | |
6-
| TaintedPath.go:20:57:20:68 | tainted_path | TaintedPath.go:20:28:20:69 | call to Join | provenance | |
7-
| TaintedPath.go:67:39:67:56 | ...+... | TaintedPath.go:67:28:67:57 | call to Clean | provenance | |
2+
| TaintedPath.go:16:18:16:22 | selection of URL | TaintedPath.go:16:18:16:30 | call to Query | provenance | |
3+
| TaintedPath.go:16:18:16:30 | call to Query | TaintedPath.go:19:29:19:40 | tainted_path | provenance | |
4+
| TaintedPath.go:16:18:16:30 | call to Query | TaintedPath.go:23:57:23:68 | tainted_path | provenance | |
5+
| TaintedPath.go:16:18:16:30 | call to Query | TaintedPath.go:70:39:70:56 | ...+... | provenance | |
6+
| TaintedPath.go:23:57:23:68 | tainted_path | TaintedPath.go:23:28:23:69 | call to Join | provenance | |
7+
| TaintedPath.go:70:39:70:56 | ...+... | TaintedPath.go:70:28:70:57 | call to Clean | provenance | |
88
nodes
9-
| TaintedPath.go:13:18:13:22 | selection of URL | semmle.label | selection of URL |
10-
| TaintedPath.go:13:18:13:30 | call to Query | semmle.label | call to Query |
11-
| TaintedPath.go:16:29:16:40 | tainted_path | semmle.label | tainted_path |
12-
| TaintedPath.go:20:28:20:69 | call to Join | semmle.label | call to Join |
13-
| TaintedPath.go:20:57:20:68 | tainted_path | semmle.label | tainted_path |
14-
| TaintedPath.go:67:28:67:57 | call to Clean | semmle.label | call to Clean |
15-
| TaintedPath.go:67:39:67:56 | ...+... | semmle.label | ...+... |
9+
| TaintedPath.go:16:18:16:22 | selection of URL | semmle.label | selection of URL |
10+
| TaintedPath.go:16:18:16:30 | call to Query | semmle.label | call to Query |
11+
| TaintedPath.go:19:29:19:40 | tainted_path | semmle.label | tainted_path |
12+
| TaintedPath.go:23:28:23:69 | call to Join | semmle.label | call to Join |
13+
| TaintedPath.go:23:57:23:68 | tainted_path | semmle.label | tainted_path |
14+
| TaintedPath.go:70:28:70:57 | call to Clean | semmle.label | call to Clean |
15+
| TaintedPath.go:70:39:70:56 | ...+... | semmle.label | ...+... |
1616
subpaths
1717
#select
18-
| TaintedPath.go:16:29:16:40 | tainted_path | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:16:29:16:40 | tainted_path | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |
19-
| TaintedPath.go:20:28:20:69 | call to Join | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:20:28:20:69 | call to Join | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |
20-
| TaintedPath.go:67:28:67:57 | call to Clean | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:67:28:67:57 | call to Clean | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |
18+
| TaintedPath.go:19:29:19:40 | tainted_path | TaintedPath.go:16:18:16:22 | selection of URL | TaintedPath.go:19:29:19:40 | tainted_path | This path depends on a $@. | TaintedPath.go:16:18:16:22 | selection of URL | user-provided value |
19+
| TaintedPath.go:23:28:23:69 | call to Join | TaintedPath.go:16:18:16:22 | selection of URL | TaintedPath.go:23:28:23:69 | call to Join | This path depends on a $@. | TaintedPath.go:16:18:16:22 | selection of URL | user-provided value |
20+
| TaintedPath.go:70:28:70:57 | call to Clean | TaintedPath.go:16:18:16:22 | selection of URL | TaintedPath.go:70:28:70:57 | call to Clean | This path depends on a $@. | TaintedPath.go:16:18:16:22 | selection of URL | user-provided value |

go/ql/test/query-tests/Security/CWE-022/TaintedPath.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package main
22

33
import (
4+
"fmt"
5+
"io"
46
"io/ioutil"
7+
"mime/multipart"
58
"net/http"
69
"path"
710
"path/filepath"
@@ -76,4 +79,21 @@ func handler(w http.ResponseWriter, r *http.Request) {
7679
}
7780
data, _ = ioutil.ReadFile(files[0].Filename)
7881
w.Write(data)
82+
83+
// GOOD: Part.FileName sanitized by filepath.Base
84+
r.ParseMultipartForm(32 << 20)
85+
file, _, err := r.FormFile("uploadfile")
86+
if err != nil {
87+
return
88+
}
89+
reader := multipart.NewReader(file, "foo")
90+
91+
// Read the first part
92+
part, err := reader.NextPart()
93+
if err != nil {
94+
return
95+
}
96+
97+
data, _ = ioutil.ReadFile(part.FileName())
98+
// fmt.Println("Content-Type:", part.Header.Get("Content-Type"))
7999
}

0 commit comments

Comments
 (0)