-
Notifications
You must be signed in to change notification settings - Fork 2k
Go: New File System Access Sinks #14064
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
25c60c4
v1
am0o0 f3ea72c
proper tests with depstubber, remove Duplicates :(
am0o0 52d1e45
add comments for better quality
am0o0 e239d76
Merge branch 'main' into amammad-go-NewFileSystemAccess
am0o0 9f9c9e0
fix issues according to codereview
am0o0 c5faddc
remove fasthttp in favor or fasthttp framework
am0o0 b7f874d
fix tests, better afero support!
am0o0 fd0d194
add changenote
am0o0 3febbec
fix qldoc and review suggestions
am0o0 cea44e2
added the go generate commands for depstubber
am0o0 73803ea
fix tests
am0o0 c6ad358
fix package FPs, fix additioanlstep issue
am0o0 9598bb5
stash
am0o0 7d5bbc3
put each new sink in its own framework
am0o0 9536345
fix tests, and review suggestions.
am0o0 22c4b51
do gofmt
am0o0 06ec3bb
fix beego tests
am0o0 c3a21da
fix Echo tests
am0o0 0c2275d
fix Gin tests
am0o0 0f5dd40
fix beego tests
am0o0 8d6f985
fix afero additional step and tests
am0o0 b6968d9
fix beego tests
am0o0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
go/ql/lib/change-notes/2023-09-25-add-new-file-system-access-sinks.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: minorAnalysis | ||
| --- | ||
| * Support has been added for file system access sinks in the following libraries: [net/http](https://pkg.go.dev/net/http), [Afero](https://github.com/spf13/afero), [beego](https://pkg.go.dev/github.com/astaxie/beego), [Echo](https://pkg.go.dev/github.com/labstack/echo), [Fiber](https://github.com/kataras/iris), [Gin](https://pkg.go.dev/github.com/gin-gonic/gin), [Iris](https://github.com/kataras/iris). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| /** | ||
| * Provides classes for working with sinks and taint propagators | ||
| * from the `github.com/spf13/afero` package. | ||
| */ | ||
|
|
||
| import go | ||
|
|
||
| /** | ||
| * Provide File system access sinks of [afero](https://github.com/spf13/afero) framework | ||
| */ | ||
| module Afero { | ||
| /** | ||
| * Gets all versions of `github.com/spf13/afero` | ||
| */ | ||
| string aferoPackage() { result = package("github.com/spf13/afero", "") } | ||
|
|
||
| /** | ||
| * The File system access sinks of [afero](https://github.com/spf13/afero) framework methods | ||
| */ | ||
| class AferoSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode { | ||
| AferoSystemAccess() { | ||
| exists(Method m | | ||
| m.hasQualifiedName(aferoPackage(), "HttpFs", | ||
| ["Create", "Open", "OpenFile", "Remove", "RemoveAll"]) and | ||
| this = m.getACall() | ||
| or | ||
| m.hasQualifiedName(aferoPackage(), "RegexpFs", | ||
| ["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and | ||
| this = m.getACall() | ||
| or | ||
| m.hasQualifiedName(aferoPackage(), "ReadOnlyFs", | ||
| ["Create", "Open", "OpenFile", "ReadDir", "ReadlinkIfPossible", "Mkdir", "MkdirAll"]) and | ||
| this = m.getACall() | ||
| or | ||
| m.hasQualifiedName(aferoPackage(), "OsFs", | ||
| [ | ||
| "Create", "Open", "OpenFile", "ReadlinkIfPossible", "Remove", "RemoveAll", "Mkdir", | ||
| "MkdirAll" | ||
| ]) and | ||
| this = m.getACall() | ||
| or | ||
| m.hasQualifiedName(aferoPackage(), "MemMapFs", | ||
| ["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and | ||
| this = m.getACall() | ||
| ) | ||
| } | ||
|
|
||
| override DataFlow::Node getAPathArgument() { result = this.getArgument(0) } | ||
| } | ||
|
|
||
| /** | ||
| * The File system access sinks of [afero](https://github.com/spf13/afero) framework utility functions | ||
| * | ||
| * Afero Type is basically is an wrapper around utility functions which make them like a method, look at [here](https://github.com/spf13/afero/blob/cf95922e71986c0116204b6eeb3b345a01ffd842/ioutil.go#L61) | ||
| * | ||
| * The Types that are not vulnerable: `afero.BasePathFs` and `afero.IOFS` | ||
| */ | ||
| class AferoUtilityFunctionSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode { | ||
| int pathArg; | ||
|
|
||
| AferoUtilityFunctionSystemAccess() { | ||
| // utility functions | ||
| exists(Function f | | ||
| f.hasQualifiedName(aferoPackage(), | ||
| ["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and | ||
| this = f.getACall() and | ||
| pathArg = 1 and | ||
| not aferoSanitizer(this.getArgument(0)) | ||
| ) | ||
| or | ||
| exists(Method m | | ||
| m.hasQualifiedName(aferoPackage(), "Afero", | ||
| ["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and | ||
| this = m.getACall() and | ||
| pathArg = 0 and | ||
| not aferoSanitizer(this.getReceiver()) | ||
| ) | ||
| } | ||
|
|
||
| override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) } | ||
| } | ||
|
|
||
| /** | ||
| * Holds if the Afero utility function has a first argument of a safe type like `NewBasePathFs`. | ||
| * | ||
| * e.g. | ||
| * ``` | ||
| * basePathFs := afero.NewBasePathFs(osFS, "tmp") | ||
| * afero.ReadFile(basePathFs, filepath) | ||
| * ``` | ||
| */ | ||
| predicate aferoSanitizer(DataFlow::Node n) { | ||
| exists(Function f | | ||
| f.hasQualifiedName(aferoPackage(), ["NewBasePathFs", "NewIOFS"]) and | ||
| TaintTracking::localTaint(f.getACall(), n) | ||
| ) | ||
| } | ||
|
|
||
| /** | ||
| * Holds if there is a dataflow node from n1 to n2 when initializing the Afero instance | ||
| * | ||
| * A helper for `aferoSanitizer` for when the Afero instance is initialized with one of the safe FS types like IOFS | ||
| * | ||
| * e.g.`n2 := &afero.Afero{Fs: afero.NewBasePathFs(osFS, "./")}` n1 is `afero.NewBasePathFs(osFS, "./")` | ||
| */ | ||
| class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep { | ||
| override predicate step(DataFlow::Node n1, DataFlow::Node n2) { | ||
| exists(StructLit st | st.getType().hasQualifiedName(aferoPackage(), "Afero") | | ||
| n1.asExpr() = st.getAnElement().(KeyValueExpr).getAChildExpr() and | ||
| n2.asExpr() = st | ||
| ) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * Provides classes for working the `github.com/gofiber/fiber` package. | ||
| */ | ||
|
|
||
| import go | ||
|
|
||
| private module Gin { | ||
| /** Gets the package name `github.com/gofiber/fiber`. */ | ||
| string packagePath() { result = package("github.com/gofiber/fiber", "") } | ||
|
|
||
| /** Gets the v2 module path `github.com/gofiber/fiber/v2` */ | ||
| string v2modulePath() { result = "github.com/gofiber/fiber/v2" } | ||
|
|
||
| /** | ||
| * The File system access sinks | ||
| */ | ||
| class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode { | ||
| int pathArg; | ||
|
|
||
| FsOperations() { | ||
| exists(Method m | | ||
| ( | ||
| m.hasQualifiedName(packagePath(), "Ctx", ["SendFile", "Download"]) and | ||
| pathArg = 0 | ||
| or | ||
| m.hasQualifiedName(packagePath(), "Ctx", "SaveFile") and | ||
| pathArg = 1 | ||
| or | ||
| m.hasQualifiedName(v2modulePath(), "Ctx", "SaveFileToStorage") and | ||
| pathArg = 1 | ||
| ) and | ||
| this = m.getACall() | ||
| ) | ||
| } | ||
|
|
||
| override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| /** | ||
| * Provides classes for working the `github.com/kataras/iris` package. | ||
| */ | ||
|
|
||
| import go | ||
|
|
||
| private module Iris { | ||
| /** Gets the v1 module path `github.com/kataras/iris`. */ | ||
| string v1modulePath() { result = "github.com/kataras/iris" } | ||
|
|
||
| /** Gets the v12 module path `github.com/kataras/iris/v12` */ | ||
| string v12modulePath() { result = "github.com/kataras/iris/v12" } | ||
|
|
||
| /** Gets the path for the context package of all versions of beego. */ | ||
| string contextPackagePath() { | ||
| result = v12contextPackagePath() | ||
| or | ||
| result = v1contextPackagePath() | ||
| } | ||
|
|
||
| /** Gets the path for the context package of beego v12. */ | ||
| string v12contextPackagePath() { result = v12modulePath() + "/context" } | ||
|
|
||
| /** Gets the path for the context package of beego v1. */ | ||
| string v1contextPackagePath() { result = v1modulePath() + "/server/web/context" } | ||
|
|
||
| /** | ||
| * The File system access sinks | ||
| */ | ||
| class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode { | ||
| int pathArg; | ||
|
|
||
| FsOperations() { | ||
| exists(Method m | | ||
| ( | ||
| m.hasQualifiedName(contextPackagePath(), "Context", | ||
| ["SendFile", "ServeFile", "SendFileWithRate", "ServeFileWithRate", "UploadFormFiles"]) and | ||
| pathArg = 0 | ||
| or | ||
| m.hasQualifiedName(v12contextPackagePath(), "Context", "SaveFormFile") and | ||
| pathArg = 1 | ||
| ) and | ||
| this = m.getACall() | ||
| ) | ||
| } | ||
|
|
||
| override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| testFailures | ||
| failures |
34 changes: 34 additions & 0 deletions
34
go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import go | ||
| import TestUtilities.InlineExpectationsTest | ||
|
|
||
| module FileSystemAccessTest implements TestSig { | ||
| string getARelevantTag() { result = ["FileSystemAccess", "succ", "pred"] } | ||
|
|
||
| predicate hasActualResult(Location location, string element, string tag, string value) { | ||
| exists(FileSystemAccess fsa | | ||
| fsa.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), | ||
| location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and | ||
| element = fsa.getAPathArgument().toString() and | ||
| value = fsa.getAPathArgument().toString() and | ||
| tag = "FileSystemAccess" | ||
| ) | ||
| or | ||
| exists(DataFlow::Node succ, DataFlow::Node pred | | ||
| any(Afero::AdditionalTaintStep adts).step(pred, succ) | ||
| | | ||
| succ.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), | ||
| location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and | ||
| element = succ.toString() and | ||
| value = succ.asExpr().(StructLit).getType().getName() and | ||
| tag = "succ" | ||
| or | ||
| pred.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), | ||
| location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and | ||
| element = pred.toString() and | ||
| value = pred.toString() and | ||
| tag = "pred" | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| import MakeTest<FileSystemAccessTest> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.