mirror of
https://github.com/github/codeql.git
synced 2026-01-29 14:23:03 +01:00
Merge branch 'main' into add-missing-licences-for-stubbed-libraries
This commit is contained in:
33
.github/workflows/check-change-note.yml
vendored
Normal file
33
.github/workflows/check-change-note.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
|
||||
paths:
|
||||
- "*/ql/src/**/*.ql"
|
||||
- "*/ql/src/**/*.qll"
|
||||
- "!**/experimental/**"
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if change note file is present
|
||||
uses: dorny/paths-filter@7c0f15b688b020e95e00f15c61299b022f08ca95 # v2.8.0
|
||||
id: paths_filter
|
||||
with:
|
||||
filters: |
|
||||
change_note:
|
||||
- '**/change-notes/*.md'
|
||||
- name: Get PR labels
|
||||
id: pr-labels
|
||||
uses: joerick/pr-labels-action@0a4cc4ee0ab557ec0b1ae1157fa6fa7f9f4c494b # v1.0.6
|
||||
- name: Fail if change note is missing
|
||||
uses: actions/github-script@v3
|
||||
if: |
|
||||
github.event.pull_request.draft == false &&
|
||||
steps.paths_filter.outputs.change_note == 'false' &&
|
||||
!contains(steps.pr-labels.outputs.labels, ' no-change-note-required ')
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
core.setFailed('No change note found.' +
|
||||
' Either add one, or add the `no-change-note-required` label.')
|
||||
12
.github/workflows/codeqltest.yml
vendored
12
.github/workflows/codeqltest.yml
vendored
@@ -7,10 +7,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.14
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.14
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
@@ -52,10 +52,10 @@ jobs:
|
||||
name: Test MacOS
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Set up Go 1.14
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.14
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
@@ -85,10 +85,10 @@ jobs:
|
||||
name: Test Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Set up Go 1.14
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.14
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Set up CodeQL CLI
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
* @github/codeql-go
|
||||
|
||||
# Documentation
|
||||
**/*.qhelp @shati-patel
|
||||
# Exclude experimental
|
||||
**/experimental/**/*.qhelp @github/codeql-go
|
||||
|
||||
3
Makefile
3
Makefile
@@ -115,7 +115,8 @@ ql/src/go.dbscheme.stats: ql/src/go.dbscheme build/stats/src.stamp extractor
|
||||
|
||||
test: all build/testdb/check-upgrade-path
|
||||
codeql test run ql/test --search-path . --consistency-queries ql/test/consistency
|
||||
env GOARCH=386 codeql$(EXE) test run ql/test/query-tests/Security/CWE-681 --search-path . --consistency-queries ql/test/consistency
|
||||
# use GOOS=linux because GOOS=darwin GOARCH=386 is no longer supported
|
||||
env GOOS=linux GOARCH=386 codeql$(EXE) test run ql/test/query-tests/Security/CWE-681 --search-path . --consistency-queries ql/test/consistency
|
||||
cd extractor; go test -mod=vendor ./... | grep -vF "[no test files]"
|
||||
|
||||
.PHONY: build/testdb/check-upgrade-path
|
||||
|
||||
2
change-notes/2021-02-18-go-116.md
Normal file
2
change-notes/2021-02-18-go-116.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The extractor now supports Go 1.16 and the new `io/fs` library that was introduced.
|
||||
@@ -549,10 +549,13 @@ func main() {
|
||||
install = exec.Command("glide", "install")
|
||||
log.Println("Installing dependencies using `glide install`")
|
||||
} else {
|
||||
// explicitly set go module support
|
||||
if depMode == GoGetWithModules {
|
||||
// enable go modules if used
|
||||
os.Setenv("GO111MODULE", "on")
|
||||
} else if depMode == GoGetNoModules {
|
||||
os.Setenv("GO111MODULE", "off")
|
||||
}
|
||||
|
||||
// get dependencies
|
||||
install = exec.Command("go", "get", "-v", "./...")
|
||||
log.Println("Installing dependencies using `go get -v ./...`.")
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/github/codeql-go
|
||||
|
||||
go 1.14
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.3.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Provides classes for working with untrusted flow sources, sinks and taint propagators
|
||||
* from the `github.com/astaxie/beego` package.
|
||||
* from the `github.com/beego/beego` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
@@ -8,21 +8,25 @@ import semmle.go.security.Xss
|
||||
private import semmle.go.security.SafeUrlFlowCustomizations
|
||||
|
||||
module Beego {
|
||||
/** Gets the package name `github.com/astaxie/beego`. */
|
||||
/** Gets the module path `github.com/astaxie/beego` or `github.com/beego/beego`. */
|
||||
bindingset[result]
|
||||
string packagePath() { result = package("github.com/astaxie/beego", "") }
|
||||
string modulePath() { result = ["github.com/astaxie/beego", "github.com/beego/beego"] }
|
||||
|
||||
/** Gets the context subpackage name `github.com/astaxie/beego/context`. */
|
||||
/** Gets the path for the root package of beego. */
|
||||
bindingset[result]
|
||||
string contextPackagePath() { result = package("github.com/astaxie/beego", "context") }
|
||||
string packagePath() { result = package(modulePath(), "") }
|
||||
|
||||
/** Gets the logs subpackage name `github.com/astaxie/beego/logs`. */
|
||||
/** Gets the path for the context package of beego. */
|
||||
bindingset[result]
|
||||
string logsPackagePath() { result = package("github.com/astaxie/beego", "logs") }
|
||||
string contextPackagePath() { result = package(modulePath(), "context") }
|
||||
|
||||
/** Gets the utils subpackage name `github.com/astaxie/beego/utils`. */
|
||||
/** Gets the path for the logs package of beego. */
|
||||
bindingset[result]
|
||||
string utilsPackagePath() { result = package("github.com/astaxie/beego", "utils") }
|
||||
string logsPackagePath() { result = package(modulePath(), "logs") }
|
||||
|
||||
/** Gets the path for the utils package of beego. */
|
||||
bindingset[result]
|
||||
string utilsPackagePath() { result = package(modulePath(), "utils") }
|
||||
|
||||
/**
|
||||
* `BeegoInput` sources of untrusted data.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provides models of the go-restful library (`https://github.com/emicklei/go-restful`).
|
||||
* Provides models of the [go-restful library](https://github.com/emicklei/go-restful).
|
||||
*/
|
||||
private module GoRestfulHttp {
|
||||
/** Gets the package name `github.com/emicklei/go-restful`. */
|
||||
|
||||
@@ -206,7 +206,7 @@ module SQL {
|
||||
private class SqlxSink extends SQL::QueryString::Range {
|
||||
SqlxSink() {
|
||||
exists(Method meth, string name, int n |
|
||||
meth.hasQualifiedName(package("github.com/jmoiron", "sqlx"), ["DB", "Tx"], name) and
|
||||
meth.hasQualifiedName(package("github.com/jmoiron/sqlx", ""), ["DB", "Tx"], name) and
|
||||
this = meth.getACall().getArgument(n)
|
||||
|
|
||||
name = ["Select", "Get"] and n = 1
|
||||
|
||||
@@ -40,6 +40,7 @@ import semmle.go.frameworks.stdlib.Fmt
|
||||
import semmle.go.frameworks.stdlib.Html
|
||||
import semmle.go.frameworks.stdlib.HtmlTemplate
|
||||
import semmle.go.frameworks.stdlib.Io
|
||||
import semmle.go.frameworks.stdlib.IoFs
|
||||
import semmle.go.frameworks.stdlib.IoIoutil
|
||||
import semmle.go.frameworks.stdlib.Log
|
||||
import semmle.go.frameworks.stdlib.Mime
|
||||
|
||||
@@ -319,5 +319,5 @@ module NhooyrWebSocket {
|
||||
module GobwasWs {
|
||||
/** Gets the package name `github.com/gobwas/ws`. */
|
||||
bindingset[result]
|
||||
string packagePath() { result = package("github.com/gobwas", "ws") }
|
||||
string packagePath() { result = package("github.com/gobwas/ws", "") }
|
||||
}
|
||||
|
||||
@@ -28,7 +28,10 @@ module XPath {
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node { }
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/antchfx/xpath package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [XPath](https://github.com/antchfx/xpath) package.
|
||||
*/
|
||||
private class AntchfxXpathXPathExpressionString extends Range {
|
||||
AntchfxXpathXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Compile%") |
|
||||
@@ -48,7 +51,10 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/antchfx/htmlquery package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [htmlquery](https://github.com/antchfx/htmlquery) package.
|
||||
*/
|
||||
private class AntchfxHtmlqueryXPathExpressionString extends Range {
|
||||
AntchfxHtmlqueryXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Find%") |
|
||||
@@ -63,7 +69,10 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/antchfx/xmlquery package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [xmlquery](https://github.com/antchfx/xmlquery) package.
|
||||
*/
|
||||
private class AntchfxXmlqueryXPathExpressionString extends Range {
|
||||
AntchfxXmlqueryXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Find%") |
|
||||
@@ -83,7 +92,10 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/antchfx/jsonquery package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [jsonquery](https://github.com/antchfx/jsonquery) package.
|
||||
*/
|
||||
private class AntchfxJsonqueryXPathExpressionString extends Range {
|
||||
AntchfxJsonqueryXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Find%") |
|
||||
@@ -98,22 +110,28 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/go-xmlpath/xmlpath package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [xmlpath](https://github.com/go-xmlpath/xmlpath) package.
|
||||
*/
|
||||
private class GoXmlpathXmlpathXPathExpressionString extends Range {
|
||||
GoXmlpathXmlpathXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Compile%") |
|
||||
f.hasQualifiedName(package("github.com/go-xmlpath/xmlpath", ""), name) and
|
||||
f.hasQualifiedName(XmlPath::packagePath(), name) and
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
or
|
||||
exists(Function f, string name | name.matches("MustCompile%") |
|
||||
f.hasQualifiedName(package("github.com/go-xmlpath/xmlpath", ""), name) and
|
||||
f.hasQualifiedName(XmlPath::packagePath(), name) and
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/ChrisTrenkamp/goxpath package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [goxpath](https://github.com/ChrisTrenkamp/goxpath) package.
|
||||
*/
|
||||
private class ChrisTrenkampGoxpathXPathExpressionString extends Range {
|
||||
ChrisTrenkampGoxpathXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Parse%") |
|
||||
@@ -128,7 +146,10 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/santhosh-tekuri/xpathparser package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [xpathparser](https://github.com/santhosh-tekuri/xpathparser) package.
|
||||
*/
|
||||
private class SanthoshTekuriXpathparserXPathExpressionString extends Range {
|
||||
SanthoshTekuriXpathparserXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Parse%") |
|
||||
@@ -143,7 +164,10 @@ module XPath {
|
||||
}
|
||||
}
|
||||
|
||||
/** An XPath expression string used in an API function of the https://github.com/jbowtie/gokogiri package. */
|
||||
/**
|
||||
* An XPath expression string used in an API function of the
|
||||
* [gokogiri]https://github.com/jbowtie/gokogiri) package.
|
||||
*/
|
||||
private class JbowtieGokogiriXPathExpressionString extends Range {
|
||||
JbowtieGokogiriXPathExpressionString() {
|
||||
exists(Function f, string name | name.matches("Compile%") |
|
||||
@@ -164,3 +188,11 @@ module XPath {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module XmlPath {
|
||||
/** Gets the package name `github.com/go-xmlpath/xmlpath` or `gopkg.in/xmlpath`. */
|
||||
bindingset[result]
|
||||
string packagePath() {
|
||||
result = package(["github.com/go-xmlpath/xmlpath", "gopkg.in/xmlpath"], "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,14 @@ module Io {
|
||||
// signature: func WriteString(w Writer, s string) (n int, err error)
|
||||
hasQualifiedName("io", "WriteString") and
|
||||
(inp.isParameter(1) and outp.isParameter(0))
|
||||
or
|
||||
// signature: func NopCloser(r io.Reader) io.ReadCloser
|
||||
hasQualifiedName("io", "NopCloser") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
or
|
||||
// signature: func ReadAll(r io.Reader) ([]byte, error)
|
||||
hasQualifiedName("io", "ReadAll") and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
|
||||
100
ql/src/semmle/go/frameworks/stdlib/IoFs.qll
Normal file
100
ql/src/semmle/go/frameworks/stdlib/IoFs.qll
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the 'io/fs' package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the 'io/fs' package.
|
||||
*/
|
||||
module IoFs {
|
||||
/** Gets the package name `io/fs`. */
|
||||
string packagePath() { result = "io/fs" }
|
||||
|
||||
private class FunctionModels extends TaintTracking::FunctionModel {
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
FunctionModels() {
|
||||
//signature: func Glob(fsys FS, pattern string) (matches []string, err error)
|
||||
this.hasQualifiedName(packagePath(), "Glob") and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
or
|
||||
//signature: func ReadFile(fsys FS, name string) ([]byte, error)
|
||||
this.hasQualifiedName(packagePath(), "ReadFile") and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
or
|
||||
//signature: func ReadDir(fsys FS, name string) ([]DirEntry, error)
|
||||
this.hasQualifiedName(packagePath(), "ReadDir") and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
or
|
||||
//signature: func Sub(fsys FS, dir string) (FS, error)
|
||||
this.hasQualifiedName(packagePath(), "Sub") and
|
||||
(inp.isParameter(0) and outp.isResult(0))
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Models a step from `fs` to `path` and `d` in
|
||||
* `fs.WalkDir(fs, "root", func(path string, d DirEntry, err error) {}`
|
||||
*/
|
||||
private class WalkDirStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
//signature: func WalkDir(fsys FS, root string, fn WalkDirFunc) error
|
||||
exists(DataFlow::CallNode call, DataFlow::FunctionNode f |
|
||||
call.getTarget().hasQualifiedName(packagePath(), "WalkDir") and
|
||||
f.getASuccessor*() = call.getArgument(2)
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = f.getParameter([0, 1])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class MethodModels extends TaintTracking::FunctionModel, Method {
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
MethodModels() {
|
||||
//signature: func (DirEntry).Name() string
|
||||
this.implements(packagePath(), "DirEntry", "Name") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
//signature: func (DirEntry).Info() (FileInfo, error)
|
||||
this.implements(packagePath(), "DirEntry", "Info") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (FS).Open(name string) (File, error)
|
||||
this.implements(packagePath(), "FS", "Open") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (GlobFS).Glob(pattern string) ([]string, error)
|
||||
this.implements(packagePath(), "GlobFS", "Glob") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (ReadDirFS).ReadDir(name string) ([]DirEntry, error)
|
||||
this.implements(packagePath(), "ReadDirFS", "ReadDir") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (ReadFileFS).ReadFile(name string) ([]byte, error)
|
||||
this.implements(packagePath(), "ReadFileFS", "ReadFile") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (SubFS).Sub(dir string) (FS, error)
|
||||
this.implements(packagePath(), "SubFS", "Sub") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
//signature: func (File).Read([]byte) (int, error)
|
||||
this.implements(packagePath(), "File", "Read") and
|
||||
(inp.isReceiver() and outp.isParameter(0))
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,18 @@ module Os {
|
||||
fn = "Symlink" and pathidx in [0 .. 1]
|
||||
or
|
||||
fn = "Truncate" and pathidx = 0
|
||||
or
|
||||
fn = "DirFS" and pathidx = 0
|
||||
or
|
||||
fn = "ReadDir" and pathidx = 0
|
||||
or
|
||||
fn = "ReadFile" and pathidx = 0
|
||||
or
|
||||
fn = "MkdirTemp" and pathidx in [0 .. 1]
|
||||
or
|
||||
fn = "CreateTemp" and pathidx in [0 .. 1]
|
||||
or
|
||||
fn = "WriteFile" and pathidx = 0
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@ private import Logrus
|
||||
abstract class SafeExternalAPIFunction extends Function { }
|
||||
|
||||
private predicate isDefaultSafePackage(Package package) {
|
||||
package.getPath() in [
|
||||
"time", "unicode/utf8", package("http://gopkg.in/go-playground/validator", "")
|
||||
]
|
||||
package.getPath() in ["time", "unicode/utf8", package("gopkg.in/go-playground/validator", "")]
|
||||
}
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
|
||||
@@ -42,16 +42,13 @@ module StoredXss {
|
||||
class FileNameSource extends Source {
|
||||
FileNameSource() {
|
||||
// the second parameter to a filepath.Walk function
|
||||
exists(DataFlow::ParameterNode prm, DataFlow::FunctionNode f, DataFlow::CallNode walkCall |
|
||||
prm = this and
|
||||
f.getParameter(0) = prm
|
||||
|
|
||||
walkCall.getTarget().hasQualifiedName("path/filepath", "Walk") and
|
||||
walkCall.getArgument(1) = f.getASuccessor*()
|
||||
exists(DataFlow::FunctionNode f, Function walkFn | this = f.getParameter(0) |
|
||||
walkFn.hasQualifiedName("path/filepath", ["Walk", "WalkDir"]) and
|
||||
walkFn.getACall().getArgument(1) = f.getASuccessor*()
|
||||
)
|
||||
or
|
||||
// A call to os.FileInfo.Name
|
||||
exists(Method m | m.implements("os", "FileInfo", "Name") |
|
||||
exists(Method m | m.implements("io/fs", "FileInfo", "Name") |
|
||||
m = this.(DataFlow::CallNode).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
1
ql/test/extractor-tests/go1.16/embed.expected
Normal file
1
ql/test/extractor-tests/go1.16/embed.expected
Normal file
@@ -0,0 +1 @@
|
||||
| embeddedfile.go:9:5:9:5 | e |
|
||||
5
ql/test/extractor-tests/go1.16/embed.ql
Normal file
5
ql/test/extractor-tests/go1.16/embed.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import go
|
||||
|
||||
from Variable v
|
||||
where exists(v.getDeclaration())
|
||||
select v
|
||||
15
ql/test/extractor-tests/go1.16/embeddedfile.go
Normal file
15
ql/test/extractor-tests/go1.16/embeddedfile.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//go:embed file
|
||||
var e string = "hi"
|
||||
|
||||
func main() {
|
||||
fmt.Println(e)
|
||||
e = "why"
|
||||
fmt.Println(e)
|
||||
}
|
||||
2
ql/test/extractor-tests/go1.16/file
Normal file
2
ql/test/extractor-tests/go1.16/file
Normal file
@@ -0,0 +1,2 @@
|
||||
file
|
||||
contents
|
||||
@@ -302,4 +302,14 @@ func RunAllTaints_Io() {
|
||||
out := TaintStepTest_IoWriterToWriteTo_B0I0O0(source)
|
||||
sink(24, out)
|
||||
}
|
||||
{
|
||||
source := newSource(25).(io.Reader)
|
||||
out := io.NopCloser(source)
|
||||
sink(25, out)
|
||||
}
|
||||
{
|
||||
source := newSource(26).(io.Reader)
|
||||
out, _ := io.ReadAll(source)
|
||||
sink(26, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
func walkDirCallback(path string, d fs.DirEntry, _ error) error {
|
||||
sink(14, path)
|
||||
sink(15, d)
|
||||
return nil
|
||||
}
|
||||
|
||||
func steps() {
|
||||
{
|
||||
source := newSource(0).(fs.FS)
|
||||
out, _ := fs.Glob(source, "*")
|
||||
sink(0, out)
|
||||
}
|
||||
{
|
||||
source := newSource(1).(fs.FS)
|
||||
out, _ := fs.ReadFile(source, "filename")
|
||||
sink(1, out)
|
||||
}
|
||||
{
|
||||
source := newSource(2).(fs.FS)
|
||||
out, _ := fs.ReadDir(source, "dirname")
|
||||
sink(2, out)
|
||||
}
|
||||
{
|
||||
source := newSource(3).(fs.FS)
|
||||
out, _ := fs.Sub(source, "dirname")
|
||||
sink(3, out)
|
||||
}
|
||||
{
|
||||
source := newSource(4).(fs.FS)
|
||||
fs.WalkDir(source, ".", func(_ string, d fs.DirEntry, _ error) error {
|
||||
sink(4, d)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
{
|
||||
source := newSource(5).(fs.FS)
|
||||
fs.WalkDir(source, ".", func(path string, _ fs.DirEntry, _ error) error {
|
||||
sink(5, path)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
{
|
||||
source := newSource(6).(fs.DirEntry)
|
||||
out := source.Name()
|
||||
sink(6, out)
|
||||
}
|
||||
{
|
||||
source := newSource(7).(fs.DirEntry)
|
||||
out, _ := source.Info()
|
||||
sink(7, out)
|
||||
}
|
||||
{
|
||||
source := newSource(8).(fs.FS)
|
||||
out, _ := source.Open("filename")
|
||||
sink(8, out)
|
||||
}
|
||||
{
|
||||
source := newSource(9).(fs.GlobFS)
|
||||
out, _ := source.Glob("*")
|
||||
sink(9, out)
|
||||
}
|
||||
{
|
||||
source := newSource(10).(fs.ReadDirFS)
|
||||
out, _ := source.ReadDir("dirname")
|
||||
sink(10, out)
|
||||
}
|
||||
{
|
||||
source := newSource(11).(fs.ReadFileFS)
|
||||
out, _ := source.ReadFile("filename")
|
||||
sink(11, out)
|
||||
}
|
||||
{
|
||||
source := newSource(12).(fs.SubFS)
|
||||
out, _ := source.Sub("dirname")
|
||||
sink(12, out)
|
||||
}
|
||||
{
|
||||
source := newSource(13).(fs.File)
|
||||
var out []byte
|
||||
source.Read(out)
|
||||
sink(13, out)
|
||||
}
|
||||
{
|
||||
source := newSource(14).(fs.FS)
|
||||
fs.WalkDir(source, ".", walkDirCallback)
|
||||
}
|
||||
{
|
||||
source := newSource(15).(fs.FS)
|
||||
fs.WalkDir(source, ".", walkDirCallback)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TaintStepTest_OsExpand_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
@@ -21,7 +22,7 @@ func TaintStepTest_OsExpandEnv_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
|
||||
func TaintStepTest_OsNewFile_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromUintptr784 := sourceCQL.(uintptr)
|
||||
intoFile957 := os.NewFile(fromUintptr784, "")
|
||||
intoFile957 := os.NewFile(fromUintptr784, "") // $fsaccess=""
|
||||
return intoFile957
|
||||
}
|
||||
|
||||
@@ -149,3 +150,34 @@ func RunAllTaints_Os() {
|
||||
sink(11, out)
|
||||
}
|
||||
}
|
||||
|
||||
func fsAccesses() {
|
||||
var path, path1, part string
|
||||
var time time.Time
|
||||
os.Chdir(path) // $fsaccess=path
|
||||
os.Chmod(path, 0600) // $fsaccess=path
|
||||
os.Chown(path, 1000, 1000) // $fsaccess=path
|
||||
os.Chtimes(path, time, time) // $fsaccess=path
|
||||
os.Create(path) // $fsaccess=path
|
||||
os.Lchown(path, 1000, 1000) // $fsaccess=path
|
||||
os.Link(path, path1) // $fsaccess=path $fsaccess=path1
|
||||
os.Lstat(path) // $fsaccess=path
|
||||
os.Mkdir(path, 0600) // $fsaccess=path
|
||||
os.MkdirAll(path, 0600) // $fsaccess=path
|
||||
os.NewFile(124, path) // $fsaccess=path
|
||||
os.Open(path) // $fsaccess=path
|
||||
os.OpenFile(path, os.O_RDONLY, 0600) // $fsaccess=path
|
||||
os.Readlink(path) // $fsaccess=path
|
||||
os.Remove(path) // $fsaccess=path
|
||||
os.RemoveAll(path) // $fsaccess=path
|
||||
os.Rename(path, path1) // $fsaccess=path $fsaccess=path1
|
||||
os.Stat(path) // $fsaccess=path
|
||||
os.Symlink(path, path1) // $fsaccess=path $fsaccess=path1
|
||||
os.Truncate(path, 1000) // $fsaccess=path
|
||||
os.DirFS(path) // $fsaccess=path
|
||||
os.ReadDir(path) // $fsaccess=path
|
||||
os.ReadFile(path) // $fsaccess=path
|
||||
os.MkdirTemp(path, part) // $fsaccess=path $fsaccess=part
|
||||
os.CreateTemp(path, part) // $fsaccess=path $fsaccess=part
|
||||
os.WriteFile(path, []byte{}, 0600) // $fsaccess=path
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class FileSystemAccessTest extends InlineExpectationsTest {
|
||||
FileSystemAccessTest() { this = "FileSystemAccess" }
|
||||
|
||||
override string getARelevantTag() { result = "fsaccess" }
|
||||
|
||||
override predicate hasActualResult(string file, int line, string element, string tag, string value) {
|
||||
exists(FileSystemAccess f |
|
||||
f.hasLocationInfo(file, line, _, _, _) and
|
||||
element = f.toString() and
|
||||
value = f.getAPathArgument().toString() and
|
||||
tag = "fsaccess"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
edges
|
||||
| StoredXss.go:13:21:13:31 | call to Name : string | StoredXss.go:13:21:13:36 | ...+... |
|
||||
| stored.go:16:3:16:28 | ... := ...[0] : pointer type | stored.go:28:22:28:25 | name |
|
||||
| stored.go:18:3:18:28 | ... := ...[0] : pointer type | stored.go:30:22:30:25 | name |
|
||||
| stored.go:59:30:59:33 | definition of path : string | stored.go:61:22:61:25 | path |
|
||||
nodes
|
||||
| StoredXss.go:13:21:13:31 | call to Name : string | semmle.label | call to Name : string |
|
||||
| StoredXss.go:13:21:13:36 | ...+... | semmle.label | ...+... |
|
||||
| stored.go:16:3:16:28 | ... := ...[0] : pointer type | semmle.label | ... := ...[0] : pointer type |
|
||||
| stored.go:28:22:28:25 | name | semmle.label | name |
|
||||
| stored.go:18:3:18:28 | ... := ...[0] : pointer type | semmle.label | ... := ...[0] : pointer type |
|
||||
| stored.go:30:22:30:25 | name | semmle.label | name |
|
||||
| stored.go:59:30:59:33 | definition of path : string | semmle.label | definition of path : string |
|
||||
| stored.go:61:22:61:25 | path | semmle.label | path |
|
||||
#select
|
||||
| StoredXss.go:13:21:13:36 | ...+... | StoredXss.go:13:21:13:31 | call to Name : string | StoredXss.go:13:21:13:36 | ...+... | Stored cross-site scripting vulnerability due to $@. | StoredXss.go:13:21:13:31 | call to Name | stored value |
|
||||
| stored.go:28:22:28:25 | name | stored.go:16:3:16:28 | ... := ...[0] : pointer type | stored.go:28:22:28:25 | name | Stored cross-site scripting vulnerability due to $@. | stored.go:16:3:16:28 | ... := ...[0] | stored value |
|
||||
| stored.go:30:22:30:25 | name | stored.go:18:3:18:28 | ... := ...[0] : pointer type | stored.go:30:22:30:25 | name | Stored cross-site scripting vulnerability due to $@. | stored.go:18:3:18:28 | ... := ...[0] | stored value |
|
||||
| stored.go:61:22:61:25 | path | stored.go:59:30:59:33 | definition of path : string | stored.go:61:22:61:25 | path | Stored cross-site scripting vulnerability due to $@. | stored.go:59:30:59:33 | definition of path | stored value |
|
||||
|
||||
@@ -3,8 +3,10 @@ package main
|
||||
import (
|
||||
"database/sql"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
@@ -51,3 +53,13 @@ func storedserve2() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func storedserve3() {
|
||||
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
|
||||
filepath.WalkDir(".", func(path string, _ fs.DirEntry, err error) error {
|
||||
// BAD: filenames are considered to be untrusted
|
||||
io.WriteString(w, path)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user