mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'main' into redsun82/rust-str
This commit is contained in:
4
.github/workflows/compile-queries.yml
vendored
4
.github/workflows/compile-queries.yml
vendored
@@ -33,9 +33,9 @@ jobs:
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
|
||||
@@ -1,121 +1,141 @@
|
||||
package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value
|
||||
,,,8,,,,,,,,,,,,,,,,,,3,5
|
||||
archive/tar,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
archive/zip,,,6,,,,,,,,,,,,,,,,,,6,
|
||||
bufio,,,17,,,,,,,,,,,,,,,,,,17,
|
||||
bytes,,,43,,,,,,,,,,,,,,,,,,43,
|
||||
clevergo.tech/clevergo,1,,,,,,,,,,,,,,1,,,,,,,
|
||||
compress/bzip2,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
compress/flate,,,4,,,,,,,,,,,,,,,,,,4,
|
||||
compress/gzip,,,3,,,,,,,,,,,,,,,,,,3,
|
||||
compress/lzw,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
compress/zlib,,,4,,,,,,,,,,,,,,,,,,4,
|
||||
container/heap,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
container/list,,,20,,,,,,,,,,,,,,,,,,20,
|
||||
container/ring,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
context,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
crypto,,,10,,,,,,,,,,,,,,,,,,10,
|
||||
database/sql,,,11,,,,,,,,,,,,,,,,,,11,
|
||||
encoding,,,77,,,,,,,,,,,,,,,,,,77,
|
||||
errors,,,3,,,,,,,,,,,,,,,,,,3,
|
||||
expvar,,,6,,,,,,,,,,,,,,,,,,6,
|
||||
fmt,,,16,,,,,,,,,,,,,,,,,,16,
|
||||
github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,3,,,,,,
|
||||
github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,8,,,,,,
|
||||
github.com/antchfx/xpath,4,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/astaxie/beego,7,21,21,,,,5,,,,,,2,,,,,,21,,21,
|
||||
github.com/beego/beego,14,42,42,,,,10,,,,,,4,,,,,,42,,42,
|
||||
github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,5,,,,1,1
|
||||
github.com/clevergo/clevergo,1,,,,,,,,,,,,,,1,,,,,,,
|
||||
github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,
|
||||
github.com/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,,18,
|
||||
github.com/couchbaselabs/gocb,,,18,,,,,,,,,,,,,,,,,,18,
|
||||
github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,9,
|
||||
github.com/elazarl/goproxy,,2,2,,,,,,,,,,,,,,,,2,,2,
|
||||
github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,7,,,
|
||||
github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,12,
|
||||
github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,
|
||||
github.com/gin-gonic/gin,3,46,2,,,,3,,,,,,,,,,,,46,,2,
|
||||
github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,3,,,
|
||||
github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,4,
|
||||
github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,6,
|
||||
github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,7,,,,,
|
||||
github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,2,,,
|
||||
github.com/gofiber/fiber,5,,,,,,4,,,,,,,,1,,,,,,,
|
||||
github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,11,
|
||||
github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,1,,,
|
||||
github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,3,,,
|
||||
github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,1,,,,,
|
||||
github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,,,
|
||||
github.com/joho/godotenv,,4,,,,,,,,,,,,,,,4,,,,,
|
||||
github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/kataras/iris/context,6,,,,,,6,,,,,,,,,,,,,,,
|
||||
github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,
|
||||
github.com/kataras/iris/server/web/context,6,,,,,,6,,,,,,,,,,,,,,,
|
||||
github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,
|
||||
github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,6,,,,,
|
||||
github.com/labstack/echo,3,12,2,,,,2,,,,,,1,,,,,,12,,2,
|
||||
github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,
|
||||
github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,3,,,,,,
|
||||
github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,
|
||||
github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,,,
|
||||
github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,
|
||||
github.com/revel/revel,2,23,10,,,,1,,,,,,1,,,,,,23,,10,
|
||||
github.com/robfig/revel,2,23,10,,,,1,,,,,,1,,,,,,23,,10,
|
||||
github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
github.com/spf13/afero,34,,,,,,34,,,,,,,,,,,,,,,
|
||||
github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,4,
|
||||
github.com/valyala/fasthttp,35,50,5,,,,8,,,,17,8,2,,,,,,50,,5,
|
||||
go.uber.org/zap,,,11,,,,,,,,,,,,,,,,,,11,
|
||||
golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,
|
||||
golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,5,
|
||||
golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,16,
|
||||
golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,2,,,
|
||||
google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,2,
|
||||
google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,8,
|
||||
google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
gopkg.in/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,,18,
|
||||
gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,4,
|
||||
gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
gopkg.in/macaron,1,12,1,,,,,,,,,,,,1,,,,12,,1,
|
||||
gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,4,
|
||||
gopkg.in/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,9,
|
||||
html,,,8,,,,,,,,,,,,,,,,,,8,
|
||||
io,5,4,34,,,,5,,,,,,,,,,,4,,,34,
|
||||
k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,10,
|
||||
k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,47,
|
||||
launchpad.net/xmlpath,2,,,,,,,,,,,,,,,2,,,,,,
|
||||
log,,,3,,,,,,,,,,,,,,,,,,3,
|
||||
math/big,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
mime,,,14,,,,,,,,,,,,,,,,,,14,
|
||||
net,2,16,100,,,,1,,,,,,,1,,,,,16,,100,
|
||||
nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,2,,,
|
||||
os,29,11,6,3,,,26,,,,,,,,,,7,3,,1,6,
|
||||
path,,,18,,,,,,,,,,,,,,,,,,18,
|
||||
reflect,,,37,,,,,,,,,,,,,,,,,,37,
|
||||
regexp,10,,20,,,,,3,3,4,,,,,,,,,,,20,
|
||||
sort,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
strconv,,,9,,,,,,,,,,,,,,,,,,9,
|
||||
strings,,,34,,,,,,,,,,,,,,,,,,34,
|
||||
sync,,,34,,,,,,,,,,,,,,,,,,34,
|
||||
syscall,5,2,8,5,,,,,,,,,,,,,2,,,,8,
|
||||
text/scanner,,,3,,,,,,,,,,,,,,,,,,3,
|
||||
text/tabwriter,,,1,,,,,,,,,,,,,,,,,,1,
|
||||
text/template,,,6,,,,,,,,,,,,,,,,,,6,
|
||||
package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:log-injection,sink:nosql-injection,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:sql-injection,sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value
|
||||
,,,8,,,,,,,,,,,,,,,,,,,,,3,5
|
||||
archive/tar,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
archive/zip,,,6,,,,,,,,,,,,,,,,,,,,,6,
|
||||
bufio,,,17,,,,,,,,,,,,,,,,,,,,,17,
|
||||
bytes,,,43,,,,,,,,,,,,,,,,,,,,,43,
|
||||
clevergo.tech/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
|
||||
compress/bzip2,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
compress/flate,,,4,,,,,,,,,,,,,,,,,,,,,4,
|
||||
compress/gzip,,,3,,,,,,,,,,,,,,,,,,,,,3,
|
||||
compress/lzw,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
compress/zlib,,,4,,,,,,,,,,,,,,,,,,,,,4,
|
||||
container/heap,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
container/list,,,20,,,,,,,,,,,,,,,,,,,,,20,
|
||||
container/ring,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
context,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
crypto,,,10,,,,,,,,,,,,,,,,,,,,,10,
|
||||
database/sql,30,,11,,,,,,,,,,,,30,,,,,,,,,11,
|
||||
encoding,,,77,,,,,,,,,,,,,,,,,,,,,77,
|
||||
errors,,,3,,,,,,,,,,,,,,,,,,,,,3,
|
||||
expvar,,,6,,,,,,,,,,,,,,,,,,,,,6,
|
||||
fmt,3,,16,,,,3,,,,,,,,,,,,,,,,,16,
|
||||
github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,,,,3,,,,,,
|
||||
github.com/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
|
||||
github.com/Sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
|
||||
github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,,,,8,,,,,,
|
||||
github.com/antchfx/xpath,4,,,,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/astaxie/beego,71,21,21,,,,34,,5,,,,,,30,2,,,,,,21,,21,
|
||||
github.com/beego/beego,142,42,42,,,,68,,10,,,,,,60,4,,,,,,42,,42,
|
||||
github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,,,,5,,,,1,1
|
||||
github.com/clevergo/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,,
|
||||
github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
|
||||
github.com/couchbaselabs/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
|
||||
github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/davecgh/go-spew/spew,9,,,,,,9,,,,,,,,,,,,,,,,,,
|
||||
github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,,,,9,
|
||||
github.com/elazarl/goproxy,2,2,2,,,,2,,,,,,,,,,,,,,,2,,2,
|
||||
github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,,,,7,,,
|
||||
github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,,,,12,
|
||||
github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/gin-gonic/gin,3,46,2,,,,,,3,,,,,,,,,,,,,46,,2,
|
||||
github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,,,,3,,,
|
||||
github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/go-gorm/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
|
||||
github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,,,,6,
|
||||
github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/go-xorm/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
|
||||
github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,,,,7,,,,,
|
||||
github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,,,,2,,,
|
||||
github.com/gofiber/fiber,5,,,,,,,,4,,,,,,,,,1,,,,,,,
|
||||
github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/gogf/gf/database/gdb,51,,,,,,,,,,,,,,51,,,,,,,,,,
|
||||
github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,,,,11,
|
||||
github.com/golang/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
|
||||
github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,,,,1,,,
|
||||
github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,,,,3,,,
|
||||
github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,,,,1,,,,,
|
||||
github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
|
||||
github.com/jinzhu/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
|
||||
github.com/jmoiron/sqlx,12,,,,,,,,,,,,,,12,,,,,,,,,,
|
||||
github.com/joho/godotenv,,4,,,,,,,,,,,,,,,,,,4,,,,,
|
||||
github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/kataras/iris/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
|
||||
github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/kataras/iris/server/web/context,6,,,,,,,,6,,,,,,,,,,,,,,,,
|
||||
github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,,,,6,,,,,
|
||||
github.com/labstack/echo,3,12,2,,,,,,2,,,,,,,1,,,,,,12,,2,
|
||||
github.com/lann/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
|
||||
github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,,,,3,,,,,,
|
||||
github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,,
|
||||
github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,,
|
||||
github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,,
|
||||
github.com/raindog308/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
|
||||
github.com/revel/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
|
||||
github.com/robfig/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10,
|
||||
github.com/rqlite/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,,
|
||||
github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
github.com/sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,,
|
||||
github.com/spf13/afero,34,,,,,,,,34,,,,,,,,,,,,,,,,
|
||||
github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
|
||||
github.com/uptrace/bun,63,,,,,,,,,,,,,,63,,,,,,,,,,
|
||||
github.com/valyala/fasthttp,35,50,5,,,,,,8,,,,17,8,,2,,,,,,50,,5,
|
||||
go.mongodb.org/mongo-driver/mongo,14,,,,,,,14,,,,,,,,,,,,,,,,,
|
||||
go.uber.org/zap,33,,11,,,,33,,,,,,,,,,,,,,,,,11,
|
||||
golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,,,,
|
||||
golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,,,,5,
|
||||
golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,,,,16,
|
||||
golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
|
||||
google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,,,,2,
|
||||
google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,,,,8,
|
||||
google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
gopkg.in/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,,
|
||||
gopkg.in/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18,
|
||||
gopkg.in/glog,90,,,,,,90,,,,,,,,,,,,,,,,,,
|
||||
gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
|
||||
gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
gopkg.in/macaron,1,12,1,,,,,,,,,,,,,,,1,,,,12,,1,
|
||||
gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4,
|
||||
gopkg.in/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,,,,9,
|
||||
gorm.io/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,,
|
||||
html,,,8,,,,,,,,,,,,,,,,,,,,,8,
|
||||
io,5,4,34,,,,,,5,,,,,,,,,,,,4,,,34,
|
||||
k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,10,
|
||||
k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,47,
|
||||
k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,,
|
||||
launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,,
|
||||
log,20,,3,,,,20,,,,,,,,,,,,,,,,,3,
|
||||
math/big,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
mime,,,14,,,,,,,,,,,,,,,,,,,,,14,
|
||||
net,2,16,100,,,,,,1,,,,,,,,1,,,,,16,,100,
|
||||
nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,,
|
||||
os,29,11,6,3,,,,,26,,,,,,,,,,,7,3,,1,6,
|
||||
path,,,18,,,,,,,,,,,,,,,,,,,,,18,
|
||||
reflect,,,37,,,,,,,,,,,,,,,,,,,,,37,
|
||||
regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,20,
|
||||
sort,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
strconv,,,9,,,,,,,,,,,,,,,,,,,,,9,
|
||||
strings,,,34,,,,,,,,,,,,,,,,,,,,,34,
|
||||
sync,,,34,,,,,,,,,,,,,,,,,,,,,34,
|
||||
syscall,5,2,8,5,,,,,,,,,,,,,,,,2,,,,8,
|
||||
text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,3,
|
||||
text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
text/template,,,6,,,,,,,,,,,,,,,,,,,,,6,
|
||||
xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,
|
||||
|
||||
|
@@ -9,27 +9,27 @@ Go framework & library support
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total)
|
||||
`Afero <https://github.com/spf13/afero>`_,``github.com/spf13/afero*``,,,34
|
||||
`CleverGo <https://github.com/clevergo/clevergo>`_,"``clevergo.tech/clevergo*``, ``github.com/clevergo/clevergo*``",,,2
|
||||
`Couchbase official client(gocb) <https://github.com/couchbase/gocb>`_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36,
|
||||
`Couchbase unofficial client <http://www.github.com/couchbase/go-couchbase>`_,``github.com/couchbaselabs/gocb*``,,18,
|
||||
`Couchbase official client(gocb) <https://github.com/couchbase/gocb>`_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36,16
|
||||
`Couchbase unofficial client <http://www.github.com/couchbase/go-couchbase>`_,``github.com/couchbaselabs/gocb*``,,18,8
|
||||
`Echo <https://echo.labstack.com/>`_,``github.com/labstack/echo*``,12,2,3
|
||||
`Fiber <https://github.com/gofiber/fiber>`_,``github.com/gofiber/fiber*``,,,5
|
||||
`Fosite <https://github.com/ory/fosite>`_,``github.com/ory/fosite*``,,,2
|
||||
`Gin <https://github.com/gin-gonic/gin>`_,``github.com/gin-gonic/gin*``,46,2,3
|
||||
`Glog <https://github.com/golang/glog>`_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,,
|
||||
`Glog <https://github.com/golang/glog>`_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,,270
|
||||
`Go JOSE <https://github.com/go-jose/go-jose>`_,"``github.com/go-jose/go-jose*``, ``github.com/square/go-jose*``, ``gopkg.in/square/go-jose*``, ``gopkg.in/go-jose/go-jose*``",,16,12
|
||||
`Go kit <https://gokit.io/>`_,``github.com/go-kit/kit*``,,,1
|
||||
`Go-spew <https://github.com/davecgh/go-spew>`_,``github.com/davecgh/go-spew/spew*``,,,
|
||||
`Go-spew <https://github.com/davecgh/go-spew>`_,``github.com/davecgh/go-spew/spew*``,,,9
|
||||
`Gokogiri <https://github.com/moovweb/gokogiri>`_,"``github.com/jbowtie/gokogiri*``, ``github.com/moovweb/gokogiri*``",,,10
|
||||
`Iris <https://www.iris-go.com/>`_,``github.com/kataras/iris*``,,,14
|
||||
`Kubernetes <https://kubernetes.io/>`_,"``k8s.io/api*``, ``k8s.io/apimachinery*``",,57,
|
||||
`Logrus <https://github.com/sirupsen/logrus>`_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,,
|
||||
`Logrus <https://github.com/sirupsen/logrus>`_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,,290
|
||||
`Macaron <https://gopkg.in/macaron.v1>`_,``gopkg.in/macaron*``,12,1,1
|
||||
`Revel <http://revel.github.io/>`_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4
|
||||
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_,``github.com/sendgrid/sendgrid-go*``,,1,
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,587,51
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,587,104
|
||||
`XPath <https://github.com/antchfx/xpath>`_,``github.com/antchfx/xpath*``,,,4
|
||||
`appleboy/gin-jwt <https://github.com/appleboy/gin-jwt>`_,``github.com/appleboy/gin-jwt*``,,,1
|
||||
`beego <https://beego.me/>`_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,21
|
||||
`beego <https://beego.me/>`_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,213
|
||||
`chi <https://go-chi.io/>`_,``github.com/go-chi/chi*``,3,,
|
||||
`cristalhq/jwt <https://github.com/cristalhq/jwt>`_,``github.com/cristalhq/jwt*``,,,1
|
||||
`fasthttp <https://github.com/valyala/fasthttp>`_,``github.com/valyala/fasthttp*``,50,5,35
|
||||
@@ -39,7 +39,7 @@ Go framework & library support
|
||||
`go-sh <https://github.com/codeskyblue/go-sh>`_,``github.com/codeskyblue/go-sh*``,,,4
|
||||
`golang.org/x/crypto/ssh <https://pkg.go.dev/golang.org/x/crypto/ssh>`_,``golang.org/x/crypto/ssh*``,,,4
|
||||
`golang.org/x/net <https://pkg.go.dev/golang.org/x/net>`_,``golang.org/x/net*``,2,21,
|
||||
`goproxy <https://github.com/elazarl/goproxy>`_,``github.com/elazarl/goproxy*``,2,2,
|
||||
`goproxy <https://github.com/elazarl/goproxy>`_,``github.com/elazarl/goproxy*``,2,2,2
|
||||
`gorilla/mux <https://github.com/gorilla/mux>`_,``github.com/gorilla/mux*``,1,,
|
||||
`gorilla/websocket <https://github.com/gorilla/websocket>`_,``github.com/gorilla/websocket*``,3,,
|
||||
`goxpath <https://github.com/ChrisTrenkamp/goxpath/wiki>`_,``github.com/ChrisTrenkamp/goxpath*``,,,3
|
||||
@@ -59,7 +59,7 @@ Go framework & library support
|
||||
`xmlquery <https://github.com/antchfx/xmlquery>`_,``github.com/antchfx/xmlquery*``,,,8
|
||||
`xpathparser <https://github.com/santhosh-tekuri/xpathparser>`_,``github.com/santhosh-tekuri/xpathparser*``,,,2
|
||||
`yaml <https://gopkg.in/yaml.v3>`_,``gopkg.in/yaml*``,,9,
|
||||
`zap <https://go.uber.org/zap>`_,``go.uber.org/zap*``,,11,
|
||||
Others,"``github.com/caarlos0/env``, ``github.com/gobuffalo/envy``, ``github.com/hashicorp/go-envparse``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``",23,2,
|
||||
Totals,,307,911,268
|
||||
`zap <https://go.uber.org/zap>`_,``go.uber.org/zap*``,,11,33
|
||||
Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",23,2,391
|
||||
Totals,,307,911,1532
|
||||
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
help="Usage: ./publish [--override-release] [--dry-run]
|
||||
Publish the automodel query pack.
|
||||
|
||||
If no arguments are provided, publish the version of the codeql repo specified by the latest official release of the codeml-automodel repo.
|
||||
If the --override-release argument is provided, your current local HEAD is used (for unofficial releases or patching).
|
||||
If the --dry-run argument is provided, the release is not published (for testing purposes)."
|
||||
|
||||
# Echo the help message
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
echo "$help"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check the number of arguments are valid
|
||||
if [ $# -gt 2 ]; then
|
||||
echo "Error: Invalid arguments provided"
|
||||
echo "$help"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OVERRIDE_RELEASE=0
|
||||
DRY_RUN=0
|
||||
for arg in "$@"
|
||||
do
|
||||
case $arg in
|
||||
--override-release)
|
||||
OVERRIDE_RELEASE=1
|
||||
shift # Remove --override-release from processing
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift # Remove --dry-run from processing
|
||||
;;
|
||||
*)
|
||||
echo "Error: Invalid argument provided: $arg"
|
||||
echo "$help"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Describe what we're about to do based on the command-line arguments
|
||||
if [ $OVERRIDE_RELEASE = 1 ]; then
|
||||
echo "Publishing the current HEAD of the automodel repo"
|
||||
else
|
||||
echo "Publishing the version of the automodel repo specified by the latest official release of the codeml-automodel repo"
|
||||
fi
|
||||
if [ $DRY_RUN = 1 ]; then
|
||||
echo "Dry run: we will step through the process but we won't publish the query pack"
|
||||
else
|
||||
echo "Not a dry run! Publishing the query pack"
|
||||
fi
|
||||
|
||||
# If we're publishing the codeml-automodel release then we will checkout the sha specified in the release.
|
||||
# So we need to check that there are no uncommitted changes in the local branch.
|
||||
# And, if we're publishing the current HEAD, it's cleaner to ensure that there are no uncommitted changes.
|
||||
if ! git diff --quiet; then
|
||||
echo "Error: Uncommitted changes exist. Please commit or stash your changes before publishing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check the above environment variables are set
|
||||
if [ -z "${GITHUB_TOKEN}" ]; then
|
||||
echo "Error: GITHUB_TOKEN environment variable not set. Please set this to a token with package:write permissions to codeql."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "${GH_TOKEN}" ]; then
|
||||
echo "Error: GH_TOKEN environment variable not set. Please set this to a token with repo permissions to github/codeml-automodel."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the sha of the previous release, i.e. the last commit to the main branch that updated the query pack version
|
||||
PREVIOUS_RELEASE_SHA=$(git rev-list -n 1 main -- ./src/qlpack.yml)
|
||||
if [ -z "$PREVIOUS_RELEASE_SHA" ]; then
|
||||
echo "Error: Could not get the sha of the previous release of codeml-automodel query pack"
|
||||
exit 1
|
||||
else
|
||||
echo "Previous query-pack release sha: $PREVIOUS_RELEASE_SHA"
|
||||
fi
|
||||
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
CURRENT_SHA=$(git rev-parse HEAD)
|
||||
|
||||
if [ $OVERRIDE_RELEASE = 1 ]; then
|
||||
# Check that the current HEAD is downstream from PREVIOUS_RELEASE_SHA
|
||||
if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$CURRENT_SHA"; then
|
||||
echo "Error: The current HEAD is not downstream from the previous release"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Get the latest release of codeml-automodel
|
||||
TAG_NAME=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/github/codeml-automodel/releases/latest | jq -r .tag_name)
|
||||
# Check TAG_NAME is not empty
|
||||
if [ -z "$TAG_NAME" ]; then
|
||||
echo "Error: Could not get latest release of codeml-automodel"
|
||||
exit 1
|
||||
fi
|
||||
echo "Updating to latest automodel release: $TAG_NAME"
|
||||
# Before downloading, delete any existing release.zip, and ignore failure if not present
|
||||
rm release.zip || true
|
||||
gh release download $TAG_NAME -A zip -O release.zip --repo 'https://github.com/github/codeml-automodel'
|
||||
# Before unzipping, delete any existing release directory, and ignore failure if not present
|
||||
rm -rf release || true
|
||||
unzip -o release.zip -d release
|
||||
REVISION=$(jq -r '.["codeql-sha"]' release/codeml-automodel*/codeml-automodel-release.json)
|
||||
echo "The latest codeml-automodel release specifies the codeql sha $REVISION"
|
||||
# Check that REVISION is downstream from PREVIOUS_RELEASE_SHA
|
||||
if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$REVISION"; then
|
||||
echo "Error: The codeql version $REVISION is not downstream of the query-pack version $PREVIOUS_RELEASE_SHA"
|
||||
exit 1
|
||||
fi
|
||||
# Get the version of the codeql code specified by the codeml-automodel release
|
||||
git checkout "$REVISION"
|
||||
fi
|
||||
|
||||
# Get the absolute path of the automodel repo
|
||||
AUTOMODEL_ROOT="$(readlink -f "$(dirname $0)")"
|
||||
# Get the absolute path of the workspace root
|
||||
WORKSPACE_ROOT="$AUTOMODEL_ROOT/../../.."
|
||||
# Specify the groups of queries to test and publish
|
||||
GRPS="automodel,-test"
|
||||
|
||||
# Install the codeql gh extension
|
||||
gh extensions install github/gh-codeql
|
||||
|
||||
pushd "$AUTOMODEL_ROOT"
|
||||
echo Testing automodel queries
|
||||
gh codeql test run test
|
||||
popd
|
||||
|
||||
pushd "$WORKSPACE_ROOT"
|
||||
echo "Preparing the release"
|
||||
gh codeql pack release --groups $GRPS -v
|
||||
|
||||
if [ $DRY_RUN = 1 ]; then
|
||||
echo "Dry run: not publishing the query pack"
|
||||
gh codeql pack publish --groups $GRPS --dry-run -v
|
||||
else
|
||||
echo "Not a dry run! Publishing the query pack"
|
||||
gh codeql pack publish --groups $GRPS -v
|
||||
fi
|
||||
|
||||
echo "Bumping versions"
|
||||
gh codeql pack post-release --groups $GRPS -v
|
||||
popd
|
||||
|
||||
# The above commands update
|
||||
# ./src/CHANGELOG.md
|
||||
# ./src/codeql-pack.release.yml
|
||||
# ./src/qlpack.yml
|
||||
# and add a new file
|
||||
# ./src/change-notes/released/<version>.md
|
||||
|
||||
# Get the filename of the most recently created file in ./src/change-notes/released/*.md
|
||||
# This will be the file for the new release
|
||||
NEW_CHANGE_NOTES_FILE=$(ls -t ./src/change-notes/released/*.md | head -n 1)
|
||||
|
||||
# Make a copy of the modified files
|
||||
mv ./src/CHANGELOG.md ./src/CHANGELOG.md.dry-run
|
||||
mv ./src/codeql-pack.release.yml ./src/codeql-pack.release.yml.dry-run
|
||||
mv ./src/qlpack.yml ./src/qlpack.yml.dry-run
|
||||
mv "$NEW_CHANGE_NOTES_FILE" ./src/change-notes/released.md.dry-run
|
||||
|
||||
if [ $OVERRIDE_RELEASE = 1 ]; then
|
||||
# Restore the original files
|
||||
git checkout ./src/CHANGELOG.md
|
||||
git checkout ./src/codeql-pack.release.yml
|
||||
git checkout ./src/qlpack.yml
|
||||
else
|
||||
# Restore the original files
|
||||
git checkout "$CURRENT_BRANCH" --force
|
||||
fi
|
||||
|
||||
if [ $DRY_RUN = 1 ]; then
|
||||
echo "Inspect the updated dry-run version files:"
|
||||
ls -l ./src/*.dry-run
|
||||
ls -l ./src/change-notes/*.dry-run
|
||||
else
|
||||
# Add the updated files to the current branch
|
||||
echo "Adding the version changes"
|
||||
mv -f ./src/CHANGELOG.md.dry-run ./src/CHANGELOG.md
|
||||
mv -f ./src/codeql-pack.release.yml.dry-run ./src/codeql-pack.release.yml
|
||||
mv -f ./src/qlpack.yml.dry-run ./src/qlpack.yml
|
||||
mv -f ./src/change-notes/released.md.dry-run "$NEW_CHANGE_NOTES_FILE"
|
||||
git add ./src/CHANGELOG.md
|
||||
git add ./src/codeql-pack.release.yml
|
||||
git add ./src/qlpack.yml
|
||||
git add "$NEW_CHANGE_NOTES_FILE"
|
||||
echo "Added the following updated version files to the current branch:"
|
||||
git status -s
|
||||
echo "To complete the release, please commit these files and merge to the main branch"
|
||||
fi
|
||||
|
||||
echo "Done"
|
||||
@@ -1,183 +0,0 @@
|
||||
private import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.RequestForgeryConfig
|
||||
private import semmle.code.java.security.CommandLineQuery
|
||||
private import semmle.code.java.security.SqlConcatenatedQuery
|
||||
private import semmle.code.java.security.SqlInjectionQuery
|
||||
private import semmle.code.java.security.UrlRedirectQuery
|
||||
private import semmle.code.java.security.TaintedPathQuery
|
||||
private import semmle.code.java.security.SqlInjectionQuery
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
private newtype TSinkModel =
|
||||
MkSinkModel(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
) {
|
||||
ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance,
|
||||
_)
|
||||
}
|
||||
|
||||
class SinkModel extends TSinkModel {
|
||||
string package;
|
||||
string type;
|
||||
boolean subtypes;
|
||||
string name;
|
||||
string signature;
|
||||
string ext;
|
||||
string input;
|
||||
string kind;
|
||||
string provenance;
|
||||
|
||||
SinkModel() {
|
||||
this = MkSinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
|
||||
}
|
||||
|
||||
/** Gets the package for this sink model. */
|
||||
string getPackage() { result = package }
|
||||
|
||||
/** Gets the type for this sink model. */
|
||||
string getType() { result = type }
|
||||
|
||||
/** Gets whether this sink model considers subtypes. */
|
||||
boolean getSubtypes() { result = subtypes }
|
||||
|
||||
/** Gets the name for this sink model. */
|
||||
string getName() { result = name }
|
||||
|
||||
/** Gets the signature for this sink model. */
|
||||
string getSignature() { result = signature }
|
||||
|
||||
/** Gets the input for this sink model. */
|
||||
string getInput() { result = input }
|
||||
|
||||
/** Gets the extension for this sink model. */
|
||||
string getExt() { result = ext }
|
||||
|
||||
/** Gets the kind for this sink model. */
|
||||
string getKind() { result = kind }
|
||||
|
||||
/** Gets the provenance for this sink model. */
|
||||
string getProvenance() { result = provenance }
|
||||
|
||||
/** Gets the number of instances of this sink model. */
|
||||
int getInstanceCount() { result = count(PotentialSinkModelExpr p | p.getSinkModel() = this) }
|
||||
|
||||
/** Gets a string representation of this sink model. */
|
||||
string toString() {
|
||||
result =
|
||||
"SinkModel(" + package + ", " + type + ", " + subtypes + ", " + name + ", " + signature + ", "
|
||||
+ ext + ", " + input + ", " + kind + ", " + provenance + ")"
|
||||
}
|
||||
|
||||
/** Gets a string representation of this sink model as it would appear in a Models-as-Data file. */
|
||||
string getRepr() {
|
||||
result =
|
||||
"\"" + package + "\", \"" + type + "\", " + pyBool(subtypes) + ", \"" + name + "\", \"" +
|
||||
signature + "\", \"" + ext + "\", \"" + input + "\", \"" + kind + "\", \"" + provenance +
|
||||
"\""
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression that may correspond to a sink model. */
|
||||
class PotentialSinkModelExpr extends Expr {
|
||||
/**
|
||||
* Holds if this expression has the given signature. The signature should contain enough
|
||||
* information to determine a corresponding sink model, if one exists.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasSignature(
|
||||
string package, string type, boolean subtypes, string name, string signature, string input
|
||||
) {
|
||||
exists(Call call, Callable callable, int argIdx |
|
||||
call.getCallee().getSourceDeclaration() = callable and
|
||||
(
|
||||
this = call.getArgument(argIdx)
|
||||
or
|
||||
this = call.getQualifier() and argIdx = -1
|
||||
) and
|
||||
(if argIdx = -1 then input = "Argument[this]" else input = "Argument[" + argIdx + "]") and
|
||||
package = callable.getDeclaringType().getPackage().getName() and
|
||||
type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
|
||||
subtypes = considerSubtypes(callable) and
|
||||
name = callable.getName() and
|
||||
signature = ExternalFlow::paramsString(callable)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a sink model that corresponds to this expression. */
|
||||
SinkModel getSinkModel() {
|
||||
this.hasSignature(result.getPackage(), result.getType(), result.getSubtypes(), result.getName(),
|
||||
result.getSignature(), result.getInput())
|
||||
}
|
||||
}
|
||||
|
||||
private string pyBool(boolean b) {
|
||||
b = true and result = "True"
|
||||
or
|
||||
b = false and result = "False"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string representation of the existing sink model at the expression `e`, in the format in
|
||||
* which it would appear in a Models-as-Data file. Also restricts the provenance of the sink model
|
||||
* to be `ai-generated`.
|
||||
*/
|
||||
string getSinkModelRepr(PotentialSinkModelExpr e) {
|
||||
result = e.getSinkModel().getRepr() and
|
||||
e.getSinkModel().getProvenance() = "ai-generated"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of a sink model in a format suitable for appending to an alert
|
||||
* message.
|
||||
*/
|
||||
string getSinkModelQueryRepr(PotentialSinkModelExpr e) {
|
||||
result = "\nsinkModel: " + getSinkModelRepr(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameterised module that takes a dataflow config, and exposes a predicate for counting the
|
||||
* number of AI-generated sink models that appear in alerts for that query.
|
||||
*/
|
||||
private module SinkTallier<DataFlow::ConfigSig Config> {
|
||||
module ConfigFlow = TaintTracking::Global<Config>;
|
||||
|
||||
predicate getSinkModelCount(int c, SinkModel s) {
|
||||
s = any(ConfigFlow::PathNode sink).getNode().asExpr().(PotentialSinkModelExpr).getSinkModel() and
|
||||
c =
|
||||
strictcount(ConfigFlow::PathNode sink |
|
||||
ConfigFlow::flowPath(_, sink) and
|
||||
s = sink.getNode().asExpr().(PotentialSinkModelExpr).getSinkModel()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate sinkModelTallyPerQuery(string queryName, int alertCount, SinkModel sinkModel) {
|
||||
queryName = "java/request-forgery" and
|
||||
SinkTallier<RequestForgeryConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/command-line-injection" and
|
||||
SinkTallier<InputToArgumentToExecFlowConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/concatenated-sql-query" and
|
||||
SinkTallier<UncontrolledStringBuilderSourceFlowConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/ssrf" and
|
||||
SinkTallier<RequestForgeryConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/path-injection" and
|
||||
SinkTallier<TaintedPathConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/unvalidated-url-redirection" and
|
||||
SinkTallier<UrlRedirectConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
or
|
||||
queryName = "java/sql-injection" and
|
||||
SinkTallier<QueryInjectionFlowConfig>::getSinkModelCount(alertCount, sinkModel)
|
||||
}
|
||||
|
||||
predicate sinkModelTally(int alertCount, SinkModel sinkModel) {
|
||||
sinkModelTallyPerQuery(_, _, sinkModel) and
|
||||
alertCount = sum(int c | sinkModelTallyPerQuery(_, c, sinkModel))
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @name Number of alerts per sink model
|
||||
* @description Counts the number of alerts using `ai-generated` sink models.
|
||||
* @kind table
|
||||
* @id java/ml/metrics-count-alerts-per-sink-model
|
||||
* @tags internal automodel metrics
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import AutomodelAlertSinkUtil
|
||||
|
||||
from int alertCount, SinkModel s
|
||||
where sinkModelTally(alertCount, s) and s.getProvenance() = "ai-generated"
|
||||
select alertCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes,
|
||||
s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext,
|
||||
s.getKind() as kind, s.getProvenance() as provenance order by alertCount desc
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @name Number of alerts per sink model and query
|
||||
* @description Counts the number of alerts per query using `ai-generated` sink models.
|
||||
* @kind table
|
||||
* @id java/ml/metrics-count-alerts-per-sink-model-and-query
|
||||
* @tags internal automodel metrics
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import AutomodelAlertSinkUtil
|
||||
|
||||
from string queryId, int alertCount, SinkModel s
|
||||
where
|
||||
sinkModelTallyPerQuery(queryId, alertCount, s) and
|
||||
s.getProvenance() = "ai-generated"
|
||||
select queryId, alertCount, s.getPackage() as package, s.getType() as type,
|
||||
s.getSubtypes() as subtypes, s.getName() as name, s.getSignature() as signature,
|
||||
s.getInput() as input, s.getExt() as ext, s.getKind() as kind, s.getProvenance() as provenance
|
||||
order by queryId, alertCount desc
|
||||
@@ -1,677 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import semmle.code.Location as Location
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
|
||||
private import semmle.code.java.Expr as Expr
|
||||
private import semmle.code.java.security.QueryInjection
|
||||
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
|
||||
private import AutomodelJavaUtil as AutomodelJavaUtil
|
||||
private import semmle.code.java.security.PathSanitizer as PathSanitizer
|
||||
import AutomodelSharedCharacteristics as SharedCharacteristics
|
||||
import AutomodelEndpointTypes as AutomodelEndpointTypes
|
||||
|
||||
newtype JavaRelatedLocationType =
|
||||
CallContext() or
|
||||
MethodDoc() or
|
||||
ClassDoc()
|
||||
|
||||
newtype TApplicationModeEndpoint =
|
||||
TExplicitArgument(Call call, DataFlow::Node arg) {
|
||||
AutomodelJavaUtil::isFromSource(call) and
|
||||
exists(Argument argExpr |
|
||||
arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg()
|
||||
) and
|
||||
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
|
||||
} or
|
||||
TInstanceArgument(Call call, DataFlow::Node arg) {
|
||||
AutomodelJavaUtil::isFromSource(call) and
|
||||
arg = DataFlow::getInstanceArgument(call) and
|
||||
not call instanceof ConstructorCall and
|
||||
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
|
||||
} or
|
||||
TImplicitVarargsArray(Call call, DataFlow::ImplicitVarargsArray arg, int idx) {
|
||||
AutomodelJavaUtil::isFromSource(call) and
|
||||
call = arg.getCall() and
|
||||
idx = call.getCallee().getVaragsParameterIndex() and
|
||||
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
|
||||
} or
|
||||
TMethodReturnValue(MethodCall call) {
|
||||
AutomodelJavaUtil::isFromSource(call) and
|
||||
not AutomodelJavaUtil::isUnexploitableType(call.getType())
|
||||
} or
|
||||
TOverriddenParameter(Parameter p, Method overriddenMethod) {
|
||||
AutomodelJavaUtil::isFromSource(p) and
|
||||
p.getCallable().(Method).overrides(overriddenMethod)
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint is a node that is a candidate for modeling.
|
||||
*/
|
||||
abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint {
|
||||
/**
|
||||
* Gets the callable to be modeled that this endpoint represents.
|
||||
*/
|
||||
abstract Callable getCallable();
|
||||
|
||||
/**
|
||||
* Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
|
||||
*
|
||||
* For endpoints that are source candidates, this will be `none()`.
|
||||
*/
|
||||
abstract string getMaDInput();
|
||||
|
||||
/**
|
||||
* Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
|
||||
*
|
||||
* For endpoints that are sink candidates, this will be `none()`.
|
||||
*/
|
||||
abstract string getMaDOutput();
|
||||
|
||||
abstract Top asTop();
|
||||
|
||||
/**
|
||||
* Converts the endpoint to a node that can be used in a data flow graph.
|
||||
*/
|
||||
abstract DataFlow::Node asNode();
|
||||
|
||||
string getExtensibleType() {
|
||||
if not exists(this.getMaDInput()) and exists(this.getMaDOutput())
|
||||
then result = "sourceModel"
|
||||
else
|
||||
if exists(this.getMaDInput()) and not exists(this.getMaDOutput())
|
||||
then result = "sinkModel"
|
||||
else none() // if both exist, it would be a summaryModel (not yet supported)
|
||||
}
|
||||
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class TCallArgument = TExplicitArgument or TInstanceArgument or TImplicitVarargsArray;
|
||||
|
||||
/**
|
||||
* An endpoint that represents an "argument" to a call in a broad sense, including
|
||||
* both explicit arguments and the instance argument.
|
||||
*/
|
||||
abstract class CallArgument extends ApplicationModeEndpoint, TCallArgument {
|
||||
Call call;
|
||||
DataFlow::Node arg;
|
||||
|
||||
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
|
||||
|
||||
override string getMaDOutput() { none() }
|
||||
|
||||
override DataFlow::Node asNode() { result = arg }
|
||||
|
||||
Call getCall() { result = call }
|
||||
|
||||
override string toString() { result = arg.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that represents an explicit argument to a call.
|
||||
*/
|
||||
class ExplicitArgument extends CallArgument, TExplicitArgument {
|
||||
ExplicitArgument() { this = TExplicitArgument(call, arg) }
|
||||
|
||||
private int getArgIndex() { this.asTop() = call.getArgument(result) }
|
||||
|
||||
override string getMaDInput() { result = "Argument[" + this.getArgIndex() + "]" }
|
||||
|
||||
override Top asTop() { result = arg.asExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that represents the instance argument to a call.
|
||||
*/
|
||||
class InstanceArgument extends CallArgument, TInstanceArgument {
|
||||
InstanceArgument() { this = TInstanceArgument(call, arg) }
|
||||
|
||||
override string getMaDInput() { result = "Argument[this]" }
|
||||
|
||||
override Top asTop() { if exists(arg.asExpr()) then result = arg.asExpr() else result = call }
|
||||
|
||||
override string toString() { result = arg.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that represents an implicit varargs array.
|
||||
* We choose to represent the varargs array as a single endpoint, rather than as multiple endpoints.
|
||||
*
|
||||
* This avoids the problem of having to deal with redundant endpoints downstream.
|
||||
*
|
||||
* In order to be able to distinguish between varargs endpoints and regular endpoints, we export the `isVarargsArray`
|
||||
* meta data field in the extraction queries.
|
||||
*/
|
||||
class ImplicitVarargsArray extends CallArgument, TImplicitVarargsArray {
|
||||
int idx;
|
||||
|
||||
ImplicitVarargsArray() { this = TImplicitVarargsArray(call, arg, idx) }
|
||||
|
||||
override string getMaDInput() { result = "Argument[" + idx + "]" }
|
||||
|
||||
override Top asTop() { result = call }
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that represents a method call. The `ReturnValue` of a method call
|
||||
* may be a source.
|
||||
*/
|
||||
class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue {
|
||||
MethodCall call;
|
||||
|
||||
MethodReturnValue() { this = TMethodReturnValue(call) }
|
||||
|
||||
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
|
||||
|
||||
override string getMaDInput() { none() }
|
||||
|
||||
override string getMaDOutput() { result = "ReturnValue" }
|
||||
|
||||
override Top asTop() { result = call }
|
||||
|
||||
override DataFlow::Node asNode() { result.asExpr() = call }
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that represents a parameter of an overridden method that may be
|
||||
* a source.
|
||||
*/
|
||||
class OverriddenParameter extends ApplicationModeEndpoint, TOverriddenParameter {
|
||||
Parameter p;
|
||||
Method overriddenMethod;
|
||||
|
||||
OverriddenParameter() { this = TOverriddenParameter(p, overriddenMethod) }
|
||||
|
||||
override Callable getCallable() {
|
||||
// NB: we're returning the overridden callable here. This means that the
|
||||
// candidate model will be about the overridden method, not the overriding
|
||||
// method. This is a more general model, that also applies to other
|
||||
// subclasses of the overridden class.
|
||||
result = overriddenMethod.getSourceDeclaration()
|
||||
}
|
||||
|
||||
private int getArgIndex() { p.getCallable().getParameter(result) = p }
|
||||
|
||||
override string getMaDInput() { none() }
|
||||
|
||||
override string getMaDOutput() { result = "Parameter[" + this.getArgIndex() + "]" }
|
||||
|
||||
override Top asTop() { result = p }
|
||||
|
||||
override DataFlow::Node asNode() { result.(DataFlow::ParameterNode).asParameter() = p }
|
||||
|
||||
override string toString() { result = p.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidates implementation.
|
||||
*
|
||||
* Some important notes:
|
||||
* - This mode is using arguments as endpoints.
|
||||
* - We use the `CallContext` (the surrounding call expression) as related location.
|
||||
*/
|
||||
module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
||||
// for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
|
||||
class Endpoint = ApplicationModeEndpoint;
|
||||
|
||||
class EndpointType = AutomodelEndpointTypes::EndpointType;
|
||||
|
||||
class SinkType = AutomodelEndpointTypes::SinkType;
|
||||
|
||||
class SourceType = AutomodelEndpointTypes::SourceType;
|
||||
|
||||
class RelatedLocation = Location::Top;
|
||||
|
||||
class RelatedLocationType = JavaRelatedLocationType;
|
||||
|
||||
// Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
|
||||
predicate isSanitizer(Endpoint e, EndpointType t) {
|
||||
exists(t) and
|
||||
AutomodelJavaUtil::isUnexploitableType([
|
||||
// for most endpoints, we can get the type from the node
|
||||
e.asNode().getType(),
|
||||
// but not for calls to void methods, where we need to go via the AST
|
||||
e.asTop().(Expr).getType()
|
||||
])
|
||||
or
|
||||
t instanceof AutomodelEndpointTypes::PathInjectionSinkType and
|
||||
e.asNode() instanceof PathSanitizer::PathInjectionSanitizer
|
||||
}
|
||||
|
||||
RelatedLocation asLocation(Endpoint e) { result = e.asTop() }
|
||||
|
||||
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
|
||||
|
||||
predicate isSink(Endpoint e, string kind, string provenance) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input
|
||||
|
|
||||
sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
|
||||
ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
|
||||
provenance, _)
|
||||
)
|
||||
or
|
||||
isCustomSink(e, kind) and provenance = "custom-sink"
|
||||
}
|
||||
|
||||
predicate isSource(Endpoint e, string kind, string provenance) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output
|
||||
|
|
||||
sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
|
||||
ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
|
||||
provenance, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isNeutral(Endpoint e) {
|
||||
exists(string package, string type, string name, string signature, string endpointType |
|
||||
sinkSpec(e, package, type, _, name, signature, _, _) and
|
||||
endpointType = "sink"
|
||||
or
|
||||
sourceSpec(e, package, type, _, name, signature, _, _) and
|
||||
endpointType = "source"
|
||||
|
|
||||
ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the endpoint concerns a callable with the given package, type, name and signature.
|
||||
*
|
||||
* If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and
|
||||
* all its overrides are considered.
|
||||
*/
|
||||
additional predicate endpointCallable(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
exists(Callable c |
|
||||
c = e.getCallable() and subtypes in [true, false]
|
||||
or
|
||||
e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true
|
||||
|
|
||||
c.hasQualifiedName(package, type, name) and
|
||||
signature = ExternalFlow::paramsString(c)
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate sinkSpec(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input
|
||||
) {
|
||||
endpointCallable(e, package, type, subtypes, name, signature) and
|
||||
ext = "" and
|
||||
input = e.getMaDInput()
|
||||
}
|
||||
|
||||
additional predicate sourceSpec(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output
|
||||
) {
|
||||
endpointCallable(e, package, type, subtypes, name, signature) and
|
||||
ext = "" and
|
||||
output = e.getMaDOutput()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the related location for the given endpoint.
|
||||
*
|
||||
* The only related location we model is the the call expression surrounding to
|
||||
* which the endpoint is either argument or qualifier (known as the call context).
|
||||
*/
|
||||
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
|
||||
type = CallContext() and
|
||||
result = e.(CallArgument).getCall()
|
||||
or
|
||||
type = MethodDoc() and
|
||||
result = e.getCallable().(Documentable).getJavadoc()
|
||||
or
|
||||
type = ClassDoc() and
|
||||
result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains endpoints that are defined in QL code rather than as a MaD model. Ideally this predicate
|
||||
* should be empty.
|
||||
*/
|
||||
private predicate isCustomSink(Endpoint e, string kind) {
|
||||
e.asNode() instanceof QueryInjectionSink and kind = "sql"
|
||||
}
|
||||
|
||||
module CharacteristicsImpl =
|
||||
SharedCharacteristics::SharedCharacteristics<ApplicationCandidatesImpl>;
|
||||
|
||||
class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
|
||||
|
||||
class Endpoint = ApplicationCandidatesImpl::Endpoint;
|
||||
|
||||
/*
|
||||
* Predicates that are used to surface prompt examples and candidates for classification with an ML model.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A MetadataExtractor that extracts metadata for application mode.
|
||||
*/
|
||||
class ApplicationModeMetadataExtractor extends string {
|
||||
ApplicationModeMetadataExtractor() { this = "ApplicationModeMetadataExtractor" }
|
||||
|
||||
predicate hasMetadata(
|
||||
Endpoint e, string package, string type, string subtypes, string name, string signature,
|
||||
string input, string output, string isVarargsArray, string alreadyAiModeled,
|
||||
string extensibleType
|
||||
) {
|
||||
exists(Callable callable | e.getCallable() = callable |
|
||||
(if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
|
||||
(if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
|
||||
package = callable.getDeclaringType().getPackage().getName() and
|
||||
// we're using the erased types because the MaD convention is to not specify type parameters.
|
||||
// Whether something is or isn't a sink doesn't usually depend on the type parameters.
|
||||
type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
|
||||
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
|
||||
name = callable.getName() and
|
||||
signature = ExternalFlow::paramsString(callable) and
|
||||
(
|
||||
if e instanceof ImplicitVarargsArray
|
||||
then isVarargsArray = "true"
|
||||
else isVarargsArray = "false"
|
||||
) and
|
||||
extensibleType = e.getExtensibleType()
|
||||
) and
|
||||
(
|
||||
not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
|
||||
or
|
||||
CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isCandidate(
|
||||
Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
|
||||
string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
|
||||
) {
|
||||
CharacteristicsImpl::isCandidate(endpoint, _) and
|
||||
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
|
||||
u.appliesToEndpoint(endpoint)
|
||||
) and
|
||||
any(ApplicationModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargs,
|
||||
alreadyAiModeled, extensibleType) and
|
||||
// If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a
|
||||
// candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's
|
||||
// already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We
|
||||
// assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink
|
||||
// types, and we don't need to reexamine it.
|
||||
alreadyAiModeled.matches(["", "%ai-%"]) and
|
||||
AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` is a negative example for the `extensibleType`
|
||||
* because of the `characteristic`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isNegativeExample(
|
||||
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
|
||||
string type, string subtypes, string name, string signature, string input, string output,
|
||||
string isVarargsArray, string extensibleType
|
||||
) {
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
// the node is known not to be an endpoint of any appropriate type
|
||||
forall(AutomodelEndpointTypes::EndpointType tp |
|
||||
tp = CharacteristicsImpl::getAPotentialType(endpoint)
|
||||
|
|
||||
characteristic.hasImplications(tp, false, _)
|
||||
) and
|
||||
// the lowest confidence across all endpoint types should be at least highConfidence
|
||||
confidence =
|
||||
min(float c |
|
||||
characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
|
||||
) and
|
||||
confidence >= SharedCharacteristics::highConfidence() and
|
||||
any(ApplicationModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
|
||||
isVarargsArray, _, extensibleType) and
|
||||
// It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
|
||||
// as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
|
||||
not exists(EndpointCharacteristic characteristic2, float confidence2 |
|
||||
characteristic2 != characteristic
|
||||
|
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
confidence2 >= SharedCharacteristics::maximalConfidence() and
|
||||
characteristic2
|
||||
.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` is a positive example for the `endpointType`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isPositiveExample(
|
||||
Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
|
||||
string signature, string input, string output, string isVarargsArray, string extensibleType
|
||||
) {
|
||||
any(ApplicationModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
|
||||
isVarargsArray, _, extensibleType) and
|
||||
CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) and
|
||||
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
|
||||
}
|
||||
|
||||
/*
|
||||
* EndpointCharacteristic classes that are specific to Automodel for Java.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks.
|
||||
*
|
||||
* A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
|
||||
* type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
|
||||
* the dangerous/interesting thing, so we want the latter to be modeled as the sink.
|
||||
*
|
||||
* TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
|
||||
*/
|
||||
private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
|
||||
UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
e.getCallable().getName().matches("is%") and
|
||||
e.getCallable().getReturnType() instanceof BooleanType and
|
||||
not ApplicationCandidatesImpl::isSink(e, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
|
||||
* considered sinks.
|
||||
*
|
||||
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
|
||||
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
|
||||
* dangerous/interesting thing, so we want the latter to be modeled as the sink.
|
||||
*/
|
||||
private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
|
||||
UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
exists(Callable callable | callable = e.getCallable() |
|
||||
callable.getName().toLowerCase() = ["exists", "notexists"] and
|
||||
callable.getReturnType() instanceof BooleanType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
|
||||
* and its return value should not be considered a source.
|
||||
*/
|
||||
private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
|
||||
{
|
||||
ExceptionCharacteristic() { this = "argument/result of exception-related method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
|
||||
(
|
||||
e.getExtensibleType() = "sinkModel" and
|
||||
not ApplicationCandidatesImpl::isSink(e, _, _)
|
||||
or
|
||||
e.getExtensibleType() = "sourceModel" and
|
||||
not ApplicationCandidatesImpl::isSource(e, _, _) and
|
||||
e.getMaDOutput() = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that an endpoint is a MaD taint step. MaD modeled taint steps are global,
|
||||
* so they are not sinks for any query. Non-MaD taint steps might be specific to a particular query, so we don't
|
||||
* filter those out.
|
||||
*/
|
||||
private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
|
||||
IsMaDTaintStepCharacteristic() { this = "taint step" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summarySetterStep(e.asNode(), _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method that's known locally will not be considered as a candidate to model.
|
||||
*
|
||||
* The reason is that we would expect data/taint flow into the method implementation to uncover
|
||||
* any sinks that are present there.
|
||||
*/
|
||||
private class LocalCall extends CharacteristicsImpl::UninterestingToModelCharacteristic {
|
||||
LocalCall() { this = "local call" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
e.(CallArgument).getCallable().fromSource()
|
||||
or
|
||||
e.(MethodReturnValue).getCallable().fromSource()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A characteristic that marks endpoints as uninteresting to model, according to the Java ModelExclusions module.
|
||||
*/
|
||||
private class ExcludedFromModeling extends CharacteristicsImpl::UninterestingToModelCharacteristic {
|
||||
ExcludedFromModeling() { this = "excluded from modeling" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
ModelExclusions::isUninterestingForModels(e.getCallable())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that filters out non-public methods. Non-public methods are not interesting to include in
|
||||
* the standard Java modeling, because they cannot be called from outside the package.
|
||||
*/
|
||||
private class NonPublicMethodCharacteristic extends CharacteristicsImpl::UninterestingToModelCharacteristic
|
||||
{
|
||||
NonPublicMethodCharacteristic() { this = "non-public method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
exists(Callable c | c = e.getCallable() | not c.isPublic())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that an endpoint is a non-sink argument to a method whose sinks have already
|
||||
* been modeled _manually_. This is restricted to manual sinks only, because only during the manual process do we have
|
||||
* the expectation that all sinks present in a method have been considered.
|
||||
*
|
||||
* WARNING: These endpoints should not be used as negative samples for training, because some sinks may have been missed
|
||||
* when the method was modeled. Specifically, as we start using ATM to merge in new declarations, we can be less sure
|
||||
* that a method with one argument modeled as a MaD sink has also had its remaining arguments manually reviewed. The
|
||||
* ML model might have predicted argument 0 of some method to be a sink but not argument 1, when in fact argument 1 is
|
||||
* also a sink.
|
||||
*/
|
||||
private class OtherArgumentToModeledMethodCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic
|
||||
{
|
||||
OtherArgumentToModeledMethodCharacteristic() {
|
||||
this = "other argument to a method that has already been modeled manually"
|
||||
}
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
not ApplicationCandidatesImpl::isSink(e, _, _) and
|
||||
exists(CallArgument otherSink |
|
||||
ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and
|
||||
e.(CallArgument).getCall() = otherSink.getCall() and
|
||||
e != otherSink
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type of the given expression is annotated with `@FunctionalInterface`.
|
||||
*/
|
||||
predicate hasFunctionalInterfaceType(Expr e) {
|
||||
exists(RefType tp | tp = e.getType().getErasure() |
|
||||
tp.getAnAssociatedAnnotation().getType().hasQualifiedName("java.lang", "FunctionalInterface")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A characteristic that marks functional expression as likely not sinks.
|
||||
*
|
||||
* These expressions may well _contain_ sinks, but rarely are sinks themselves.
|
||||
*/
|
||||
private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
|
||||
FunctionValueCharacteristic() { this = "function value" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
exists(Expr expr | expr = e.asNode().asExpr() |
|
||||
expr instanceof FunctionalExpr or hasFunctionalInterfaceType(expr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that an endpoint is not a `to` node for any known taint step. Such a node
|
||||
* cannot be tainted, because taint can't flow into it.
|
||||
*
|
||||
* WARNING: These endpoints should not be used as negative samples for training, because they may include sinks for
|
||||
* which our taint tracking modeling is incomplete.
|
||||
*/
|
||||
private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic
|
||||
{
|
||||
CannotBeTaintedCharacteristic() { this = "cannot be tainted" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) { not this.isKnownOutNodeForStep(e) }
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is known as the predecessor in a modeled flow step.
|
||||
*/
|
||||
private predicate isKnownOutNodeForStep(Endpoint e) {
|
||||
e.asNode().asExpr() instanceof Call or // we just assume flow in that case
|
||||
TaintTracking::localTaintStep(_, e.asNode()) or
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(_, e.asNode(), _) or
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(_, e.asNode(), _) or
|
||||
FlowSummaryImpl::Private::Steps::summaryGetterStep(_, _, e.asNode(), _) or
|
||||
FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e.asNode(), _)
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for
|
||||
* classification with an ML model.
|
||||
*
|
||||
* Note: This query does not actually classify the endpoints using the model.
|
||||
*
|
||||
* @name Automodel candidates (application mode)
|
||||
* @description A query to extract automodel candidates in application mode.
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-application-candidates
|
||||
* @tags internal extract automodel application-mode candidates
|
||||
*/
|
||||
|
||||
import java
|
||||
private import AutomodelApplicationModeCharacteristics
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
/**
|
||||
* Gets a sample of endpoints (of at most `limit` samples) with the given method signature.
|
||||
*
|
||||
* The main purpose of this helper predicate is to avoid selecting too many candidates, as this may
|
||||
* cause the SARIF file to exceed the maximum size limit.
|
||||
*/
|
||||
bindingset[limit]
|
||||
private Endpoint getSampleForSignature(
|
||||
int limit, string package, string type, string subtypes, string name, string signature,
|
||||
string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
|
||||
) {
|
||||
exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
|
||||
num_endpoints =
|
||||
count(Endpoint e |
|
||||
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
|
||||
alreadyAiModeled, extensibleType)
|
||||
)
|
||||
|
|
||||
result =
|
||||
rank[n](Endpoint e, Location loc |
|
||||
loc = e.asTop().getLocation() and
|
||||
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
|
||||
alreadyAiModeled, extensibleType)
|
||||
|
|
||||
e
|
||||
order by
|
||||
loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(),
|
||||
loc.getEndLine(), loc.getEndColumn()
|
||||
) and
|
||||
// To avoid selecting samples that are too close together (as the ranking above goes by file
|
||||
// path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By
|
||||
// default this would always include the first sample, so we add a random-chosen prime offset
|
||||
// to the first sample index, and reduce modulo the number of endpoints.
|
||||
// Finally, we add 1 to the result, as ranking results in a 1-indexed relation.
|
||||
n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
|
||||
DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output,
|
||||
DollarAtString isVarargsArray, DollarAtString alreadyAiModeled, DollarAtString extensibleType
|
||||
where
|
||||
isCandidate(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray,
|
||||
extensibleType, alreadyAiModeled) and
|
||||
endpoint =
|
||||
getSampleForSignature(9, package, type, subtypes, name, signature, input, output,
|
||||
isVarargsArray, extensibleType, alreadyAiModeled)
|
||||
select endpoint.asNode(),
|
||||
"Related locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", // method name
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
isVarargsArray, "isVarargsArray", //
|
||||
alreadyAiModeled, "alreadyAiModeled", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt.
|
||||
*
|
||||
* @name Negative examples (application mode)
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-application-negative-examples
|
||||
* @tags internal extract automodel application-mode negative examples
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import AutomodelApplicationModeCharacteristics
|
||||
private import AutomodelEndpointTypes
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
/**
|
||||
* Gets a sample of endpoints (of at most `limit` samples) for which the given characteristic applies.
|
||||
*
|
||||
* The main purpose of this helper predicate is to avoid selecting too many samples, as this may
|
||||
* cause the SARIF file to exceed the maximum size limit.
|
||||
*/
|
||||
bindingset[limit]
|
||||
Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) {
|
||||
exists(int n, int num_endpoints | num_endpoints = count(Endpoint e | c.appliesToEndpoint(e)) |
|
||||
result =
|
||||
rank[n](Endpoint e, Location loc |
|
||||
loc = e.asTop().getLocation() and c.appliesToEndpoint(e)
|
||||
|
|
||||
e
|
||||
order by
|
||||
loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(),
|
||||
loc.getEndLine(), loc.getEndColumn()
|
||||
) and
|
||||
// To avoid selecting samples that are too close together (as the ranking above goes by file
|
||||
// path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By
|
||||
// default this would always include the first sample, so we add a random-chosen prime offset
|
||||
// to the first sample index, and reduce modulo the number of endpoints.
|
||||
// Finally, we add 1 to the result, as ranking results in a 1-indexed relation.
|
||||
n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
|
||||
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
|
||||
DollarAtString signature, DollarAtString input, DollarAtString output,
|
||||
DollarAtString isVarargsArray, DollarAtString extensibleType
|
||||
where
|
||||
endpoint = getSampleForCharacteristic(characteristic, 100) and
|
||||
isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
|
||||
input, output, isVarargsArray, extensibleType) and
|
||||
message = characteristic
|
||||
select endpoint.asNode(),
|
||||
message + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", //
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
isVarargsArray, "isVarargsArray", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt.
|
||||
*
|
||||
* @name Positive examples (application mode)
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-application-positive-examples
|
||||
* @tags internal extract automodel application-mode positive examples
|
||||
*/
|
||||
|
||||
private import AutomodelApplicationModeCharacteristics
|
||||
private import AutomodelEndpointTypes
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
from
|
||||
Endpoint endpoint, EndpointType endpointType, ApplicationModeMetadataExtractor meta,
|
||||
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
|
||||
DollarAtString signature, DollarAtString input, DollarAtString output,
|
||||
DollarAtString isVarargsArray, DollarAtString extensibleType
|
||||
where
|
||||
isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
|
||||
isVarargsArray, extensibleType)
|
||||
select endpoint.asNode(),
|
||||
endpointType + "\nrelated locations: $@, $@, $@." +
|
||||
"\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", //
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
isVarargsArray, "isVarargsArray", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,5 +0,0 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-automodel-queries
|
||||
extensible: automodelCandidateFilter
|
||||
data: []
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @name Number of instances of each sink model
|
||||
* @description Counts the number of instances of `ai-generated` sink models.
|
||||
* @kind table
|
||||
* @id java/ml/metrics-count-instances-per-sink-model
|
||||
* @tags internal automodel metrics
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import AutomodelAlertSinkUtil
|
||||
|
||||
from int instanceCount, SinkModel s
|
||||
where
|
||||
instanceCount = s.getInstanceCount() and
|
||||
instanceCount > 0 and
|
||||
s.getProvenance() = "ai-generated"
|
||||
select instanceCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes,
|
||||
s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext,
|
||||
s.getKind() as kind, s.getProvenance() as provenance order by instanceCount desc
|
||||
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* Defines the set of classes that endpoint scoring models can predict. Endpoint scoring models must
|
||||
* only predict classes defined within this file. This file is the source of truth for the integer
|
||||
* representation of each of these classes.
|
||||
*/
|
||||
|
||||
/** A class that can be predicted by a classifier. */
|
||||
abstract class EndpointType extends string {
|
||||
/**
|
||||
* Holds when the string matches the name of the sink / source type.
|
||||
*/
|
||||
bindingset[this]
|
||||
EndpointType() { any() }
|
||||
|
||||
/**
|
||||
* Gets the name of the sink/source kind for this endpoint type as used in models-as-data.
|
||||
*
|
||||
* See https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#LL353C11-L357C31
|
||||
* for sink types, and https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#L365
|
||||
* for source types.
|
||||
*/
|
||||
final string getKind() { result = this }
|
||||
}
|
||||
|
||||
/** A class for sink types that can be predicted by a classifier. */
|
||||
abstract class SinkType extends EndpointType {
|
||||
bindingset[this]
|
||||
SinkType() { any() }
|
||||
}
|
||||
|
||||
/** A sink relevant to the SQL injection query */
|
||||
class SqlInjectionSinkType extends SinkType {
|
||||
SqlInjectionSinkType() { this = "sql-injection" }
|
||||
}
|
||||
|
||||
/** A sink relevant to the tainted path injection query. */
|
||||
class PathInjectionSinkType extends SinkType {
|
||||
PathInjectionSinkType() { this = "path-injection" }
|
||||
}
|
||||
|
||||
/** A sink relevant to the SSRF query. */
|
||||
class RequestForgerySinkType extends SinkType {
|
||||
RequestForgerySinkType() { this = "request-forgery" }
|
||||
}
|
||||
|
||||
/** A sink relevant to the command injection query. */
|
||||
class CommandInjectionSinkType extends SinkType {
|
||||
CommandInjectionSinkType() { this = "command-injection" }
|
||||
}
|
||||
|
||||
/** A sink relevant to file storage. */
|
||||
class FileContentStoreSinkType extends SinkType {
|
||||
FileContentStoreSinkType() { this = "file-content-store" }
|
||||
}
|
||||
|
||||
/** A sink relevant to HTML injection. */
|
||||
class HtmlInjectionSinkType extends SinkType {
|
||||
HtmlInjectionSinkType() { this = "html-injection" }
|
||||
}
|
||||
|
||||
/** A sink relevant to LDAP injection. */
|
||||
class LdapInjectionSinkType extends SinkType {
|
||||
LdapInjectionSinkType() { this = "ldap-injection" }
|
||||
}
|
||||
|
||||
/** A sink relevant to URL redirection. */
|
||||
class UrlRedirectionSinkType extends SinkType {
|
||||
UrlRedirectionSinkType() { this = "url-redirection" }
|
||||
}
|
||||
|
||||
/** A class for source types that can be predicted by a classifier. */
|
||||
abstract class SourceType extends EndpointType {
|
||||
bindingset[this]
|
||||
SourceType() { any() }
|
||||
}
|
||||
|
||||
/** A source of remote data. */
|
||||
class RemoteSourceType extends SourceType {
|
||||
RemoteSourceType() { this = "remote" }
|
||||
}
|
||||
@@ -1,507 +0,0 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import semmle.code.Location as Location
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
|
||||
private import semmle.code.java.Expr as Expr
|
||||
private import semmle.code.java.security.QueryInjection
|
||||
private import semmle.code.java.security.RequestForgery
|
||||
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
|
||||
private import AutomodelJavaUtil as AutomodelJavaUtil
|
||||
import AutomodelSharedCharacteristics as SharedCharacteristics
|
||||
import AutomodelEndpointTypes as AutomodelEndpointTypes
|
||||
|
||||
newtype JavaRelatedLocationType =
|
||||
MethodDoc() or
|
||||
ClassDoc()
|
||||
|
||||
newtype TFrameworkModeEndpoint =
|
||||
TExplicitParameter(Parameter p) {
|
||||
AutomodelJavaUtil::isFromSource(p) and
|
||||
not AutomodelJavaUtil::isUnexploitableType(p.getType())
|
||||
} or
|
||||
TQualifier(Callable c) { AutomodelJavaUtil::isFromSource(c) and not c instanceof Constructor } or
|
||||
TReturnValue(Callable c) {
|
||||
AutomodelJavaUtil::isFromSource(c) and
|
||||
c instanceof Constructor
|
||||
or
|
||||
AutomodelJavaUtil::isFromSource(c) and
|
||||
c instanceof Method and
|
||||
not AutomodelJavaUtil::isUnexploitableType(c.getReturnType())
|
||||
} or
|
||||
TOverridableParameter(Method m, Parameter p) {
|
||||
AutomodelJavaUtil::isFromSource(p) and
|
||||
not AutomodelJavaUtil::isUnexploitableType(p.getType()) and
|
||||
p.getCallable() = m and
|
||||
m instanceof ModelExclusions::ModelApi and
|
||||
AutomodelJavaUtil::isOverridable(m)
|
||||
} or
|
||||
TOverridableQualifier(Method m) {
|
||||
AutomodelJavaUtil::isFromSource(m) and
|
||||
m instanceof ModelExclusions::ModelApi and
|
||||
AutomodelJavaUtil::isOverridable(m)
|
||||
}
|
||||
|
||||
/**
|
||||
* A framework mode endpoint.
|
||||
*/
|
||||
abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
|
||||
/**
|
||||
* Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
|
||||
*
|
||||
* For endpoints that are source candidates, this will be `none()`.
|
||||
*/
|
||||
abstract string getMaDInput();
|
||||
|
||||
/**
|
||||
* Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
|
||||
*
|
||||
* For endpoints that are sink candidates, this will be `none()`.
|
||||
*/
|
||||
abstract string getMaDOutput();
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter of the endpoint.
|
||||
*/
|
||||
abstract string getParamName();
|
||||
|
||||
/**
|
||||
* Returns the callable that contains the endpoint.
|
||||
*/
|
||||
abstract Callable getCallable();
|
||||
|
||||
abstract Top asTop();
|
||||
|
||||
abstract string getExtensibleType();
|
||||
|
||||
string toString() { result = this.asTop().toString() }
|
||||
|
||||
Location getLocation() { result = this.asTop().getLocation() }
|
||||
}
|
||||
|
||||
class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParameter {
|
||||
Parameter param;
|
||||
|
||||
ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() }
|
||||
|
||||
override string getMaDInput() { result = "Argument[" + param.getPosition() + "]" }
|
||||
|
||||
override string getMaDOutput() { none() }
|
||||
|
||||
override string getParamName() { result = param.getName() }
|
||||
|
||||
override Callable getCallable() { result = param.getCallable() }
|
||||
|
||||
override Top asTop() { result = param }
|
||||
|
||||
override string getExtensibleType() { result = "sinkModel" }
|
||||
}
|
||||
|
||||
class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
|
||||
Callable callable;
|
||||
|
||||
QualifierEndpoint() {
|
||||
this = TQualifier(callable) and not callable.isStatic() and callable.fromSource()
|
||||
}
|
||||
|
||||
override string getMaDInput() { result = "Argument[this]" }
|
||||
|
||||
override string getMaDOutput() { none() }
|
||||
|
||||
override string getParamName() { result = "this" }
|
||||
|
||||
override Callable getCallable() { result = callable }
|
||||
|
||||
override Top asTop() { result = callable }
|
||||
|
||||
override string getExtensibleType() { result = "sinkModel" }
|
||||
}
|
||||
|
||||
class ReturnValue extends FrameworkModeEndpoint, TReturnValue {
|
||||
Callable callable;
|
||||
|
||||
ReturnValue() { this = TReturnValue(callable) and callable.fromSource() }
|
||||
|
||||
override string getMaDInput() { none() }
|
||||
|
||||
override string getMaDOutput() { result = "ReturnValue" }
|
||||
|
||||
override string getParamName() { none() }
|
||||
|
||||
override Callable getCallable() { result = callable }
|
||||
|
||||
override Top asTop() { result = callable }
|
||||
|
||||
override string getExtensibleType() { result = "sourceModel" }
|
||||
}
|
||||
|
||||
class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter {
|
||||
Method method;
|
||||
Parameter param;
|
||||
|
||||
OverridableParameter() { this = TOverridableParameter(method, param) }
|
||||
|
||||
override string getMaDInput() { none() }
|
||||
|
||||
override string getMaDOutput() { result = "Parameter[" + param.getPosition() + "]" }
|
||||
|
||||
override string getParamName() { result = param.getName() }
|
||||
|
||||
override Callable getCallable() { result = method }
|
||||
|
||||
override Top asTop() { result = param }
|
||||
|
||||
override string getExtensibleType() { result = "sourceModel" }
|
||||
}
|
||||
|
||||
class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier {
|
||||
Method m;
|
||||
|
||||
OverridableQualifier() { this = TOverridableQualifier(m) }
|
||||
|
||||
override string getMaDInput() { none() }
|
||||
|
||||
override string getMaDOutput() { result = "Parameter[this]" }
|
||||
|
||||
override string getParamName() { result = "this" }
|
||||
|
||||
override Callable getCallable() { result = m }
|
||||
|
||||
override Top asTop() { result = m }
|
||||
|
||||
override string getExtensibleType() { result = "sourceModel" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidates implementation for framework mode.
|
||||
*
|
||||
* Some important notes:
|
||||
* - This mode is using parameters as endpoints.
|
||||
* - Sink- and neutral-information is being used from MaD models.
|
||||
* - When available, we use method- and class-java-docs as related locations.
|
||||
*/
|
||||
module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
||||
// for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
|
||||
class Endpoint = FrameworkModeEndpoint;
|
||||
|
||||
class EndpointType = AutomodelEndpointTypes::EndpointType;
|
||||
|
||||
class SinkType = AutomodelEndpointTypes::SinkType;
|
||||
|
||||
class SourceType = AutomodelEndpointTypes::SourceType;
|
||||
|
||||
class RelatedLocation = Location::Top;
|
||||
|
||||
class RelatedLocationType = JavaRelatedLocationType;
|
||||
|
||||
// Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
|
||||
predicate isSanitizer(Endpoint e, EndpointType t) { none() }
|
||||
|
||||
RelatedLocation asLocation(Endpoint e) { result = e.asTop() }
|
||||
|
||||
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
|
||||
|
||||
predicate isSink(Endpoint e, string kind, string provenance) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input
|
||||
|
|
||||
sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
|
||||
ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
|
||||
provenance, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSource(Endpoint e, string kind, string provenance) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output
|
||||
|
|
||||
sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
|
||||
ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
|
||||
provenance, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isNeutral(Endpoint e) {
|
||||
exists(string package, string type, string name, string signature, string endpointType |
|
||||
sinkSpec(e, package, type, _, name, signature, _, _) and
|
||||
endpointType = "sink"
|
||||
or
|
||||
sourceSpec(e, package, type, _, name, signature, _, _) and
|
||||
endpointType = "source"
|
||||
|
|
||||
ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the endpoint concerns a callable with the given package, type, name and signature.
|
||||
*
|
||||
* If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and
|
||||
* all its overrides are considered.
|
||||
*/
|
||||
additional predicate endpointCallable(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
exists(Callable c |
|
||||
c = e.getCallable() and subtypes in [true, false]
|
||||
or
|
||||
e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true
|
||||
|
|
||||
c.hasQualifiedName(package, type, name) and
|
||||
signature = ExternalFlow::paramsString(c)
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate sinkSpec(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input
|
||||
) {
|
||||
endpointCallable(e, package, type, subtypes, name, signature) and
|
||||
ext = "" and
|
||||
input = e.getMaDInput()
|
||||
}
|
||||
|
||||
additional predicate sourceSpec(
|
||||
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output
|
||||
) {
|
||||
endpointCallable(e, package, type, subtypes, name, signature) and
|
||||
ext = "" and
|
||||
output = e.getMaDOutput()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the related location for the given endpoint.
|
||||
*
|
||||
* Related locations can be JavaDoc comments of the class or the method.
|
||||
*/
|
||||
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
|
||||
type = MethodDoc() and
|
||||
result = e.getCallable().(Documentable).getJavadoc()
|
||||
or
|
||||
type = ClassDoc() and
|
||||
result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
|
||||
}
|
||||
}
|
||||
|
||||
module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics<FrameworkCandidatesImpl>;
|
||||
|
||||
class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
|
||||
|
||||
class Endpoint = FrameworkCandidatesImpl::Endpoint;
|
||||
|
||||
/*
|
||||
* Predicates that are used to surface prompt examples and candidates for classification with an ML model.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A MetadataExtractor that extracts metadata for framework mode.
|
||||
*/
|
||||
class FrameworkModeMetadataExtractor extends string {
|
||||
FrameworkModeMetadataExtractor() { this = "FrameworkModeMetadataExtractor" }
|
||||
|
||||
predicate hasMetadata(
|
||||
Endpoint e, string package, string type, string subtypes, string name, string signature,
|
||||
string input, string output, string parameterName, string alreadyAiModeled,
|
||||
string extensibleType
|
||||
) {
|
||||
exists(Callable callable | e.getCallable() = callable |
|
||||
(if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
|
||||
(if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
|
||||
package = callable.getDeclaringType().getPackage().getName() and
|
||||
// we're using the erased types because the MaD convention is to not specify type parameters.
|
||||
// Whether something is or isn't a sink doesn't usually depend on the type parameters.
|
||||
type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and
|
||||
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
|
||||
name = callable.getName() and
|
||||
signature = ExternalFlow::paramsString(callable) and
|
||||
(if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and
|
||||
e.getExtensibleType() = extensibleType
|
||||
) and
|
||||
(
|
||||
not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
|
||||
or
|
||||
CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isCandidate(
|
||||
Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
|
||||
string input, string output, string parameterName, string extensibleType, string alreadyAiModeled
|
||||
) {
|
||||
CharacteristicsImpl::isCandidate(endpoint, _) and
|
||||
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
|
||||
u.appliesToEndpoint(endpoint)
|
||||
) and
|
||||
any(FrameworkModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
|
||||
alreadyAiModeled, extensibleType) and
|
||||
// If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a
|
||||
// candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's
|
||||
// already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We
|
||||
// assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink
|
||||
// types, and we don't need to reexamine it.
|
||||
alreadyAiModeled.matches(["", "%ai-%"]) and
|
||||
AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` is a negative example for the `extensibleType`
|
||||
* because of the `characteristic`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isNegativeExample(
|
||||
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
|
||||
string type, string subtypes, string name, string signature, string input, string output,
|
||||
string parameterName, string extensibleType
|
||||
) {
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
// the node is known not to be an endpoint of any appropriate type
|
||||
forall(AutomodelEndpointTypes::EndpointType tp |
|
||||
tp = CharacteristicsImpl::getAPotentialType(endpoint)
|
||||
|
|
||||
characteristic.hasImplications(tp, false, _)
|
||||
) and
|
||||
// the lowest confidence across all endpoint types should be at least highConfidence
|
||||
confidence =
|
||||
min(float c |
|
||||
characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
|
||||
) and
|
||||
confidence >= SharedCharacteristics::highConfidence() and
|
||||
any(FrameworkModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
|
||||
_, extensibleType) and
|
||||
// It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
|
||||
// as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
|
||||
not exists(EndpointCharacteristic characteristic2, float confidence2 |
|
||||
characteristic2 != characteristic
|
||||
|
|
||||
characteristic2.appliesToEndpoint(endpoint) and
|
||||
confidence2 >= SharedCharacteristics::maximalConfidence() and
|
||||
characteristic2
|
||||
.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` is a positive example for the `endpointType`.
|
||||
*
|
||||
* The other parameters record various other properties of interest.
|
||||
*/
|
||||
predicate isPositiveExample(
|
||||
Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
|
||||
string signature, string input, string output, string parameterName, string extensibleType
|
||||
) {
|
||||
any(FrameworkModeMetadataExtractor meta)
|
||||
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
|
||||
_, extensibleType) and
|
||||
CharacteristicsImpl::isKnownAs(endpoint, endpointType, _)
|
||||
}
|
||||
|
||||
/*
|
||||
* EndpointCharacteristic classes that are specific to Automodel for Java.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks,
|
||||
* and its return value should not be considered a source.
|
||||
*
|
||||
* A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
|
||||
* type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
|
||||
* the dangerous/interesting thing, so we want the latter to be modeled as the sink.
|
||||
*
|
||||
* TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
|
||||
*/
|
||||
private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
|
||||
{
|
||||
UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
e.getCallable().getName().matches("is%") and
|
||||
e.getCallable().getReturnType() instanceof BooleanType and
|
||||
(
|
||||
e.getExtensibleType() = "sinkModel" and
|
||||
not FrameworkCandidatesImpl::isSink(e, _, _)
|
||||
or
|
||||
e.getExtensibleType() = "sourceModel" and
|
||||
not FrameworkCandidatesImpl::isSource(e, _, _) and
|
||||
e.getMaDOutput() = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
|
||||
* considered sinks, and its return value should not be considered a source.
|
||||
*
|
||||
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
|
||||
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
|
||||
* dangerous/interesting thing, so we want the latter to be modeled as the sink.
|
||||
*/
|
||||
private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
|
||||
{
|
||||
UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
exists(Callable callable |
|
||||
callable = e.getCallable() and
|
||||
callable.getName().toLowerCase() = ["exists", "notexists"] and
|
||||
callable.getReturnType() instanceof BooleanType
|
||||
|
|
||||
e.getExtensibleType() = "sinkModel" and
|
||||
not FrameworkCandidatesImpl::isSink(e, _, _)
|
||||
or
|
||||
e.getExtensibleType() = "sourceModel" and
|
||||
not FrameworkCandidatesImpl::isSource(e, _, _) and
|
||||
e.getMaDOutput() = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
|
||||
* and its return value should not be considered a source.
|
||||
*/
|
||||
private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
|
||||
{
|
||||
ExceptionCharacteristic() { this = "argument/result of exception-related method" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
|
||||
(
|
||||
e.getExtensibleType() = "sinkModel" and
|
||||
not FrameworkCandidatesImpl::isSink(e, _, _)
|
||||
or
|
||||
e.getExtensibleType() = "sourceModel" and
|
||||
not FrameworkCandidatesImpl::isSource(e, _, _) and
|
||||
e.getMaDOutput() = "ReturnValue"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A characteristic that limits candidates to parameters of methods that are recognized as `ModelApi`, iow., APIs that
|
||||
* are considered worth modeling.
|
||||
*/
|
||||
private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelCharacteristic {
|
||||
NotAModelApi() { this = "not a model API" }
|
||||
|
||||
override predicate appliesToEndpoint(Endpoint e) {
|
||||
not e.getCallable() instanceof ModelExclusions::ModelApi
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for
|
||||
* classification with an ML model.
|
||||
*
|
||||
* Note: This query does not actually classify the endpoints using the model.
|
||||
*
|
||||
* @name Automodel candidates (framework mode)
|
||||
* @description A query to extract automodel candidates in framework mode.
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-framework-candidates
|
||||
* @tags internal extract automodel framework-mode candidates
|
||||
*/
|
||||
|
||||
private import AutomodelFrameworkModeCharacteristics
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
from
|
||||
Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
|
||||
DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output,
|
||||
DollarAtString parameterName, DollarAtString alreadyAiModeled, DollarAtString extensibleType
|
||||
where
|
||||
isCandidate(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
|
||||
extensibleType, alreadyAiModeled)
|
||||
select endpoint,
|
||||
"Related locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", //
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
parameterName, "parameterName", //
|
||||
alreadyAiModeled, "alreadyAiModeled", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt.
|
||||
*
|
||||
* @name Negative examples (framework mode)
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-framework-negative-examples
|
||||
* @tags internal extract automodel framework-mode negative examples
|
||||
*/
|
||||
|
||||
private import AutomodelFrameworkModeCharacteristics
|
||||
private import AutomodelEndpointTypes
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
from
|
||||
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence,
|
||||
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
|
||||
DollarAtString signature, DollarAtString input, DollarAtString output,
|
||||
DollarAtString parameterName, DollarAtString extensibleType
|
||||
where
|
||||
isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
|
||||
input, output, parameterName, extensibleType)
|
||||
select endpoint,
|
||||
characteristic + "\nrelated locations: $@, $@." +
|
||||
"\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", //
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
parameterName, "parameterName", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt.
|
||||
*
|
||||
* @name Positive examples (framework mode)
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @id java/ml/extract-automodel-framework-positive-examples
|
||||
* @tags internal extract automodel framework-mode positive examples
|
||||
*/
|
||||
|
||||
private import AutomodelFrameworkModeCharacteristics
|
||||
private import AutomodelEndpointTypes
|
||||
private import AutomodelJavaUtil
|
||||
|
||||
from
|
||||
Endpoint endpoint, EndpointType endpointType, DollarAtString package, DollarAtString type,
|
||||
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
|
||||
DollarAtString output, DollarAtString parameterName, DollarAtString extensibleType
|
||||
where
|
||||
isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
|
||||
parameterName, extensibleType)
|
||||
select endpoint,
|
||||
endpointType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
|
||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
|
||||
package, "package", //
|
||||
type, "type", //
|
||||
subtypes, "subtypes", //
|
||||
name, "name", //
|
||||
signature, "signature", //
|
||||
input, "input", //
|
||||
output, "output", //
|
||||
parameterName, "parameterName", //
|
||||
extensibleType, "extensibleType"
|
||||
@@ -1,111 +0,0 @@
|
||||
private import java
|
||||
private import AutomodelEndpointTypes as AutomodelEndpointTypes
|
||||
|
||||
/**
|
||||
* A helper class to represent a string value that can be returned by a query using $@ notation.
|
||||
*
|
||||
* It extends `string`, but adds a mock `hasLocationInfo` method that returns the string itself as the file name.
|
||||
*
|
||||
* Use this, when you want to return a string value from a query using $@ notation - the string value
|
||||
* will be included in the sarif file.
|
||||
*
|
||||
*
|
||||
* Background information on `hasLocationInfo`:
|
||||
* https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-location-information
|
||||
*/
|
||||
class DollarAtString extends string {
|
||||
bindingset[this]
|
||||
DollarAtString() { any() }
|
||||
|
||||
bindingset[this]
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = this and sl = 1 and sc = 1 and el = 1 and ec = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for all combinations of MaD kinds (`kind`) and their human readable
|
||||
* descriptions.
|
||||
*/
|
||||
predicate isKnownKind(string kind, AutomodelEndpointTypes::EndpointType type) {
|
||||
kind = type.getKind()
|
||||
}
|
||||
|
||||
/**
|
||||
* By convention, the subtypes property of the MaD declaration should only be
|
||||
* true when there _can_ exist any subtypes with a different implementation.
|
||||
*
|
||||
* It would technically be ok to always use the value 'true', but this would
|
||||
* break convention.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
boolean considerSubtypes(Callable callable) {
|
||||
if
|
||||
callable.isStatic() or
|
||||
callable.getDeclaringType().isStatic() or
|
||||
callable.isFinal() or
|
||||
callable.getDeclaringType().isFinal()
|
||||
then result = false
|
||||
else result = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given package, type, name and signature is a candidate for automodeling.
|
||||
*
|
||||
* This predicate is extensible, so that different endpoints can be selected at runtime.
|
||||
*/
|
||||
extensible predicate automodelCandidateFilter(
|
||||
string package, string type, string name, string signature
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if the given package, type, name and signature is a candidate for automodeling.
|
||||
*
|
||||
* This relies on an extensible predicate, and if that is not supplied then
|
||||
* all endpoints are considered candidates.
|
||||
*/
|
||||
bindingset[package, type, name, signature]
|
||||
predicate includeAutomodelCandidate(string package, string type, string name, string signature) {
|
||||
not automodelCandidateFilter(_, _, _, _) or
|
||||
automodelCandidateFilter(package, type, name, signature)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given program element corresponds to a piece of source code,
|
||||
* that is, it is not compiler-generated.
|
||||
*
|
||||
* Note: This is a stricter check than `Element::fromSource`, which simply
|
||||
* checks whether the element is in a source file as opposed to a JAR file.
|
||||
* There can be compiler-generated elements in source files (especially for
|
||||
* Kotlin), which we also want to exclude.
|
||||
*/
|
||||
predicate isFromSource(Element e) {
|
||||
// from a source file (not a JAR)
|
||||
e.fromSource() and
|
||||
// not explicitly marked as compiler-generated
|
||||
not e.isCompilerGenerated() and
|
||||
// does not have a dummy location
|
||||
not e.hasLocationInfo(_, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint cannot flow through the given type (because it is a numeric
|
||||
* type or some other type with a fixed set of values).
|
||||
*/
|
||||
predicate isUnexploitableType(Type tp) {
|
||||
tp instanceof PrimitiveType or
|
||||
tp instanceof BoxedType or
|
||||
tp instanceof NumberType or
|
||||
tp instanceof VoidType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given method can be overridden, that is, it is not final,
|
||||
* static, or private.
|
||||
*/
|
||||
predicate isOverridable(Method m) {
|
||||
not m.getDeclaringType().isFinal() and
|
||||
not m.isFinal() and
|
||||
not m.isStatic() and
|
||||
not m.isPrivate()
|
||||
}
|
||||
@@ -1,412 +0,0 @@
|
||||
float maximalConfidence() { result = 1.0 }
|
||||
|
||||
float highConfidence() { result = 0.9 }
|
||||
|
||||
float mediumConfidence() { result = 0.6 }
|
||||
|
||||
/**
|
||||
* A specification of how to instantiate the shared characteristics for a given candidate class.
|
||||
*
|
||||
* The `CandidateSig` implementation specifies a type to use for Endpoints (eg., `ParameterNode`), as well as a type
|
||||
* to label endpoint classes (the `EndpointType`). One of the endpoint classes needs to be a 'negative' class, meaning
|
||||
* "not any of the other known endpoint types".
|
||||
*/
|
||||
signature module CandidateSig {
|
||||
/**
|
||||
* An endpoint is a potential candidate for modeling. This will typically be bound to the language's
|
||||
* DataFlow node class, or a subtype thereof.
|
||||
*/
|
||||
class Endpoint {
|
||||
/**
|
||||
* Gets the kind of this endpoint, either "sourceModel" or "sinkModel".
|
||||
*/
|
||||
string getExtensibleType();
|
||||
|
||||
/**
|
||||
* Gets a string representation of this endpoint.
|
||||
*/
|
||||
string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A related location for an endpoint. This will typically be bound to the supertype of all AST nodes (eg., `Top`).
|
||||
*/
|
||||
class RelatedLocation;
|
||||
|
||||
/**
|
||||
* A label for a related location.
|
||||
*
|
||||
* Eg., method-doc, class-doc, etc.
|
||||
*/
|
||||
class RelatedLocationType;
|
||||
|
||||
/**
|
||||
* An endpoint type considered by this specification.
|
||||
*/
|
||||
class EndpointType extends string;
|
||||
|
||||
/**
|
||||
* A sink endpoint type considered by this specification.
|
||||
*/
|
||||
class SinkType extends EndpointType;
|
||||
|
||||
/**
|
||||
* A source endpoint type considered by this specification.
|
||||
*/
|
||||
class SourceType extends EndpointType;
|
||||
|
||||
/**
|
||||
* Gets the endpoint as a location.
|
||||
*
|
||||
* This is a utility function to convert an endpoint to its corresponding location.
|
||||
*/
|
||||
RelatedLocation asLocation(Endpoint e);
|
||||
|
||||
/**
|
||||
* Defines what MaD kinds are known, and what endpoint type they correspond to.
|
||||
*/
|
||||
predicate isKnownKind(string kind, EndpointType type);
|
||||
|
||||
/**
|
||||
* Holds if `e` is a flow sanitizer, and has type `t`.
|
||||
*/
|
||||
predicate isSanitizer(Endpoint e, EndpointType t);
|
||||
|
||||
/**
|
||||
* Holds if `e` is a sink with the label `kind`, and provenance `provenance`.
|
||||
*/
|
||||
predicate isSink(Endpoint e, string kind, string provenance);
|
||||
|
||||
/**
|
||||
* Holds if `e` is a source with the label `kind`, and provenance `provenance`.
|
||||
*/
|
||||
predicate isSource(Endpoint e, string kind, string provenance);
|
||||
|
||||
/**
|
||||
* Holds if `e` is not a source or sink of any kind.
|
||||
*/
|
||||
predicate isNeutral(Endpoint e);
|
||||
|
||||
/**
|
||||
* Gets a related location.
|
||||
*
|
||||
* A related location is a source code location that may hold extra information about an endpoint that can be useful
|
||||
* to the machine learning model.
|
||||
*
|
||||
* For example, a related location for a method call may be the documentation comment of a method.
|
||||
*/
|
||||
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of shared characteristics for a given candidate class.
|
||||
*
|
||||
* This module is language-agnostic, although the `CandidateSig` module will be language-specific.
|
||||
*
|
||||
* The language specific implementation can also further extend the behavior of this module by adding additional
|
||||
* implementations of endpoint characteristics exported by this module.
|
||||
*/
|
||||
module SharedCharacteristics<CandidateSig Candidate> {
|
||||
predicate isSink = Candidate::isSink/3;
|
||||
|
||||
predicate isNeutral = Candidate::isNeutral/1;
|
||||
|
||||
predicate isModeled(Candidate::Endpoint e, string kind, string extensibleKind, string provenance) {
|
||||
Candidate::isSink(e, kind, provenance) and extensibleKind = "sinkModel"
|
||||
or
|
||||
Candidate::isSource(e, kind, provenance) and extensibleKind = "sourceModel"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `endpoint` is modeled as `endpointType`.
|
||||
*/
|
||||
predicate isKnownAs(
|
||||
Candidate::Endpoint endpoint, Candidate::EndpointType endpointType,
|
||||
EndpointCharacteristic characteristic
|
||||
) {
|
||||
// If the list of characteristics includes positive indicators with maximal confidence for this class, then it's a
|
||||
// known sink for the class.
|
||||
characteristic.appliesToEndpoint(endpoint) and
|
||||
characteristic.hasImplications(endpointType, true, maximalConfidence())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a potential type of this endpoint to make sure that sources are
|
||||
* associated with source types and sinks with sink types.
|
||||
*/
|
||||
Candidate::EndpointType getAPotentialType(Candidate::Endpoint endpoint) {
|
||||
endpoint.getExtensibleType() = "sourceModel" and
|
||||
result instanceof Candidate::SourceType
|
||||
or
|
||||
endpoint.getExtensibleType() = "sinkModel" and
|
||||
result instanceof Candidate::SinkType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given `endpoint` should be considered as a candidate for type `endpointType`,
|
||||
* and classified by the ML model.
|
||||
*
|
||||
* A candidate is an endpoint that cannot be excluded from `endpointType` based on its characteristics.
|
||||
*/
|
||||
predicate isCandidate(Candidate::Endpoint endpoint, Candidate::EndpointType endpointType) {
|
||||
endpointType = getAPotentialType(endpoint) and
|
||||
not exists(getAnExcludingCharacteristic(endpoint, endpointType))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the related location of `e` with name `name`, if it exists.
|
||||
* Otherwise, gets the candidate itself.
|
||||
*/
|
||||
Candidate::RelatedLocation getRelatedLocationOrCandidate(
|
||||
Candidate::Endpoint e, Candidate::RelatedLocationType type
|
||||
) {
|
||||
if exists(Candidate::getRelatedLocation(e, type))
|
||||
then result = Candidate::getRelatedLocation(e, type)
|
||||
else result = Candidate::asLocation(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a characteristics that disbar `endpoint` from being a candidate for `endpointType`
|
||||
* with at least medium confidence.
|
||||
*/
|
||||
EndpointCharacteristic getAnExcludingCharacteristic(
|
||||
Candidate::Endpoint endpoint, Candidate::EndpointType endpointType
|
||||
) {
|
||||
result.appliesToEndpoint(endpoint) and
|
||||
exists(float confidence |
|
||||
confidence >= mediumConfidence() and
|
||||
result.hasImplications(endpointType, false, confidence)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of characteristics that a particular endpoint might have. This set of characteristics is used to make decisions
|
||||
* about whether to include the endpoint in the training set and with what kind, as well as whether to score the
|
||||
* endpoint at inference time.
|
||||
*/
|
||||
abstract class EndpointCharacteristic extends string {
|
||||
/**
|
||||
* Holds for the string that is the name of the characteristic. This should describe some property of an endpoint
|
||||
* that is meaningful for determining whether it's a sink, and if so, of which sink type.
|
||||
*/
|
||||
bindingset[this]
|
||||
EndpointCharacteristic() { any() }
|
||||
|
||||
/**
|
||||
* Holds for endpoints that have this characteristic.
|
||||
*/
|
||||
abstract predicate appliesToEndpoint(Candidate::Endpoint n);
|
||||
|
||||
/**
|
||||
* This predicate describes what the characteristic tells us about an endpoint.
|
||||
*
|
||||
* Params:
|
||||
* endpointType: The sink/source type.
|
||||
* isPositiveIndicator: If true, this characteristic indicates that this endpoint _is_ a member of the class; if
|
||||
* false, it indicates that it _isn't_ a member of the class.
|
||||
* confidence: A float in [0, 1], which tells us how strong an indicator this characteristic is for the endpoint
|
||||
* belonging / not belonging to the given class. A confidence near zero means this characteristic is a very weak
|
||||
* indicator of whether or not the endpoint belongs to the class. A confidence of 1 means that all endpoints with
|
||||
* this characteristic definitively do/don't belong to the class.
|
||||
*/
|
||||
abstract predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
);
|
||||
|
||||
/** Indicators with confidence at or above this threshold are considered to be high-confidence indicators. */
|
||||
final float getHighConfidenceThreshold() { result = 0.8 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-confidence characteristic that indicates that an endpoint is a sink of a specified type. These endpoints can
|
||||
* be used as positive samples for training or for a few-shot prompt.
|
||||
*/
|
||||
abstract class SinkCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
SinkCharacteristic() { any() }
|
||||
|
||||
abstract Candidate::EndpointType getSinkType();
|
||||
|
||||
final override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType = this.getSinkType() and
|
||||
isPositiveIndicator = true and
|
||||
confidence = maximalConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-confidence characteristic that indicates that an endpoint is a source of a specified type. These endpoints can
|
||||
* be used as positive samples for training or for a few-shot prompt.
|
||||
*/
|
||||
abstract class SourceCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
SourceCharacteristic() { any() }
|
||||
|
||||
abstract Candidate::EndpointType getSourceType();
|
||||
|
||||
final override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType = this.getSourceType() and
|
||||
isPositiveIndicator = true and
|
||||
confidence = maximalConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-confidence characteristic that indicates that an endpoint is not a sink of any type. These endpoints can be
|
||||
* used as negative samples for training or for a few-shot prompt.
|
||||
*/
|
||||
abstract class NotASinkCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
NotASinkCharacteristic() { any() }
|
||||
|
||||
override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType instanceof Candidate::SinkType and
|
||||
isPositiveIndicator = false and
|
||||
confidence = highConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-confidence characteristic that indicates that an endpoint is not a source of any type. These endpoints can be
|
||||
* used as negative samples for training or for a few-shot prompt.
|
||||
*/
|
||||
abstract class NotASourceCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
NotASourceCharacteristic() { any() }
|
||||
|
||||
override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType instanceof Candidate::SourceType and
|
||||
isPositiveIndicator = false and
|
||||
confidence = highConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-confidence characteristic that indicates that an endpoint is neither a source nor a sink of any type.
|
||||
*/
|
||||
abstract class NeitherSourceNorSinkCharacteristic extends NotASinkCharacteristic,
|
||||
NotASourceCharacteristic
|
||||
{
|
||||
bindingset[this]
|
||||
NeitherSourceNorSinkCharacteristic() { any() }
|
||||
|
||||
final override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
NotASinkCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence) or
|
||||
NotASourceCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A medium-confidence characteristic that indicates that an endpoint is unlikely to be a sink of any type. These
|
||||
* endpoints can be excluded from scoring at inference time, both to save time and to avoid false positives. They should
|
||||
* not, however, be used as negative samples for training or for a few-shot prompt, because they may include a small
|
||||
* number of sinks.
|
||||
*/
|
||||
abstract class LikelyNotASinkCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
LikelyNotASinkCharacteristic() { any() }
|
||||
|
||||
override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType instanceof Candidate::SinkType and
|
||||
isPositiveIndicator = false and
|
||||
confidence = mediumConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A characteristic that indicates not necessarily that an endpoint is not a sink, but rather that it is not a sink
|
||||
* that's interesting to model in the standard Java libraries. These filters should be removed when extracting sink
|
||||
* candidates within a user's codebase for customized modeling.
|
||||
*
|
||||
* These endpoints should not be used as negative samples for training or for a few-shot prompt, because they are not
|
||||
* necessarily non-sinks.
|
||||
*/
|
||||
abstract class UninterestingToModelCharacteristic extends EndpointCharacteristic {
|
||||
bindingset[this]
|
||||
UninterestingToModelCharacteristic() { any() }
|
||||
|
||||
override predicate hasImplications(
|
||||
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
|
||||
) {
|
||||
endpointType instanceof Candidate::SinkType and
|
||||
isPositiveIndicator = false and
|
||||
confidence = mediumConfidence()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains default implementations that are derived solely from the `CandidateSig` implementation.
|
||||
*/
|
||||
private module DefaultCharacteristicImplementations {
|
||||
/**
|
||||
* Endpoints identified as sinks by the `CandidateSig` implementation are sinks with maximal confidence.
|
||||
*/
|
||||
private class KnownSinkCharacteristic extends SinkCharacteristic {
|
||||
string madKind;
|
||||
Candidate::EndpointType endpointType;
|
||||
string provenance;
|
||||
|
||||
KnownSinkCharacteristic() {
|
||||
Candidate::isKnownKind(madKind, endpointType) and
|
||||
// bind "this" to a unique string differing from that of the SinkType classes
|
||||
this = madKind + "_" + provenance + "_characteristic" and
|
||||
Candidate::isSink(_, madKind, provenance)
|
||||
}
|
||||
|
||||
override predicate appliesToEndpoint(Candidate::Endpoint e) {
|
||||
Candidate::isSink(e, madKind, provenance)
|
||||
}
|
||||
|
||||
override Candidate::EndpointType getSinkType() { result = endpointType }
|
||||
}
|
||||
|
||||
private class KnownSourceCharacteristic extends SourceCharacteristic {
|
||||
string madKind;
|
||||
Candidate::EndpointType endpointType;
|
||||
string provenance;
|
||||
|
||||
KnownSourceCharacteristic() {
|
||||
Candidate::isKnownKind(madKind, endpointType) and
|
||||
// bind "this" to a unique string differing from that of the SinkType classes
|
||||
this = madKind + "_" + provenance + "_characteristic" and
|
||||
Candidate::isSource(_, madKind, provenance)
|
||||
}
|
||||
|
||||
override predicate appliesToEndpoint(Candidate::Endpoint e) {
|
||||
Candidate::isSource(e, madKind, provenance)
|
||||
}
|
||||
|
||||
override Candidate::EndpointType getSourceType() { result = endpointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that an endpoint was manually modeled as a neutral model.
|
||||
*/
|
||||
private class NeutralModelCharacteristic extends NeitherSourceNorSinkCharacteristic {
|
||||
NeutralModelCharacteristic() { this = "known non-sink" }
|
||||
|
||||
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isNeutral(e) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A negative characteristic that indicates that an endpoint is a sanitizer, and thus not a source.
|
||||
*/
|
||||
private class IsSanitizerCharacteristic extends NotASourceCharacteristic {
|
||||
IsSanitizerCharacteristic() { this = "known sanitizer" }
|
||||
|
||||
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* This file contains query predicates for use when gathering metrics at scale using Multi Repo
|
||||
* Variant Analysis.
|
||||
*/
|
||||
|
||||
private import java
|
||||
private import AutomodelAlertSinkUtil
|
||||
|
||||
/**
|
||||
* Holds if `alertCount` is the number of alerts for the query with ID `queryId` for which the
|
||||
* sinks correspond to the given `ai-generated` sink model.
|
||||
*/
|
||||
query predicate sinkModelCountPerQuery(
|
||||
string queryId, int alertCount, string package, string type, boolean subtypes, string name,
|
||||
string signature, string input, string ext, string kind, string provenance
|
||||
) {
|
||||
exists(SinkModel s |
|
||||
sinkModelTallyPerQuery(queryId, alertCount, s) and
|
||||
s.getProvenance() = "ai-generated" and
|
||||
s.getPackage() = package and
|
||||
s.getType() = type and
|
||||
s.getSubtypes() = subtypes and
|
||||
s.getName() = name and
|
||||
s.getSignature() = signature and
|
||||
s.getInput() = input and
|
||||
s.getExt() = ext and
|
||||
s.getKind() = kind and
|
||||
s.getProvenance() = provenance
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instanceCount` is the number of instances corresponding to the given `ai-generated`
|
||||
* sink model (as identified by the `package`, `name`, `input`, etc.).
|
||||
*/
|
||||
query predicate instanceCount(
|
||||
int instanceCount, string package, string type, boolean subtypes, string name, string signature,
|
||||
string input, string ext, string kind, string provenance
|
||||
) {
|
||||
exists(SinkModel s |
|
||||
instanceCount = s.getInstanceCount() and
|
||||
instanceCount > 0 and
|
||||
s.getProvenance() = "ai-generated" and
|
||||
s.getPackage() = package and
|
||||
s.getType() = type and
|
||||
s.getSubtypes() = subtypes and
|
||||
s.getName() = name and
|
||||
s.getSignature() = signature and
|
||||
s.getInput() = input and
|
||||
s.getExt() = ext and
|
||||
s.getKind() = kind and
|
||||
s.getProvenance() = provenance
|
||||
)
|
||||
}
|
||||
|
||||
// MRVA requires a select clause, so we repurpose it to tell us which query predicates had results.
|
||||
from string hadResults
|
||||
where
|
||||
sinkModelCountPerQuery(_, _, _, _, _, _, _, _, _, _, _) and hadResults = "sinkModelCountPerQuery"
|
||||
or
|
||||
instanceCount(_, _, _, _, _, _, _, _, _, _) and hadResults = "instanceCount"
|
||||
select hadResults
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* Dropped the Java Automodel queries.
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.11
|
||||
@@ -1,10 +0,0 @@
|
||||
name: codeql/java-automodel-queries
|
||||
version: 1.0.12-dev
|
||||
groups:
|
||||
- java
|
||||
- automodel
|
||||
dependencies:
|
||||
codeql/java-all: ${workspace}
|
||||
dataExtensions:
|
||||
- AutomodelCandidateFilter.yml
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,2 +0,0 @@
|
||||
testFailures
|
||||
failures
|
||||
@@ -1,35 +0,0 @@
|
||||
import java
|
||||
import AutomodelApplicationModeCharacteristics as Characteristics
|
||||
import AutomodelExtractionTests
|
||||
|
||||
module TestHelper implements TestHelperSig<Characteristics::ApplicationCandidatesImpl> {
|
||||
Location getEndpointLocation(Characteristics::Endpoint endpoint) {
|
||||
result = endpoint.asTop().getLocation()
|
||||
}
|
||||
|
||||
predicate isCandidate(
|
||||
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
) {
|
||||
Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
|
||||
extensibleType, _)
|
||||
}
|
||||
|
||||
predicate isPositiveExample(
|
||||
Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
|
||||
string input, string output, string extensibleType
|
||||
) {
|
||||
Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
|
||||
output, _, extensibleType)
|
||||
}
|
||||
|
||||
predicate isNegativeExample(
|
||||
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
) {
|
||||
Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
|
||||
extensibleType)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<Extraction<Characteristics::ApplicationCandidatesImpl, TestHelper>>
|
||||
@@ -1,8 +0,0 @@
|
||||
import hudson.Plugin;
|
||||
|
||||
public class PluginImpl extends Plugin {
|
||||
@Override
|
||||
public void configure(String name, String value) { // $ sourceModelCandidate=configure(String,String):Parameter[0] sourceModelCandidate=configure(String,String):Parameter[1]
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.github.codeql.test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.net.URLConnection;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
class Test {
|
||||
public static void main(String[] args) throws Exception {
|
||||
AtomicReference<String> reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
|
||||
reference.set( // $ sinkModelCandidate=set(Object):Argument[this]
|
||||
args[0] // $ negativeSinkExample=set(Object):Argument[0] // modeled as a flow step
|
||||
); // not a source candidate (return type is void)
|
||||
}
|
||||
|
||||
public static void callSupplier(Supplier<String> supplier) {
|
||||
supplier.get(); // not a source candidate (lambda flow)
|
||||
}
|
||||
|
||||
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
|
||||
Files.copy(
|
||||
source, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[0](path-injection)
|
||||
target, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[1](path-injection)
|
||||
option // no candidate (not modeled, but source and target are modeled)
|
||||
); // $ sourceModelCandidate=copy(Path,Path,CopyOption[]):ReturnValue
|
||||
}
|
||||
|
||||
public static InputStream getInputStream(Path openPath) throws Exception {
|
||||
return Files.newInputStream(
|
||||
openPath // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) // sink candidate because "only" ai-modeled, and useful as a candidate in regression testing
|
||||
); // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
|
||||
}
|
||||
|
||||
public static InputStream getInputStream(String openPath, String otherPath) throws Exception {
|
||||
return Test.getInputStream( // the call is not a source candidate (argument to local call)
|
||||
Paths.get(
|
||||
openPath, // $ negativeSinkExample=get(String,String[]):Argument[0] // modeled as a flow step
|
||||
otherPath
|
||||
) // $ sourceModelCandidate=get(String,String[]):ReturnValue negativeSinkExample=get(String,String[]):Argument[1]
|
||||
);
|
||||
}
|
||||
|
||||
public static int compareFiles(File f1, File f2) {
|
||||
return f1.compareTo( // $ negativeSinkExample=compareTo(File):Argument[this]
|
||||
f2 // $ negativeSinkExample=compareTo(File):Argument[0] // modeled as not a sink
|
||||
); // not a source candidate (return type is int)
|
||||
}
|
||||
|
||||
public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
|
||||
Files.walk(
|
||||
p, // $ negativeSinkExample=walk(Path,FileVisitOption[]):Argument[0] // modeled as a flow step
|
||||
o, // the implicit varargs array is a candidate, annotated on the last line of the call
|
||||
o // not a candidate (only the first arg corresponding to a varargs array
|
||||
// is extracted)
|
||||
); // $ sourceModelCandidate=walk(Path,FileVisitOption[]):ReturnValue sinkModelCandidate=walk(Path,FileVisitOption[]):Argument[1]
|
||||
}
|
||||
|
||||
public static void WebSocketExample(URLConnection c) throws Exception {
|
||||
c.getInputStream(); // $ sinkModelCandidate=getInputStream():Argument[this] positiveSourceExample=getInputStream():ReturnValue(remote) // not a source candidate (manual modeling)
|
||||
c.connect(); // $ sinkModelCandidate=connect():Argument[this] // not a source candidate (return type is void)
|
||||
}
|
||||
|
||||
public static void fileFilterExample(File f, FileFilter ff) {
|
||||
f.listFiles( // $ sinkModelCandidate=listFiles(FileFilter):Argument[this]
|
||||
ff
|
||||
); // $ sourceModelCandidate=listFiles(FileFilter):ReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
class OverrideTest extends Exception {
|
||||
public void printStackTrace(PrintWriter writer) { // $ sourceModelCandidate=printStackTrace(PrintWriter):Parameter[0]
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TaskUtils {
|
||||
public FutureTask getTask() {
|
||||
FutureTask ft = new FutureTask(() -> {
|
||||
// ^-- no sink candidate for the `this` qualifier of a constructor
|
||||
return 42;
|
||||
});
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
|
||||
class MoreTests {
|
||||
public static void FilesListExample(Path p) throws Exception {
|
||||
Files.list(
|
||||
Files.createDirectories(
|
||||
p // $ positiveSinkExample=createDirectories(Path,FileAttribute[]):Argument[0](path-injection)
|
||||
) // $ sourceModelCandidate=createDirectories(Path,FileAttribute[]):ReturnValue negativeSinkExample=list(Path):Argument[0] // modeled as a flow step
|
||||
); // $ sourceModelCandidate=list(Path):ReturnValue
|
||||
|
||||
Files.delete(
|
||||
p // $ sinkModelCandidate=delete(Path):Argument[0] positiveSinkExample=delete(Path):Argument[0](path-injection)
|
||||
); // not a source candidate (return type is void)
|
||||
|
||||
Files.deleteIfExists(
|
||||
p // $ sinkModelCandidate=deleteIfExists(Path):Argument[0] positiveSinkExample=deleteIfExists(Path):Argument[0](path-injection)
|
||||
); // not a source candidate (return type is boolean)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package hudson;
|
||||
|
||||
/** Plugin doc */
|
||||
public class Plugin {
|
||||
/** Configure method doc */
|
||||
public void configure(String name, String value) {}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import java
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import AutomodelSharedCharacteristics
|
||||
|
||||
signature module TestHelperSig<CandidateSig Candidate> {
|
||||
Location getEndpointLocation(Candidate::Endpoint e);
|
||||
|
||||
predicate isCandidate(
|
||||
Candidate::Endpoint e, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
);
|
||||
|
||||
predicate isPositiveExample(
|
||||
Candidate::Endpoint e, string endpointType, string name, string signature, string input,
|
||||
string output, string extensibleType
|
||||
);
|
||||
|
||||
predicate isNegativeExample(
|
||||
Candidate::Endpoint e, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
);
|
||||
}
|
||||
|
||||
module Extraction<CandidateSig Candidate, TestHelperSig<Candidate> TestHelper> implements TestSig {
|
||||
string getARelevantTag() {
|
||||
result in [
|
||||
"sourceModelCandidate", "sinkModelCandidate", // a candidate source/sink
|
||||
"positiveSourceExample", "positiveSinkExample", // a known source/sink
|
||||
"negativeSourceExample", "negativeSinkExample" // a known non-source/non-sink
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* If `extensibleType` is `sourceModel` then the result is `ifSource`, if it
|
||||
* is `sinkModel` then the result is `ifSink`.
|
||||
*/
|
||||
bindingset[extensibleType, ifSource, ifSink]
|
||||
private string ifSource(string extensibleType, string ifSource, string ifSink) {
|
||||
extensibleType = "sourceModel" and result = ifSource
|
||||
or
|
||||
extensibleType = "sinkModel" and result = ifSink
|
||||
}
|
||||
|
||||
additional predicate selectEndpoint(
|
||||
Candidate::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType, string tag, string suffix
|
||||
) {
|
||||
TestHelper::isCandidate(endpoint, name, signature, input, output, extensibleType) and
|
||||
tag = ifSource(extensibleType, "sourceModelCandidate", "sinkModelCandidate") and
|
||||
suffix = ""
|
||||
or
|
||||
TestHelper::isNegativeExample(endpoint, name, signature, input, output, extensibleType) and
|
||||
tag = "negative" + ifSource(extensibleType, "Source", "Sink") + "Example" and
|
||||
suffix = ""
|
||||
or
|
||||
exists(string endpointType |
|
||||
TestHelper::isPositiveExample(endpoint, endpointType, name, signature, input, output,
|
||||
extensibleType) and
|
||||
tag = "positive" + ifSource(extensibleType, "Source", "Sink") + "Example" and
|
||||
suffix = "(" + endpointType + ")"
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(
|
||||
Candidate::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType, string suffix
|
||||
|
|
||||
selectEndpoint(endpoint, name, signature, input, output, extensibleType, tag, suffix)
|
||||
|
|
||||
TestHelper::getEndpointLocation(endpoint) = location and
|
||||
endpoint.toString() = element and
|
||||
// for source models only the output is relevant, and vice versa for sink models
|
||||
value = name + signature + ":" + ifSource(extensibleType, output, input) + suffix
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
testFailures
|
||||
failures
|
||||
@@ -1,35 +0,0 @@
|
||||
import java
|
||||
import AutomodelFrameworkModeCharacteristics as Characteristics
|
||||
import AutomodelExtractionTests
|
||||
|
||||
module TestHelper implements TestHelperSig<Characteristics::FrameworkCandidatesImpl> {
|
||||
Location getEndpointLocation(Characteristics::Endpoint endpoint) {
|
||||
result = endpoint.asTop().getLocation()
|
||||
}
|
||||
|
||||
predicate isCandidate(
|
||||
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
) {
|
||||
Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
|
||||
extensibleType, _)
|
||||
}
|
||||
|
||||
predicate isPositiveExample(
|
||||
Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
|
||||
string input, string output, string extensibleType
|
||||
) {
|
||||
Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
|
||||
output, _, extensibleType)
|
||||
}
|
||||
|
||||
predicate isNegativeExample(
|
||||
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
|
||||
string extensibleType
|
||||
) {
|
||||
Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
|
||||
extensibleType)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<Extraction<Characteristics::FrameworkCandidatesImpl, TestHelper>>
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.github.codeql.test;
|
||||
|
||||
public class MyWriter extends java.io.Writer {
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) { // $ sinkModelCandidate=write(char[],int,int):Argument[this] positiveSinkExample=write(char[],int,int):Argument[0](file-content-store) sourceModelCandidate=write(char[],int,int):Parameter[this] sourceModelCandidate=write(char[],int,int):Parameter[0]
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() { // $ sinkModelCandidate=close():Argument[this] sourceModelCandidate=close():Parameter[this]
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() { // $ sinkModelCandidate=flush():Argument[this] sourceModelCandidate=flush():Parameter[this]
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.github.codeql.test;
|
||||
|
||||
/**
|
||||
* No candidates in this class, as it's not public!
|
||||
*/
|
||||
class NonPublicClass {
|
||||
public void noCandidates(String here) {
|
||||
System.out.println(here);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.github.codeql.test;
|
||||
|
||||
public class PublicClass {
|
||||
public void stuff(String arg) { // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // source candidates because it is an overrideable method
|
||||
System.out.println(arg);
|
||||
}
|
||||
|
||||
public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // `arg` is not a source candidate (not overrideabe); `this` is not a candidate (static method)
|
||||
System.out.println(arg);
|
||||
}
|
||||
|
||||
protected void nonPublicStuff(String arg) { // $ sinkModelCandidate=nonPublicStuff(String):Argument[this] sourceModelCandidate=nonPublicStuff(String):Parameter[this] sinkModelCandidate=nonPublicStuff(String):Argument[0] sourceModelCandidate=nonPublicStuff(String):Parameter[0]
|
||||
System.out.println(arg);
|
||||
}
|
||||
|
||||
void packagePrivateStuff(String arg) { // no candidates because the method is not public
|
||||
System.out.println(arg);
|
||||
}
|
||||
|
||||
public PublicClass(Object input) { // $ sourceModelCandidate=PublicClass(Object):ReturnValue sinkModelCandidate=PublicClass(Object):Argument[0] // `this` is not a candidate because it is a constructor
|
||||
}
|
||||
|
||||
// `input` and `input` are source candidates, but not sink candidates (is-style method)
|
||||
public Boolean isIgnored(Object input) { // $ negativeSinkExample=isIgnored(Object):Argument[this] sourceModelCandidate=isIgnored(Object):Parameter[this] negativeSinkExample=isIgnored(Object):Argument[0] sourceModelCandidate=isIgnored(Object):Parameter[0]
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.github.codeql.test;
|
||||
|
||||
public interface PublicInterface {
|
||||
public int stuff(String arg); // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // result is _not_ a source candidate source (primitive return type)
|
||||
|
||||
public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // not a source candidate (static method)
|
||||
System.out.println(arg);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package java.io;
|
||||
|
||||
public class File {
|
||||
public int compareTo( // $ negativeSinkExample=compareTo(File):Argument[this] sourceModelCandidate=compareTo(File):Parameter[this] // modeled as neutral for sinks
|
||||
File pathname // $ negativeSinkExample=compareTo(File):Argument[0] sourceModelCandidate=compareTo(File):Parameter[0] // modeled as neutral for sinks
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean setLastModified(long time) { // $ sinkModelCandidate=setLastModified(long):Argument[this] sourceModelCandidate=setLastModified(long):Parameter[this] // time is not a candidate (primitive type)
|
||||
return false;
|
||||
} // return value is not a source candidate because it's a primitive
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package java.nio.file;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.OpenOption;
|
||||
|
||||
public class Files {
|
||||
public static void copy( // method result is not a candidate source (void)
|
||||
Path source, // $ positiveSinkExample=copy(Path,OutputStream):Argument[0](path-injection) // manual model exists
|
||||
OutputStream out // $ sinkModelCandidate=copy(Path,OutputStream):Argument[1]
|
||||
/* NB: may be worthwhile to implement the
|
||||
same behavior as in application mode where out would not be a
|
||||
candidate because there already is a model for another parameter of
|
||||
the same method and we assume that methods are always modeled
|
||||
completely.
|
||||
*/
|
||||
) throws IOException {
|
||||
// ...
|
||||
}
|
||||
|
||||
public static InputStream newInputStream( // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
|
||||
Path openPath, // $ positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] // known sink, but still a candidate (ai-modeled, and useful as a candidate in regression testing)
|
||||
OpenOption... options // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[1]
|
||||
) throws IOException {
|
||||
return new FileInputStream(openPath.toFile());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
|
||||
@@ -1,13 +0,0 @@
|
||||
name: codeql/java-automodel-tests
|
||||
version: 1.0.0-dev
|
||||
groups:
|
||||
- java
|
||||
- automodel
|
||||
- test
|
||||
dependencies:
|
||||
codeql/java-all: ${workspace}
|
||||
codeql/java-automodel-queries: ${workspace}
|
||||
codeql/java-tests: ${workspace}
|
||||
extractor: java
|
||||
tests: .
|
||||
warnOnImplicitThis: true
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added taint-steps for `String.prototype.toWellFormed`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added taint-steps for `Map.groupBy` and `Object.groupBy`.
|
||||
@@ -151,4 +151,32 @@ private module CollectionDataFlow {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `groupBy` on an iterable object.
|
||||
*/
|
||||
private class GroupByTaintStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call = DataFlow::globalVarRef(["Map", "Object"]).getAMemberCall("groupBy") and
|
||||
pred = call.getArgument(0) and
|
||||
(succ = call.getCallback(1).getParameter(0) or succ = call)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for handling data flow and taint tracking for the groupBy method on iterable objects.
|
||||
* Ensures propagation of taint and data flow through the groupBy operation.
|
||||
*/
|
||||
private class GroupByDataFlowStep extends PreCallGraphStep {
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call = DataFlow::globalVarRef("Map").getAMemberCall("groupBy") and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call and
|
||||
prop = mapValueUnknownKey()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +612,7 @@ module TaintTracking {
|
||||
"italics", "link", "padEnd", "padStart", "repeat", "replace", "replaceAll", "slice",
|
||||
"small", "split", "strike", "sub", "substr", "substring", "sup",
|
||||
"toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim",
|
||||
"trimLeft", "trimRight"
|
||||
"trimLeft", "trimRight", "toWellFormed"
|
||||
]
|
||||
or
|
||||
// sorted, interesting, properties of Object.prototype
|
||||
|
||||
@@ -209,6 +209,10 @@ typeInferenceMismatch
|
||||
| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:27:14:27:22 | RegExp.$1 |
|
||||
| static-capture-groups.js:32:17:32:24 | source() | static-capture-groups.js:38:10:38:18 | RegExp.$1 |
|
||||
| static-capture-groups.js:42:12:42:19 | source() | static-capture-groups.js:43:14:43:22 | RegExp.$1 |
|
||||
| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:3:10:3:25 | x.toWellFormed() |
|
||||
| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:6:10:6:20 | wellFormedX |
|
||||
| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:9:10:9:26 | concatWellFormedX |
|
||||
| string-immutable-operations.js:11:10:11:17 | source() | string-immutable-operations.js:11:10:11:32 | source( ... ormed() |
|
||||
| string-replace.js:3:13:3:20 | source() | string-replace.js:14:10:14:13 | data |
|
||||
| string-replace.js:3:13:3:20 | source() | string-replace.js:18:10:18:13 | data |
|
||||
| string-replace.js:3:13:3:20 | source() | string-replace.js:21:6:21:41 | safe(). ... taint) |
|
||||
@@ -244,8 +248,19 @@ typeInferenceMismatch
|
||||
| tst.js:2:13:2:20 | source() | tst.js:66:10:66:16 | xSorted |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:68:10:68:23 | x.toReversed() |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:70:10:70:18 | xReversed |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:72:10:72:17 | x.with() |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:74:10:74:14 | xWith |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:72:10:72:31 | Map.gro ... z => z) |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:74:10:74:34 | Object. ... z => z) |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:78:55:78:58 | item |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:79:14:79:20 | grouped |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:100:10:100:17 | x.with() |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:102:10:102:14 | xWith |
|
||||
| tst.js:75:22:75:29 | source() | tst.js:75:10:75:52 | Map.gro ... (item)) |
|
||||
| tst.js:75:22:75:29 | source() | tst.js:75:47:75:50 | item |
|
||||
| tst.js:82:23:82:30 | source() | tst.js:83:58:83:61 | item |
|
||||
| tst.js:82:23:82:30 | source() | tst.js:84:14:84:20 | grouped |
|
||||
| tst.js:87:22:87:29 | source() | tst.js:90:14:90:25 | taintedValue |
|
||||
| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue |
|
||||
| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) |
|
||||
| xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text |
|
||||
| xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result |
|
||||
| xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr |
|
||||
|
||||
@@ -112,3 +112,5 @@
|
||||
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe |
|
||||
| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue |
|
||||
| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
function test() {
|
||||
let x = source();
|
||||
sink(x.toWellFormed()); // NOT OK
|
||||
|
||||
const wellFormedX = x.toWellFormed();
|
||||
sink(wellFormedX); // NOT OK
|
||||
|
||||
const concatWellFormedX = "/" + wellFormedX + "!";
|
||||
sink(concatWellFormedX); // NOT OK
|
||||
|
||||
sink(source().toWellFormed()); // NOT OK
|
||||
}
|
||||
@@ -69,6 +69,34 @@ function test() {
|
||||
const xReversed = x.toReversed();
|
||||
sink(xReversed) // NOT OK
|
||||
|
||||
sink(Map.groupBy(x, z => z)); // NOT OK
|
||||
sink(Custom.groupBy(x, z => z)); // OK
|
||||
sink(Object.groupBy(x, z => z)); // NOT OK
|
||||
sink(Map.groupBy(source(), (item) => sink(item))); // NOT OK
|
||||
|
||||
{
|
||||
const grouped = Map.groupBy(x, (item) => sink(item)); // NOT OK
|
||||
sink(grouped); // NOT OK
|
||||
}
|
||||
{
|
||||
const list = [source()];
|
||||
const grouped = Map.groupBy(list, (item) => sink(item)); // NOT OK
|
||||
sink(grouped); // NOT OK
|
||||
}
|
||||
{
|
||||
const data = source();
|
||||
const result = Object.groupBy(data, item => item);
|
||||
const taintedValue = result[notDefined()];
|
||||
sink(taintedValue); // NOT OK
|
||||
}
|
||||
{
|
||||
const data = source();
|
||||
const map = Map.groupBy(data, item => item);
|
||||
const taintedValue = map.get(true);
|
||||
sink(taintedValue); // NOT OK
|
||||
sink(map.get(true)); // NOT OK
|
||||
}
|
||||
|
||||
sink(x.with()) // NOT OK
|
||||
const xWith = x.with();
|
||||
sink(xWith) // NOT OK
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
testFailures
|
||||
failures
|
||||
@@ -0,0 +1,118 @@
|
||||
import threading
|
||||
import time
|
||||
|
||||
# Test 1
|
||||
# TP - Flow is tracked through a global variable
|
||||
foo1 = None
|
||||
|
||||
def bar1():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo1) # $tainted
|
||||
|
||||
# The intent of these tests is to test how dataflow is handled through shared state accessed by different threads;
|
||||
# but the presense or absense of the actual call to start a thread does not affect the results (there is no special modelling for Thread)
|
||||
# threading.Thread(target=bar).start()
|
||||
|
||||
foo1 = TAINTED_STRING
|
||||
|
||||
# Test 2
|
||||
# FN - Flow is *not* tracked through an access path on a global variable
|
||||
foo2 = []
|
||||
|
||||
def bar2():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo2[0]) # $MISSING:tainted
|
||||
|
||||
threading.Thread(target=bar2).start()
|
||||
|
||||
foo2.append(TAINTED_STRING)
|
||||
|
||||
# Test 3
|
||||
# FN - Flow is not found even when there is a direct call
|
||||
foo3 = []
|
||||
|
||||
def bar3():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo2[0]) # $MISSING:tainted
|
||||
|
||||
foo3.append(TAINTED_STRING)
|
||||
bar3()
|
||||
|
||||
# Tast 4
|
||||
# TP - Sanity check: Flow is found through a ListElement directly without a call
|
||||
foo4 = []
|
||||
foo4.append(TAINTED_STRING)
|
||||
ensure_tainted(foo4[0]) # $tainted
|
||||
|
||||
# Test 5
|
||||
# FN - Flow is *not* tracked through a shared captured but non-global variable
|
||||
def test5():
|
||||
foo5 = None
|
||||
|
||||
def bar5():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo5) # $MISSING:tainted
|
||||
|
||||
threading.Thread(target=bar5).start() # Only the presense of this thread call makes this an FN rather than a TN
|
||||
|
||||
foo5 = TAINTED_STRING
|
||||
|
||||
# Test 6
|
||||
# TP - Flow is tracked through a shared captured but non-global variable with a direct call
|
||||
def test6():
|
||||
foo6 = []
|
||||
|
||||
def bar6():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo6[0]) # $tainted
|
||||
|
||||
foo6.append(TAINTED_STRING)
|
||||
bar6()
|
||||
|
||||
|
||||
# Test 7
|
||||
# FN - Flow is *not* found through an access path on a global variable that's also used as a parameter
|
||||
# We'd like to cover this case in order to be able to cover this CVE: https://github.com/github/codeql-python-CVE-coverage/issues/3176
|
||||
|
||||
foo7 = []
|
||||
|
||||
def bar7():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo7[0]) # $MISSING: tainted
|
||||
|
||||
def baz7(loc_foo):
|
||||
loc_foo.append(TAINTED_STRING)
|
||||
|
||||
threading.Thread(target=bar7).start()
|
||||
|
||||
baz7(foo7)
|
||||
|
||||
# Test 8
|
||||
# FN - Flow is also *not* found in the above case through a direct call
|
||||
|
||||
foo8 = []
|
||||
|
||||
def bar8():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo8[0]) # $MISSING: tainted
|
||||
|
||||
def baz8(loc_foo):
|
||||
loc_foo.append(TAINTED_STRING)
|
||||
|
||||
baz8(foo8)
|
||||
bar8()
|
||||
|
||||
# Test 9
|
||||
# TP - Flow is found in the above case when the variable is captured rather than global
|
||||
|
||||
def test9():
|
||||
foo9 = []
|
||||
def bar9():
|
||||
time.sleep(1)
|
||||
ensure_tainted(foo9[0]) # $tainted
|
||||
|
||||
def baz9(loc_foo):
|
||||
loc_foo.append(TAINTED_STRING)
|
||||
|
||||
baz9(foo9)
|
||||
bar9()
|
||||
@@ -0,0 +1,3 @@
|
||||
import python
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
32
rust/ql/.generated.list
generated
32
rust/ql/.generated.list
generated
@@ -1,4 +1,4 @@
|
||||
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll f331c857a9c849ea8e3074446a2633a2dbd042e33c6ecab325f5cab91486204a 497feaf8afce895b24bc7e147199d3b9e6b2ad097f474158a220217d4d68d273
|
||||
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 4005dd5213c45c8f96e12f08d8a6a7532692d68a3cd9e3a0fd55d7f982a92f23 ec753357ac4fc76706acc0cf1d9208e63a0688e480ece52e4314d7dc2a743de5
|
||||
lib/codeql/rust/elements/Abi.qll 4c973d28b6d628f5959d1f1cc793704572fd0acaae9a97dfce82ff9d73f73476 250f68350180af080f904cd34cb2af481c5c688dc93edf7365fd0ae99855e893
|
||||
lib/codeql/rust/elements/ArgList.qll 661f5100f5d3ef8351452d9058b663a2a5c720eea8cf11bedd628969741486a2 28e424aac01a90fb58cd6f9f83c7e4cf379eea39e636bc0ba07efc818be71c71
|
||||
lib/codeql/rust/elements/ArrayExpr.qll a3e6e122632f4011644ec31b37f88b32fe3f2b7e388e7e878a6883309937049f 12ccb5873d95c433da5606fd371d182ef2f71b78d0c53c2d6dec10fa45852bdc
|
||||
@@ -41,10 +41,10 @@ lib/codeql/rust/elements/FieldList.qll bd243adc4696c60f636055a1c2da28039fe202847
|
||||
lib/codeql/rust/elements/FnPtrType.qll c4a90dc660cf620972dc23b95494f5caf9f050eabd4bdb52fdc061f8797ba9a1 f8defc91582fa503607664668f9e2e6c2cd8b320c7c449610f21e52e332a129f
|
||||
lib/codeql/rust/elements/ForExpr.qll 0cc8bfe10b8baf62a1ff65c8463cfb17ab64b41c30c9e1edb962a227df2036d9 b1be73294e6da0f49fd32177ad0b05fecf26081d5ce424f288be99a4bd59cc84
|
||||
lib/codeql/rust/elements/ForType.qll 0036bed8749358c356d78c4a0eef40d73e2796284293cde5604ae70ddd6d0470 4edcaf8f7c67d42ebe3ebb1be6a7643758717d4fe88f5f648b6a1c5ff4ee4de7
|
||||
lib/codeql/rust/elements/Format.qll 506172d176f4b965f428585c032464f4abe07a0e47c574f8e011d8641ec45370 653e81bf233b8729649064de64f4a7a8533f8864ac6d2ea913f347088c924c60
|
||||
lib/codeql/rust/elements/Format.qll 51222fa2d2e85d496ab093d74d3bc606ede3ce48f926106e059dc8478e657203 b4da6be38413c86f2e9d82004624abab16e23ef238197a5c85246009cce276d5
|
||||
lib/codeql/rust/elements/FormatArgsArg.qll 5bc9b4cd1bac7131165836e93838c45452a08ea6011741cbddace3cbf9c69440 f825140e98dc9800d5c045402186793c7b21511448e2f6bf6402d1e06305219c
|
||||
lib/codeql/rust/elements/FormatArgsExpr.qll f2ffad5a1105b29a8437c8ed6cf918cfcf4d65ac164bbf1be0585c3b673ca749 3ba20dc312a0a994bb43b37b2db72cbd4e06061b97918fa0e84ce355070ffbeb
|
||||
lib/codeql/rust/elements/FormatArgument.qll bdd93e1da78637f19beee6f953d3a45512100e925d90cb5ad08a097f412009b8 2a0ae7eb885615e380f925c0d130a1b795bf3c395486550a1f1c9c82848f8d77
|
||||
lib/codeql/rust/elements/FormatArgsExpr.qll 8127cbe4082f7acc3d8a05298c2c9bea302519b8a6cd2d158a83c516d18fc487 88cf9b3bedd69a1150968f9a465c904bbb6805da0e0b90cfd1fc0dab1f6d9319
|
||||
lib/codeql/rust/elements/FormatArgument.qll f6fe17ee1481c353dd42edae8b5fa79aeb99dff25b4842ec9a6f267b1837d1e3 5aed19c2daf2383b89ad7fd527375641cff26ddee7afddb89bc0d18d520f4034
|
||||
lib/codeql/rust/elements/FormatTemplateVariableAccess.qll ff3218a1dda30c232d0ecd9d1c60bbb9f3973456ef0bee1d1a12ad14b1e082b5 e4316291c939800d8b34d477d92be9404a30d52b7eee37302aef3d3205cf4ae0
|
||||
lib/codeql/rust/elements/Function.qll 2c76c2c7036891996b1f0ebde16c414edf37ebb44ff9c3483088dc6218733e07 d84d017d98aa240bf3bee6502a030aa8cfb7ed95425ffa9853e73b41485e1f4a
|
||||
lib/codeql/rust/elements/GenericArg.qll 5f11ce0e3c5f08de84db61f56ba1b984652455ba6b95a8b8a5b5a235913d4072 756b6a73d66fde45bdcc65ce2362a5b1391af2927e6d54b6550b3ecd5fd11e75
|
||||
@@ -452,10 +452,10 @@ lib/codeql/rust/elements/internal/generated/FieldList.qll 43c13c6e3c9ba75a7a4cb8
|
||||
lib/codeql/rust/elements/internal/generated/FnPtrType.qll 748d766dbefd19a7d644734c57885eeede66897029bbfe1b87919517f43bfde2 5a7d80acc00e56594ed85026a8ea4923104d2e98c2e42db8c5bcd32ddd164e48
|
||||
lib/codeql/rust/elements/internal/generated/ForExpr.qll d81751e9599874a1292a0aace80b2de60ab36fc43f74ec08fbdfe044fc19e5c1 34a64586f8ffbadd44d0e747f69ab550a16149b658a9c92d9593689cb9a4f6fc
|
||||
lib/codeql/rust/elements/internal/generated/ForType.qll 3d43d044a1189281f09c55caafb6c8020a836f49e2866077086101925a573cf2 646b59bfd1b428aaf7211f574c49f79cb4c6a79ca151aa0663b2b31480298721
|
||||
lib/codeql/rust/elements/internal/generated/Format.qll 37ad20cf2bf363b4027a8913d095292c8a4eb8ccdf2a9965f2fb7d41930f9bfe 329b89cdd75ce951269273dd18897e32ff5cfcc94f451001c64143386c1e48dd
|
||||
lib/codeql/rust/elements/internal/generated/Format.qll df7ef61e6ba61fa0eb093f8e6b3e7a0329104e03f659c9507db9535b8b4ea759 ef8ddd98405fc84938ad8cd5f87d2858e01d06a6bb00566a785a984b60a79dc6
|
||||
lib/codeql/rust/elements/internal/generated/FormatArgsArg.qll e07a1ae310f590003f1b88fada7dcf4847c99adb9d4c838d1c88e66e1da85c5f 0ef7342451fe2cb06e765fb4b33bb8c4a9b927f5edbc8feb5c6ba3655697f447
|
||||
lib/codeql/rust/elements/internal/generated/FormatArgsExpr.qll 40d6daa7d2bafb33798a21d79774dc802cfbd7a31618ac3bd0149399ea2bf893 d1172e2151791228559004792e125fc4625f6a26ffad25f29efb0ad263bf8795
|
||||
lib/codeql/rust/elements/internal/generated/FormatArgument.qll 00646f38217a66978b8b2648cca39dddbed22ece693b26cb682f019fbfedda95 e364e085f967847a7ed21b76156a9203d64032f0f0eea357b4779885a41bf9a7
|
||||
lib/codeql/rust/elements/internal/generated/FormatArgsExpr.qll 8aed8715a27d3af3de56ded4610c6792a25216b1544eb7e57c8b0b37c14bd9c1 590a2b0063d2ecd00bbbd1ce29603c8fd69972e34e6daddf309c915ce4ec1375
|
||||
lib/codeql/rust/elements/internal/generated/FormatArgument.qll cd05153276e63e689c95d5537fbc7d892615f62e110323759ef02e23a7587407 be2a4531b498f01625effa4c631d51ee8857698b00cfb829074120a0f2696d57
|
||||
lib/codeql/rust/elements/internal/generated/FormatTemplateVariableAccess.qll a6175214fad445df9234b3ee9bf5147da75baf82473fb8d384b455e3add0dac1 a928db0ff126b2e54a18f5c488232abd1bd6c5eda24591d3c3bb80c6ee71c770
|
||||
lib/codeql/rust/elements/internal/generated/Function.qll f285ee0c771f897eba6db34a7e98f3cfb7db91b0df252ff4b37fc9d779de0bfb 07401e832565ff376acda219514c2e2bbe4ae5058c76a73b40ca6ca66f1626c7
|
||||
lib/codeql/rust/elements/internal/generated/GenericArg.qll 464da0ba1c5ddcd1be68617167f177773d99b5ac4775ec8ea24d503e789a9099 6faa1033d59baf7c210ac4837a55781cfc054b7acbad8027faf4630dbfa6e101
|
||||
@@ -509,7 +509,7 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b
|
||||
lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60
|
||||
lib/codeql/rust/elements/internal/generated/ParenPat.qll ce24b8f8ecbf0f204af200317405724063887257460c80cf250c39b2fdf37185 e7c87d37e1a0ca7ea03840017e1aa9ddb7f927f1f3b6396c0305b46aeee33db6
|
||||
lib/codeql/rust/elements/internal/generated/ParenType.qll 9cc954d73f8330dcac7b475f97748b63af5c8766dee9d2f2872c0a7e4c903537 c07534c8a9c683c4a9b11d490095647e420de0a0bfc23273eaf6f31b00244273
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll 2237ba700c7d790cbbf7ad4d86889d22c6d210af62474ad8d363d79abb574722 36f9d47b002a241f0f793816ca9e6327fbbefb02268665553c56ded6012f82ec
|
||||
lib/codeql/rust/elements/internal/generated/ParentChild.qll 52186ab2aead10bbbaab401272afff0b8247b0050064123d0e45d972ec501dee f082318c0da678845763d6070283872b94b59425fbaa305582b5fe72da03e7e6
|
||||
lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4
|
||||
lib/codeql/rust/elements/internal/generated/Path.qll 4c1c8e840ed57880e574142b081b11d7a7428a009f10e3aa8f4645e211f6b2e0 989668cf0f1bdee7557e2f97c01e41d2a56848227fed41477833f5fc1e1d35f6
|
||||
lib/codeql/rust/elements/internal/generated/PathExpr.qll 2096e3c1db22ee488a761690adabfc9cfdea501c99f7c5d96c0019cb113fc506 54245ce0449c4e263173213df01e079d5168a758503a5dbd61b25ad35a311140
|
||||
@@ -522,7 +522,7 @@ lib/codeql/rust/elements/internal/generated/PtrType.qll 40099c5a4041314b66932dfd
|
||||
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll ea294a3ba33fd1bc632046c4fedbcb84dcb961a8e4599969d65893b19d90e590 ea294a3ba33fd1bc632046c4fedbcb84dcb961a8e4599969d65893b19d90e590
|
||||
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
|
||||
lib/codeql/rust/elements/internal/generated/RangePat.qll efd93730de217cf50dcba5875595263a5eadf9f7e4e1272401342a094d158614 229b251b3d118932e31e78ac4dfb75f48b766f240f20d436062785606d44467b
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll b534b0f2318a3a15d27cfa1d2d98ad4ef778b48edf2d36b49c56cf350a0f8328 baf18167656d407fc496ed222fcc9766030b018651f8bc4e2801a1ccbbfb29d6
|
||||
lib/codeql/rust/elements/internal/generated/Raw.qll b23d3574920376ca7c52858d6ad2ea6670640812422329f9c44f699075c16d89 13c1a199de3e71f012bdab0fa2b982f1c92f95536b07bbbe816e680a0e64ad71
|
||||
lib/codeql/rust/elements/internal/generated/RecordExpr.qll eb6cb662e463f9260efae1a6ce874fa781172063b916ef1963f861e9942d308d 1a21cbccc8f3799ff13281e822818ebfb21d81591720a427cac3625512cb9d40
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprField.qll 7e9f8663d3b74ebbc9603b10c9912f082febba6bd73d344b100bbd3edf837802 fbe6b578e7fd5d5a6f21bbb8c388957ab7210a6a249ec71510a50fb35b319ea1
|
||||
lib/codeql/rust/elements/internal/generated/RecordExprFieldList.qll 179a97211fe7aa6265085d4d54115cdbc0e1cd7c9b2135591e8f36d6432f13d3 dd44bbbc1e83a1ed3a587afb729d7debf7aeb7b63245de181726af13090e50c0
|
||||
@@ -712,13 +712,19 @@ test/extractor-tests/generated/ForExpr/ForExpr_getPat.ql 1e0205a9b3a58fd2ddba49e
|
||||
test/extractor-tests/generated/ForType/ForType.ql ba930d0c4fe52d57449ce4025b1c3e49c688afc5ef18ee8ac1ed7a9fd3eb8d41 08e9aa0301a942f6f9564ddeddc69606f3e2916e1b551cc56ae3b6048c56ce61
|
||||
test/extractor-tests/generated/ForType/ForType_getGenericParamList.ql e25cd79737bbae92d8f417c6bbf6fb8ae660976b8005cd91d0900c7076fdd827 b1e32b7e3ca9f29a4564f83e37ae53de6baf04837a393e6dedc64a01cc7d10e8
|
||||
test/extractor-tests/generated/ForType/ForType_getTy.ql e932d3412828bb83afc42e2dc1a4cbe9fcf25ec9a9617ec138722f834091a61a 298fc9df34b2cb436c8f180c4d229341ee4a73e3c451b905f017f32a6f65056c
|
||||
test/extractor-tests/generated/FormatArgsArg/FormatArgsArg.ql a521903c73f79e2616f7b8ef76790e11cbf432f8437825d52d117da232022b9e 4cb195d09ecb51e5bbd5c1c069ec1720f74fc074efc88b0f5c07cfc140167775
|
||||
test/extractor-tests/generated/FormatArgsArg/FormatArgsArg_getExpr.ql 7e1a7f902fb661660760d2a2f3f4cb6818a0c9f5b5061ede6ae80223774e4e09 8a50f64cba6f56320631206c801160201e3c98e74367bb035d689baaa9b4e411
|
||||
test/extractor-tests/generated/FormatArgsArg/FormatArgsArg_getName.ql 0e2f24388d516e14d195957163a2d5d97029c9e11a83ca71cf69e00ecc0bb2a8 dab2969f5ae6a15ec331c0152e7c116d1ee2c3d073b2d4da59ffbcb83404c65f
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr.ql 0cd439f61569ecf046e9548c458329647f331bfa034ae8b3d4f7628595881287 013a948607e1ac96100ea9a8cd3c8f357e378ac21baa015dcf4927022c2bdafb
|
||||
test/extractor-tests/generated/FormatArgsExpr/Format.ql 25268dd7ad2a58b071c3a38164944c1b7389dfdda01c99ef2694a475596341b4 0a3f674d5a4f005835b9a5ba11a6e8bf58477829258f30ae7d8f76f8986f7b7f
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg.ql a521903c73f79e2616f7b8ef76790e11cbf432f8437825d52d117da232022b9e 4cb195d09ecb51e5bbd5c1c069ec1720f74fc074efc88b0f5c07cfc140167775
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg_getExpr.ql 7e1a7f902fb661660760d2a2f3f4cb6818a0c9f5b5061ede6ae80223774e4e09 8a50f64cba6f56320631206c801160201e3c98e74367bb035d689baaa9b4e411
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg_getName.ql 0e2f24388d516e14d195957163a2d5d97029c9e11a83ca71cf69e00ecc0bb2a8 dab2969f5ae6a15ec331c0152e7c116d1ee2c3d073b2d4da59ffbcb83404c65f
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr.ql 7b6f09b23d0dffa19b8dddf7f5cfe53068f8a8e5279e235c6d54e60616bd0822 47db74f035770ce708a00355acbfd4ae99152b7eb29cf28001985806a4efe5aa
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getArg.ql 8f692486be1546b914b17abdff4a989dfbaa889bfa1fc44597f4357806c1a1dd da9fd237e31e9c8dd0ef0c3c968157815b87d3e8dcdfd74674c988ce2ab6d270
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getAttr.ql 1f9bf1344f942e65c3a3591b6ae04d3f5a2a1a65459bce0d976698de7d8a5958 02acb861d8ab4d32cf144c589881a888c3da5e2ade27e8c85fec3ae45219bb3b
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getFormat.ql 02d3fad540700966488b24c62dcf200548154a2f10f578ee2995d8c4ebe32287 cccfe779b9804c2bb968a2b1f54da8a72393805c2c8b31d7160e8538f2f335f2
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getTemplate.ql c912ac37275cbe7b3b29607bed1a3190c80779436422c14a475113e1bfd91a54 ef90f67a9b952a38ce557b1afbf0b5ce8551e83ddfaad8309a0c9523e40b5ea7
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgument.ql 7a7ee3a3322b4af8cb3b525cfed8cc9719d136ea80aa6b3fb30c7e16394dd93f 5aa8a77d7741b02f8ceb9e5991efa4c2c43c6f1624989218990e985108dae535
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatArgument_getVariable.ql 7bd4ec3dde2ef0463585794101e6cc426c368b0e4ab95fbb1f24f8f0a76cf471 e7b01e8b21df5b22c51643e2c909c6fc4ca96fda41b3290c907ba228abe8669b
|
||||
test/extractor-tests/generated/FormatArgsExpr/FormatTemplateVariableAccess.ql 2793ba1ff52182dab992d82d3767a000928f6b2fbfdb621349cafc183f0d2480 c3777d03214f7feb9020de3ce45af6556129e39e9b30d083de605b70ab9a0a12
|
||||
test/extractor-tests/generated/FormatArgsExpr/Format_getArgument.ql 26d592398a17795427b5b6b51ff4a013ee15c31443e732a000baca5f2e65acca 7940a864b84b89e84d7fb186599cb8b6bcbead7141c592b8ab0c59fcd380d5fb
|
||||
test/extractor-tests/generated/Function/Function.ql c1c2a9b68c35f839ccd2b5e62e87d1acd94dcc2a3dc4c307c269b84b2a0806e6 1c446f19d2f81dd139aa5a1578d1b165e13bddbaeab8cfee8f0430bced3a99ab
|
||||
test/extractor-tests/generated/Function/Function_getAbi.ql e5c9c97de036ddd51cae5d99d41847c35c6b2eabbbd145f4467cb501edc606d8 0b81511528bd0ef9e63b19edfc3cb638d8af43eb87d018fad69d6ef8f8221454
|
||||
test/extractor-tests/generated/Function/Function_getAttr.ql 44067ee11bdec8e91774ff10de0704a8c5c1b60816d587378e86bf3d82e1f660 b4bebf9441bda1f2d1e34e9261e07a7468cbabf53cf8047384f3c8b11869f04e
|
||||
|
||||
12
rust/ql/.gitattributes
generated
vendored
12
rust/ql/.gitattributes
generated
vendored
@@ -714,13 +714,19 @@
|
||||
/test/extractor-tests/generated/ForType/ForType.ql linguist-generated
|
||||
/test/extractor-tests/generated/ForType/ForType_getGenericParamList.ql linguist-generated
|
||||
/test/extractor-tests/generated/ForType/ForType_getTy.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsArg/FormatArgsArg.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsArg/FormatArgsArg_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsArg/FormatArgsArg_getName.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/Format.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg_getExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsArg_getName.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getArg.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getAttr.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getFormat.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getTemplate.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgument.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatArgument_getVariable.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/FormatTemplateVariableAccess.ql linguist-generated
|
||||
/test/extractor-tests/generated/FormatArgsExpr/Format_getArgument.ql linguist-generated
|
||||
/test/extractor-tests/generated/Function/Function.ql linguist-generated
|
||||
/test/extractor-tests/generated/Function/Function_getAbi.ql linguist-generated
|
||||
/test/extractor-tests/generated/Function/Function_getAttr.ql linguist-generated
|
||||
|
||||
116
rust/ql/lib/codeql/rust/Concepts.qll
Normal file
116
rust/ql/lib/codeql/rust/Concepts.qll
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Provides abstract classes representing generic concepts such as file system
|
||||
* access or system command execution, for which individual framework libraries
|
||||
* provide concrete subclasses.
|
||||
*/
|
||||
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.threatmodels.ThreatModels
|
||||
|
||||
/**
|
||||
* A data flow source for a specific threat-model.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `ThreatModelSource::Range` instead.
|
||||
*/
|
||||
final class ThreatModelSource = ThreatModelSource::Range;
|
||||
|
||||
/**
|
||||
* Provides a class for modeling new sources for specific threat-models.
|
||||
*/
|
||||
module ThreatModelSource {
|
||||
/**
|
||||
* A data flow source, for a specific threat-model.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a string that represents the source kind with respect to threat modeling.
|
||||
*
|
||||
* See
|
||||
* - https://github.com/github/codeql/blob/main/docs/codeql/reusables/threat-model-description.rst
|
||||
* - https://github.com/github/codeql/blob/main/shared/threat-models/ext/threat-model-grouping.model.yml
|
||||
*/
|
||||
abstract string getThreatModel();
|
||||
|
||||
/**
|
||||
* Gets a string that describes the type of this threat-model source.
|
||||
*/
|
||||
abstract string getSourceType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow source that is enabled in the current threat model configuration.
|
||||
*/
|
||||
class ActiveThreatModelSource extends ThreatModelSource {
|
||||
ActiveThreatModelSource() { currentThreatModel(this.getThreatModel()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that constructs a SQL statement.
|
||||
*
|
||||
* Often, it is worthy of an alert if a SQL statement is constructed such that
|
||||
* executing it would be a security risk.
|
||||
*
|
||||
* If it is important that the SQL statement is executed, use `SqlExecution`.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `SqlConstruction::Range` instead.
|
||||
*/
|
||||
final class SqlConstruction = SqlConstruction::Range;
|
||||
|
||||
/**
|
||||
* Provides a class for modeling new SQL execution APIs.
|
||||
*/
|
||||
module SqlConstruction {
|
||||
/**
|
||||
* A data-flow node that constructs a SQL statement.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the argument that specifies the SQL statements to be constructed.
|
||||
*/
|
||||
abstract DataFlow::Node getSql();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that executes SQL statements.
|
||||
*
|
||||
* If the context of interest is such that merely constructing a SQL statement
|
||||
* would be valuable to report, consider using `SqlConstruction`.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `SqlExecution::Range` instead.
|
||||
*/
|
||||
final class SqlExecution = SqlExecution::Range;
|
||||
|
||||
/**
|
||||
* Provides a class for modeling new SQL execution APIs.
|
||||
*/
|
||||
module SqlExecution {
|
||||
/**
|
||||
* A data-flow node that executes SQL statements.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the argument that specifies the SQL statements to be executed.
|
||||
*/
|
||||
abstract DataFlow::Node getSql();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that performs SQL sanitization.
|
||||
*/
|
||||
final class SqlSanitization = SqlSanitization::Range;
|
||||
|
||||
/**
|
||||
* Provides a class for modeling new SQL sanitization APIs.
|
||||
*/
|
||||
module SqlSanitization {
|
||||
/**
|
||||
* A data-flow node that performs SQL sanitization.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node { }
|
||||
}
|
||||
@@ -13,6 +13,8 @@ class AstCfgNode = CfgImpl::AstCfgNode;
|
||||
|
||||
class ExitCfgNode = CfgImpl::ExitNode;
|
||||
|
||||
class AnnotatedExitCfgNode = CfgImpl::AnnotatedExitNode;
|
||||
|
||||
/**
|
||||
* An assignment expression, for example
|
||||
*
|
||||
|
||||
@@ -894,7 +894,11 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
/**
|
||||
* A FormatArgsExpr. For example:
|
||||
* ```rust
|
||||
* todo!()
|
||||
* format_args!("no args");
|
||||
* format_args!("{} foo {:?}", 1, 2);
|
||||
* format_args!("{b} foo {a:?}", a=1, b=2);
|
||||
* let (x, y) = (1, 42);
|
||||
* format_args!("{x}, {y}");
|
||||
* ```
|
||||
*/
|
||||
final class FormatArgsExprCfgNode extends CfgNodeFinal, ExprCfgNode {
|
||||
@@ -946,6 +950,21 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
|
||||
* Holds if `getTemplate()` exists.
|
||||
*/
|
||||
predicate hasTemplate() { exists(this.getTemplate()) }
|
||||
|
||||
/**
|
||||
* Gets the `index`th format of this format arguments expression (0-based).
|
||||
*/
|
||||
Format getFormat(int index) { result = node.getFormat(index) }
|
||||
|
||||
/**
|
||||
* Gets any of the formats of this format arguments expression.
|
||||
*/
|
||||
Format getAFormat() { result = this.getFormat(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of formats of this format arguments expression.
|
||||
*/
|
||||
int getNumberOfFormats() { result = count(int i | exists(this.getFormat(i))) }
|
||||
}
|
||||
|
||||
final private class ParentFormatTemplateVariableAccess extends ParentAstNode,
|
||||
|
||||
@@ -43,22 +43,59 @@ final class DataFlowCallable extends TDataFlowCallable {
|
||||
}
|
||||
|
||||
final class DataFlowCall extends TDataFlowCall {
|
||||
private CallExprBaseCfgNode call;
|
||||
|
||||
DataFlowCall() { this = TCall(call) }
|
||||
|
||||
/** Gets the underlying call in the CFG, if any. */
|
||||
CallExprCfgNode asCallExprCfgNode() { this = TNormalCall(result) }
|
||||
CallExprCfgNode asCallExprCfgNode() { result = call }
|
||||
|
||||
MethodCallExprCfgNode asMethodCallExprCfgNode() { this = TMethodCall(result) }
|
||||
MethodCallExprCfgNode asMethodCallExprCfgNode() { result = call }
|
||||
|
||||
CallExprBaseCfgNode asExprCfgNode() {
|
||||
result = this.asCallExprCfgNode() or result = this.asMethodCallExprCfgNode()
|
||||
}
|
||||
CallExprBaseCfgNode asCallBaseExprCfgNode() { result = call }
|
||||
|
||||
DataFlowCallable getEnclosingCallable() {
|
||||
result = TCfgScope(this.asExprCfgNode().getExpr().getEnclosingCfgScope())
|
||||
result = TCfgScope(call.getExpr().getEnclosingCfgScope())
|
||||
}
|
||||
|
||||
string toString() { result = this.asExprCfgNode().toString() }
|
||||
string toString() { result = this.asCallBaseExprCfgNode().toString() }
|
||||
|
||||
Location getLocation() { result = this.asExprCfgNode().getLocation() }
|
||||
Location getLocation() { result = this.asCallBaseExprCfgNode().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The position of a parameter or an argument in a function or call.
|
||||
*
|
||||
* As there is a 1-to-1 correspondence between parameter positions and
|
||||
* arguments positions in Rust we use the same type for both.
|
||||
*/
|
||||
final class ParameterPosition extends TParameterPosition {
|
||||
/** Gets the underlying integer position, if any. */
|
||||
int getPosition() { this = TPositionalParameterPosition(result) }
|
||||
|
||||
/** Holds if this position represents the `self` position. */
|
||||
predicate isSelf() { this = TSelfParameterPosition() }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
result = this.getPosition().toString()
|
||||
or
|
||||
result = "self" and this.isSelf()
|
||||
}
|
||||
|
||||
AstNode getParameterIn(ParamList ps) {
|
||||
result = ps.getParam(this.getPosition())
|
||||
or
|
||||
result = ps.getSelfParam() and this.isSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an argument of `call` at the position `pos`. */
|
||||
private predicate isArgumentForCall(ExprCfgNode arg, CallExprBaseCfgNode call, ParameterPosition pos) {
|
||||
arg = call.getArgument(pos.getPosition())
|
||||
or
|
||||
// The self argument in a method call.
|
||||
arg = call.(MethodCallExprCfgNode).getReceiver() and pos.isSelf()
|
||||
}
|
||||
|
||||
module Node {
|
||||
@@ -93,11 +130,6 @@ module Node {
|
||||
* Gets this node's underlying SSA definition, if any.
|
||||
*/
|
||||
Ssa::Definition asDefinition() { none() }
|
||||
|
||||
/**
|
||||
* Gets the parameter that corresponds to this node, if any.
|
||||
*/
|
||||
Param asParameter() { none() }
|
||||
}
|
||||
|
||||
/** A node type that is not implemented. */
|
||||
@@ -111,7 +143,7 @@ module Node {
|
||||
override Location getLocation() { none() }
|
||||
}
|
||||
|
||||
/** A data flow node that corresponds to a CFG node for an AST node. */
|
||||
/** A data flow node that corresponds directly to a CFG node for an AST node. */
|
||||
abstract class AstCfgFlowNode extends Node {
|
||||
AstCfgNode n;
|
||||
|
||||
@@ -145,24 +177,37 @@ module Node {
|
||||
|
||||
PatNode() { this = TPatNode(n) }
|
||||
|
||||
/** Gets the `Pat` in the AST that this node corresponds to. */
|
||||
Pat getPat() { result = n.getPat() }
|
||||
/** Gets the `PatCfgNode` in the CFG that this node corresponds to. */
|
||||
PatCfgNode getPat() { result = n }
|
||||
}
|
||||
|
||||
abstract class ParameterNode extends AstCfgFlowNode { }
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
final class ParameterNode extends AstCfgFlowNode, TParameterNode {
|
||||
final class PositionalParameterNode extends ParameterNode, TParameterNode {
|
||||
override ParamCfgNode n;
|
||||
|
||||
ParameterNode() { this = TParameterNode(n) }
|
||||
PositionalParameterNode() { this = TParameterNode(n) }
|
||||
|
||||
/** Gets the parameter in the CFG that this node corresponds to. */
|
||||
ParamCfgNode getParameter() { result = n }
|
||||
}
|
||||
|
||||
final class ArgumentNode = NaNode;
|
||||
final class SelfParameterNode extends ParameterNode, TSelfParameterNode {
|
||||
override SelfParamCfgNode n;
|
||||
|
||||
SelfParameterNode() { this = TSelfParameterNode(n) }
|
||||
|
||||
/** Gets the self parameter in the AST that this node corresponds to. */
|
||||
SelfParamCfgNode getSelfParameter() { result = n }
|
||||
}
|
||||
|
||||
final class ArgumentNode extends ExprNode {
|
||||
ArgumentNode() { isArgumentForCall(n, _, _) }
|
||||
}
|
||||
|
||||
/** An SSA node. */
|
||||
class SsaNode extends Node, TSsaNode {
|
||||
@@ -185,7 +230,7 @@ module Node {
|
||||
|
||||
/** A data flow node that represents a value returned by a callable. */
|
||||
final class ReturnNode extends ExprNode {
|
||||
ReturnNode() { this.getCfgNode().getASuccessor() instanceof ExitCfgNode }
|
||||
ReturnNode() { this.getCfgNode().getASuccessor() instanceof AnnotatedExitCfgNode }
|
||||
|
||||
ReturnKind getKind() { any() }
|
||||
}
|
||||
@@ -197,10 +242,10 @@ module Node {
|
||||
}
|
||||
|
||||
final private class ExprOutNode extends ExprNode, OutNode {
|
||||
ExprOutNode() { this.asExpr() instanceof CallExprCfgNode }
|
||||
ExprOutNode() { this.asExpr() instanceof CallExprBaseCfgNode }
|
||||
|
||||
/** Gets the underlying call CFG node that includes this out node. */
|
||||
override DataFlowCall getCall() { result.asExprCfgNode() = this.getCfgNode() }
|
||||
override DataFlowCall getCall() { result.asCallBaseExprCfgNode() = this.getCfgNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,9 +259,19 @@ module Node {
|
||||
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
|
||||
* to the value before the update.
|
||||
*/
|
||||
final class PostUpdateNode extends Node::NaNode {
|
||||
final class PostUpdateNode extends Node, TArgumentPostUpdateNode {
|
||||
private ExprCfgNode n;
|
||||
|
||||
PostUpdateNode() { this = TArgumentPostUpdateNode(n) }
|
||||
|
||||
/** Gets the node before the state update. */
|
||||
Node getPreUpdateNode() { none() }
|
||||
Node getPreUpdateNode() { result = TExprNode(n) }
|
||||
|
||||
final override CfgScope getCfgScope() { result = n.getScope() }
|
||||
|
||||
final override Location getLocation() { result = n.getLocation() }
|
||||
|
||||
final override string toString() { result = n.toString() }
|
||||
}
|
||||
|
||||
final class CastNode = NaNode;
|
||||
@@ -226,25 +281,27 @@ final class Node = Node::Node;
|
||||
|
||||
/** Provides logic related to SSA. */
|
||||
module SsaFlow {
|
||||
private module Impl = SsaImpl::DataFlowIntegration;
|
||||
private module SsaFlow = SsaImpl::DataFlowIntegration;
|
||||
|
||||
private Node::ParameterNode toParameterNode(ParamCfgNode p) { result.getParameter() = p }
|
||||
private Node::ParameterNode toParameterNode(ParamCfgNode p) {
|
||||
result.(Node::PositionalParameterNode).getParameter() = p
|
||||
}
|
||||
|
||||
/** Converts a control flow node into an SSA control flow node. */
|
||||
Impl::Node asNode(Node n) {
|
||||
SsaFlow::Node asNode(Node n) {
|
||||
n = TSsaNode(result)
|
||||
or
|
||||
result.(Impl::ExprNode).getExpr() = n.asExpr()
|
||||
result.(SsaFlow::ExprNode).getExpr() = n.asExpr()
|
||||
or
|
||||
n = toParameterNode(result.(Impl::ParameterNode).getParameter())
|
||||
n = toParameterNode(result.(SsaFlow::ParameterNode).getParameter())
|
||||
}
|
||||
|
||||
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
SsaFlow::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
SsaFlow::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +333,9 @@ module LocalFlow {
|
||||
nodeFrom.(Node::AstCfgFlowNode).getCfgNode() =
|
||||
nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode()
|
||||
or
|
||||
nodeFrom.(Node::PositionalParameterNode).getParameter().getPat() =
|
||||
nodeTo.(Node::PatNode).getPat()
|
||||
or
|
||||
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
|
||||
or
|
||||
exists(AssignmentExprCfgNode a |
|
||||
@@ -291,6 +351,8 @@ private class ReturnKindAlias = ReturnKind;
|
||||
|
||||
private class DataFlowCallAlias = DataFlowCall;
|
||||
|
||||
private class ParameterPositionAlias = ParameterPosition;
|
||||
|
||||
module RustDataFlow implements InputSig<Location> {
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an expression
|
||||
@@ -310,9 +372,15 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
final class CastNode = Node::NaNode;
|
||||
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) { none() }
|
||||
/** Holds if `p` is a parameter of `c` at the position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.getCfgNode().getAstNode() = pos.getParameterIn(c.asCfgScope().(Callable).getParamList())
|
||||
}
|
||||
|
||||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { none() }
|
||||
/** Holds if `n` is an argument of `c` at the position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentForCall(n.getCfgNode(), call.asCallBaseExprCfgNode(), pos)
|
||||
}
|
||||
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node node) { result = node.getEnclosingCallable() }
|
||||
|
||||
@@ -335,10 +403,9 @@ module RustDataFlow implements InputSig<Location> {
|
||||
DataFlowCallable viableCallable(DataFlowCall c) {
|
||||
exists(Function f, string name | result.asCfgScope() = f and name = f.getName().toString() |
|
||||
if f.getParamList().hasSelfParam()
|
||||
then name = c.asMethodCallExprCfgNode().getMethodCallExpr().getNameRef().getText()
|
||||
then name = c.asMethodCallExprCfgNode().getNameRef().getText()
|
||||
else
|
||||
name =
|
||||
c.asCallExprCfgNode().getCallExpr().getExpr().(PathExpr).getPath().getPart().toString()
|
||||
name = c.asCallExprCfgNode().getExpr().getExpr().(PathExpr).getPath().getPart().toString()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -377,19 +444,15 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
ContentApprox getContentApprox(Content c) { any() }
|
||||
|
||||
class ParameterPosition extends string {
|
||||
ParameterPosition() { this = "pos" }
|
||||
}
|
||||
class ParameterPosition = ParameterPositionAlias;
|
||||
|
||||
class ArgumentPosition extends string {
|
||||
ArgumentPosition() { this = "pos" }
|
||||
}
|
||||
class ArgumentPosition = ParameterPosition;
|
||||
|
||||
/**
|
||||
* Holds if the parameter position `ppos` matches the argument position
|
||||
* `apos`.
|
||||
*/
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { none() }
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if there is a simple local flow step from `node1` to `node2`. These
|
||||
@@ -497,13 +560,13 @@ private module Cached {
|
||||
newtype TNode =
|
||||
TExprNode(ExprCfgNode n) or
|
||||
TParameterNode(ParamCfgNode p) or
|
||||
TSelfParameterNode(SelfParamCfgNode p) or
|
||||
TPatNode(PatCfgNode p) or
|
||||
TArgumentPostUpdateNode(ExprCfgNode e) { isArgumentForCall(e, _, _) } or
|
||||
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)
|
||||
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallExprCfgNode c) or
|
||||
TMethodCall(MethodCallExprCfgNode c)
|
||||
newtype TDataFlowCall = TCall(CallExprBaseCfgNode c)
|
||||
|
||||
cached
|
||||
newtype TOptionalContentSet =
|
||||
@@ -521,6 +584,13 @@ private module Cached {
|
||||
predicate localFlowStepImpl(Node::Node nodeFrom, Node::Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TParameterPosition =
|
||||
TPositionalParameterPosition(int i) {
|
||||
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
|
||||
} or
|
||||
TSelfParameterPosition()
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
1
rust/ql/lib/codeql/rust/elements/Format.qll
generated
1
rust/ql/lib/codeql/rust/elements/Format.qll
generated
@@ -5,6 +5,7 @@
|
||||
|
||||
private import internal.FormatImpl
|
||||
import codeql.rust.elements.FormatArgsExpr
|
||||
import codeql.rust.elements.FormatArgument
|
||||
import codeql.rust.elements.Locatable
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,12 +6,17 @@
|
||||
private import internal.FormatArgsExprImpl
|
||||
import codeql.rust.elements.Attr
|
||||
import codeql.rust.elements.Expr
|
||||
import codeql.rust.elements.Format
|
||||
import codeql.rust.elements.FormatArgsArg
|
||||
|
||||
/**
|
||||
* A FormatArgsExpr. For example:
|
||||
* ```rust
|
||||
* todo!()
|
||||
* format_args!("no args");
|
||||
* format_args!("{} foo {:?}", 1, 2);
|
||||
* format_args!("{b} foo {a:?}", a=1, b=2);
|
||||
* let (x, y) = (1, 42);
|
||||
* format_args!("{x}, {y}");
|
||||
* ```
|
||||
*/
|
||||
final class FormatArgsExpr = Impl::FormatArgsExpr;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
private import internal.FormatArgumentImpl
|
||||
import codeql.rust.elements.Format
|
||||
import codeql.rust.elements.FormatTemplateVariableAccess
|
||||
import codeql.rust.elements.Locatable
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,14 +16,15 @@ module Impl {
|
||||
/**
|
||||
* A FormatArgsExpr. For example:
|
||||
* ```rust
|
||||
* todo!()
|
||||
* format_args!("no args");
|
||||
* format_args!("{} foo {:?}", 1, 2);
|
||||
* format_args!("{b} foo {a:?}", a=1, b=2);
|
||||
* let (x, y) = (1, 42);
|
||||
* format_args!("{x}, {y}");
|
||||
* ```
|
||||
*/
|
||||
class FormatArgsExpr extends Generated::FormatArgsExpr {
|
||||
/**
|
||||
* Gets the `index`th format of this `FormatArgsExpr`'s formatting template (0-based).
|
||||
*/
|
||||
Format getFormat(int index) {
|
||||
override Format getFormat(int index) {
|
||||
result =
|
||||
rank[index + 1](Format f, int i | f.getParent() = this and f.getIndex() = i | f order by i)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ module Impl {
|
||||
override string toString() { result = name }
|
||||
|
||||
override Format getParent() { result = Synth::TFormat(parent, index, _, _) }
|
||||
|
||||
override FormatTemplateVariableAccess getVariable() { result.getArgument() = this }
|
||||
}
|
||||
|
||||
private class FormatSynthLocationImpl extends FormatArgument, LocatableImpl::SynthLocatable {
|
||||
|
||||
@@ -38,6 +38,8 @@ module Impl {
|
||||
|
||||
override int getIndex() { result = index }
|
||||
|
||||
override FormatArgument getArgument() { result.getParent() = this }
|
||||
|
||||
/**
|
||||
* Gets the name or position reference of this format, if any. For example `name` and `0` in:
|
||||
* ```rust
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.FormatArgsExpr
|
||||
import codeql.rust.elements.FormatArgument
|
||||
import codeql.rust.elements.internal.LocatableImpl::Impl as LocatableImpl
|
||||
|
||||
/**
|
||||
@@ -34,5 +35,15 @@ module Generated {
|
||||
* Gets the index of this format.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
|
||||
/**
|
||||
* Gets the argument of this format, if it exists.
|
||||
*/
|
||||
FormatArgument getArgument() { none() }
|
||||
|
||||
/**
|
||||
* Holds if `getArgument()` exists.
|
||||
*/
|
||||
final predicate hasArgument() { exists(this.getArgument()) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.Attr
|
||||
import codeql.rust.elements.Expr
|
||||
import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
|
||||
import codeql.rust.elements.Format
|
||||
import codeql.rust.elements.FormatArgsArg
|
||||
|
||||
/**
|
||||
@@ -19,7 +20,11 @@ module Generated {
|
||||
/**
|
||||
* A FormatArgsExpr. For example:
|
||||
* ```rust
|
||||
* todo!()
|
||||
* format_args!("no args");
|
||||
* format_args!("{} foo {:?}", 1, 2);
|
||||
* format_args!("{b} foo {a:?}", a=1, b=2);
|
||||
* let (x, y) = (1, 42);
|
||||
* format_args!("{x}, {y}");
|
||||
* ```
|
||||
* INTERNAL: Do not reference the `Generated::FormatArgsExpr` class directly.
|
||||
* Use the subclass `FormatArgsExpr`, where the following predicates are available.
|
||||
@@ -81,5 +86,20 @@ module Generated {
|
||||
* Holds if `getTemplate()` exists.
|
||||
*/
|
||||
final predicate hasTemplate() { exists(this.getTemplate()) }
|
||||
|
||||
/**
|
||||
* Gets the `index`th format of this format arguments expression (0-based).
|
||||
*/
|
||||
Format getFormat(int index) { none() }
|
||||
|
||||
/**
|
||||
* Gets any of the formats of this format arguments expression.
|
||||
*/
|
||||
final Format getAFormat() { result = this.getFormat(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of formats of this format arguments expression.
|
||||
*/
|
||||
final int getNumberOfFormats() { result = count(int i | exists(this.getFormat(i))) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
import codeql.rust.elements.Format
|
||||
import codeql.rust.elements.FormatTemplateVariableAccess
|
||||
import codeql.rust.elements.internal.LocatableImpl::Impl as LocatableImpl
|
||||
|
||||
/**
|
||||
@@ -33,5 +34,15 @@ module Generated {
|
||||
* Gets the parent of this format argument.
|
||||
*/
|
||||
Format getParent() { none() }
|
||||
|
||||
/**
|
||||
* Gets the variable of this format argument, if it exists.
|
||||
*/
|
||||
FormatTemplateVariableAccess getVariable() { none() }
|
||||
|
||||
/**
|
||||
* Holds if `getVariable()` exists.
|
||||
*/
|
||||
final predicate hasVariable() { exists(this.getVariable()) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +52,17 @@ private module Impl {
|
||||
}
|
||||
|
||||
private Element getImmediateChildOfFormat(Format e, int index, string partialPredicateCall) {
|
||||
exists(int b, int bLocatable, int n |
|
||||
exists(int b, int bLocatable, int n, int nArgument |
|
||||
b = 0 and
|
||||
bLocatable = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfLocatable(e, i, _)) | i) and
|
||||
n = bLocatable and
|
||||
nArgument = n + 1 and
|
||||
(
|
||||
none()
|
||||
or
|
||||
result = getImmediateChildOfLocatable(e, index - b, partialPredicateCall)
|
||||
or
|
||||
index = n and result = e.getArgument() and partialPredicateCall = "Argument()"
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -67,14 +70,17 @@ private module Impl {
|
||||
private Element getImmediateChildOfFormatArgument(
|
||||
FormatArgument e, int index, string partialPredicateCall
|
||||
) {
|
||||
exists(int b, int bLocatable, int n |
|
||||
exists(int b, int bLocatable, int n, int nVariable |
|
||||
b = 0 and
|
||||
bLocatable = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfLocatable(e, i, _)) | i) and
|
||||
n = bLocatable and
|
||||
nVariable = n + 1 and
|
||||
(
|
||||
none()
|
||||
or
|
||||
result = getImmediateChildOfLocatable(e, index - b, partialPredicateCall)
|
||||
or
|
||||
index = n and result = e.getVariable() and partialPredicateCall = "Variable()"
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1709,13 +1715,14 @@ private module Impl {
|
||||
private Element getImmediateChildOfFormatArgsExpr(
|
||||
FormatArgsExpr e, int index, string partialPredicateCall
|
||||
) {
|
||||
exists(int b, int bExpr, int n, int nArg, int nAttr, int nTemplate |
|
||||
exists(int b, int bExpr, int n, int nArg, int nAttr, int nTemplate, int nFormat |
|
||||
b = 0 and
|
||||
bExpr = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfExpr(e, i, _)) | i) and
|
||||
n = bExpr and
|
||||
nArg = n + 1 + max(int i | i = -1 or exists(e.getArg(i)) | i) and
|
||||
nAttr = nArg + 1 + max(int i | i = -1 or exists(e.getAttr(i)) | i) and
|
||||
nTemplate = nAttr + 1 and
|
||||
nFormat = nTemplate + 1 + max(int i | i = -1 or exists(e.getFormat(i)) | i) and
|
||||
(
|
||||
none()
|
||||
or
|
||||
@@ -1728,6 +1735,9 @@ private module Impl {
|
||||
partialPredicateCall = "Attr(" + (index - nArg).toString() + ")"
|
||||
or
|
||||
index = nAttr and result = e.getTemplate() and partialPredicateCall = "Template()"
|
||||
or
|
||||
result = e.getFormat(index - nTemplate) and
|
||||
partialPredicateCall = "Format(" + (index - nTemplate).toString() + ")"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1782,7 +1782,11 @@ module Raw {
|
||||
* INTERNAL: Do not use.
|
||||
* A FormatArgsExpr. For example:
|
||||
* ```rust
|
||||
* todo!()
|
||||
* format_args!("no args");
|
||||
* format_args!("{} foo {:?}", 1, 2);
|
||||
* format_args!("{b} foo {a:?}", a=1, b=2);
|
||||
* let (x, y) = (1, 42);
|
||||
* format_args!("{x}, {y}");
|
||||
* ```
|
||||
*/
|
||||
class FormatArgsExpr extends @format_args_expr, Expr {
|
||||
|
||||
50
rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll
Normal file
50
rust/ql/lib/codeql/rust/security/SqlInjectionExtensions.qll
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about database
|
||||
* queries built from user-controlled sources (that is, SQL injection
|
||||
* vulnerabilities).
|
||||
*/
|
||||
|
||||
import rust
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and barriers for detecting SQL injection
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module SqlInjection {
|
||||
/**
|
||||
* A data flow source for SQL injection vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for SQL injection vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A barrier for SQL injection vulnerabilities.
|
||||
*/
|
||||
abstract class Barrier extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* An active threat-model source, considered as a flow source.
|
||||
*/
|
||||
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A flow sink that is the statement of an SQL construction.
|
||||
*/
|
||||
class SqlConstructionAsSink extends Sink {
|
||||
SqlConstructionAsSink() { this = any(SqlConstruction c).getSql() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow sink that is the statement of an SQL execution.
|
||||
*/
|
||||
class SqlExecutionAsSink extends Sink {
|
||||
SqlExecutionAsSink() { this = any(SqlExecution e).getSql() }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ dependencies:
|
||||
codeql/controlflow: ${workspace}
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/regex: ${workspace}
|
||||
codeql/threat-models: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
|
||||
39
rust/ql/src/queries/security/CWE-089/SqlInjection.qhelp
Normal file
39
rust/ql/src/queries/security/CWE-089/SqlInjection.qhelp
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
|
||||
<p>
|
||||
If a database query (such as an SQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. An attacker can craft the part of the query they control to change the overall meaning of the query.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Most database connector libraries offer a way to safely embed untrusted data into a query using query parameters or prepared statements. You should use these features to build queries, rather than string concatenation or similar methods. You can also escape (sanitize) user-controlled strings so that they can be included directly in an SQL command. A library function should be used for escaping, because this approach is only safe if the escaping function is robust against all possible inputs.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
In the following examples, an SQL query is prepared using string formatting to directly include a user-controlled value <code>remote_controlled_string</code>. An attacker could craft <code>remote_controlled_string</code> to change the overall meaning of the SQL query.
|
||||
</p>
|
||||
|
||||
<sample src="SqlInjectionBad.rs" />
|
||||
|
||||
<p>A better way to do this is with a prepared statement, binding <code>remote_controlled_string</code> to a parameter of that statement. An attacker who controls <code>remote_controlled_string</code> now cannot change the overall meaning of the query.
|
||||
</p>
|
||||
|
||||
<sample src="SqlInjectionGood.rs" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/SQL_injection">SQL injection</a>.</li>
|
||||
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html">SQL Injection Prevention Cheat Sheet</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
35
rust/ql/src/queries/security/CWE-089/SqlInjection.ql
Normal file
35
rust/ql/src/queries/security/CWE-089/SqlInjection.ql
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @name Database query built from user-controlled sources
|
||||
* @description Building a database query from user-controlled sources is vulnerable to insertion of malicious code by attackers.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 8.8
|
||||
* @precision high
|
||||
* @id rust/sql-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import rust
|
||||
import codeql.rust.dataflow.DataFlow
|
||||
import codeql.rust.dataflow.TaintTracking
|
||||
import codeql.rust.security.SqlInjectionExtensions
|
||||
import SqlInjectionFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A taint configuration for tainted data that reaches a SQL sink.
|
||||
*/
|
||||
module SqlInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node instanceof SqlInjection::Source }
|
||||
|
||||
predicate isSink(DataFlow::Node node) { node instanceof SqlInjection::Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof SqlInjection::Barrier }
|
||||
}
|
||||
|
||||
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;
|
||||
|
||||
from SqlInjectionFlow::PathNode sourceNode, SqlInjectionFlow::PathNode sinkNode
|
||||
where SqlInjectionFlow::flowPath(sourceNode, sinkNode)
|
||||
select sinkNode.getNode(), sourceNode, sinkNode, "This query depends on a $@.",
|
||||
sourceNode.getNode(), "user-provided value"
|
||||
7
rust/ql/src/queries/security/CWE-089/SqlInjectionBad.rs
Normal file
7
rust/ql/src/queries/security/CWE-089/SqlInjectionBad.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// with SQLx
|
||||
|
||||
let unsafe_query = format!("SELECT * FROM people WHERE firstname='{remote_controlled_string}'");
|
||||
|
||||
let _ = conn.execute(unsafe_query.as_str()).await?; // BAD (arbitrary SQL injection is possible)
|
||||
|
||||
let _ = sqlx::query(unsafe_query.as_str()).fetch_all(&mut conn).await?; // BAD (arbitrary SQL injection is possible)
|
||||
5
rust/ql/src/queries/security/CWE-089/SqlInjectionGood.rs
Normal file
5
rust/ql/src/queries/security/CWE-089/SqlInjectionGood.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// with SQLx
|
||||
|
||||
let prepared_query = "SELECT * FROM people WHERE firstname=?";
|
||||
|
||||
let _ = sqlx::query(prepared_query_1).bind(&remote_controlled_string).fetch_all(&mut conn).await?; // GOOD (prepared statement with bound parameter)
|
||||
@@ -31,8 +31,10 @@ FieldExpr/gen_field_expr.rs 9a70500d592e0a071b03d974a55558b3bc0df531ff11bce5898f
|
||||
FnPtrType/gen_fn_ptr_type.rs a7842d8c21636739d1be959e5ce5e0b23482d5ef6eab5c45b009895da8175932 a7842d8c21636739d1be959e5ce5e0b23482d5ef6eab5c45b009895da8175932
|
||||
ForExpr/gen_for_expr.rs 67decf3073e1a9363d9df05a5a64a6059349e50b81356f480f7aeb352189136d 67decf3073e1a9363d9df05a5a64a6059349e50b81356f480f7aeb352189136d
|
||||
ForType/gen_for_type.rs 6cb447df02c61b192e283e019576c28225added02d167030d64ebd0bebb1b158 6cb447df02c61b192e283e019576c28225added02d167030d64ebd0bebb1b158
|
||||
FormatArgsArg/gen_format_args_arg.rs c466f2fc2c0f9592061a159a217a87551d67f1ccb0e4d8f7f56a463a2aa4a73a c466f2fc2c0f9592061a159a217a87551d67f1ccb0e4d8f7f56a463a2aa4a73a
|
||||
FormatArgsExpr/gen_format_args_expr.rs 7184dbb8833f970676e59fca3a40ec51d14a68e3151d8a6d637896494f2b4454 7184dbb8833f970676e59fca3a40ec51d14a68e3151d8a6d637896494f2b4454
|
||||
FormatArgsExpr/gen_format.rs bd009cb152c35e2aacd147b5520a42be31e66e9a8715ec1d0fd57b8e97c743ed bd009cb152c35e2aacd147b5520a42be31e66e9a8715ec1d0fd57b8e97c743ed
|
||||
FormatArgsExpr/gen_format_args_arg.rs c466f2fc2c0f9592061a159a217a87551d67f1ccb0e4d8f7f56a463a2aa4a73a c466f2fc2c0f9592061a159a217a87551d67f1ccb0e4d8f7f56a463a2aa4a73a
|
||||
FormatArgsExpr/gen_format_args_expr.rs 72c806ed163e9dcce2d0c5c8664d409b2aa635c1022c91959f9e8ae084f05bf2 72c806ed163e9dcce2d0c5c8664d409b2aa635c1022c91959f9e8ae084f05bf2
|
||||
FormatArgsExpr/gen_format_argument.rs 350d370e6f1db03d756384a3dbdb294697d241ff7c28d159cf57748abe99cfe9 350d370e6f1db03d756384a3dbdb294697d241ff7c28d159cf57748abe99cfe9
|
||||
Function/gen_function.rs ba6ecb9e0d89183295eb02f3c20ebbf5c209f89bd0172c73a3b4a6dacbf3a54c ba6ecb9e0d89183295eb02f3c20ebbf5c209f89bd0172c73a3b4a6dacbf3a54c
|
||||
GenericArgList/gen_generic_arg_list.rs cfb072d3b48f9dd568c23d4dfefba28766628678f66bbf9a436de9919ead35f5 cfb072d3b48f9dd568c23d4dfefba28766628678f66bbf9a436de9919ead35f5
|
||||
GenericParamList/gen_generic_param_list.rs 4cc9b628f53e1a6c5781ad195b8648fa6dee0bb41b24007fbd986527374d3669 4cc9b628f53e1a6c5781ad195b8648fa6dee0bb41b24007fbd986527374d3669
|
||||
|
||||
4
rust/ql/test/extractor-tests/generated/.gitattributes
generated
vendored
4
rust/ql/test/extractor-tests/generated/.gitattributes
generated
vendored
@@ -33,8 +33,10 @@
|
||||
/FnPtrType/gen_fn_ptr_type.rs linguist-generated
|
||||
/ForExpr/gen_for_expr.rs linguist-generated
|
||||
/ForType/gen_for_type.rs linguist-generated
|
||||
/FormatArgsArg/gen_format_args_arg.rs linguist-generated
|
||||
/FormatArgsExpr/gen_format.rs linguist-generated
|
||||
/FormatArgsExpr/gen_format_args_arg.rs linguist-generated
|
||||
/FormatArgsExpr/gen_format_args_expr.rs linguist-generated
|
||||
/FormatArgsExpr/gen_format_argument.rs linguist-generated
|
||||
/Function/gen_function.rs linguist-generated
|
||||
/GenericArgList/gen_generic_arg_list.rs linguist-generated
|
||||
/GenericParamList/gen_generic_param_list.rs linguist-generated
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
| gen_format.rs:5:21:5:22 | {} | getParent: | gen_format.rs:5:14:5:32 | FormatArgsExpr | getIndex: | 1 | hasArgument: | no |
|
||||
| gen_format_args_expr.rs:6:19:6:20 | {} | getParent: | gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | getIndex: | 1 | hasArgument: | no |
|
||||
| gen_format_args_expr.rs:6:26:6:29 | {:?} | getParent: | gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | getIndex: | 3 | hasArgument: | no |
|
||||
| gen_format_args_expr.rs:7:19:7:21 | {b} | getParent: | gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | getIndex: | 1 | hasArgument: | yes |
|
||||
| gen_format_args_expr.rs:7:27:7:31 | {a:?} | getParent: | gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | getIndex: | 3 | hasArgument: | yes |
|
||||
| gen_format_args_expr.rs:9:19:9:21 | {x} | getParent: | gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | getIndex: | 1 | hasArgument: | yes |
|
||||
| gen_format_args_expr.rs:9:24:9:26 | {y} | getParent: | gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | getIndex: | 3 | hasArgument: | yes |
|
||||
| gen_format_argument.rs:5:21:5:46 | {value:#width$.precision$} | getParent: | gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | getIndex: | 1 | hasArgument: | yes |
|
||||
| gen_format_argument.rs:7:21:7:30 | {0:#1$.2$} | getParent: | gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | getIndex: | 1 | hasArgument: | yes |
|
||||
12
rust/ql/test/extractor-tests/generated/FormatArgsExpr/Format.ql
generated
Normal file
12
rust/ql/test/extractor-tests/generated/FormatArgsExpr/Format.ql
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from Format x, FormatArgsExpr getParent, int getIndex, string hasArgument
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getParent = x.getParent() and
|
||||
getIndex = x.getIndex() and
|
||||
if x.hasArgument() then hasArgument = "yes" else hasArgument = "no"
|
||||
select x, "getParent:", getParent, "getIndex:", getIndex, "hasArgument:", hasArgument
|
||||
@@ -0,0 +1,8 @@
|
||||
| gen_format.rs:5:26:5:32 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
| gen_format_args_expr.rs:6:33:6:33 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
| gen_format_args_expr.rs:6:36:6:36 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
| gen_format_args_expr.rs:7:35:7:37 | FormatArgsArg | hasExpr: | yes | hasName: | yes |
|
||||
| gen_format_args_expr.rs:7:40:7:42 | FormatArgsArg | hasExpr: | yes | hasName: | yes |
|
||||
| gen_format_argument.rs:7:34:7:38 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
| gen_format_argument.rs:7:41:7:45 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
| gen_format_argument.rs:7:48:7:56 | FormatArgsArg | hasExpr: | yes | hasName: | no |
|
||||
@@ -0,0 +1,8 @@
|
||||
| gen_format.rs:5:26:5:32 | FormatArgsArg | gen_format.rs:5:26:5:32 | "world" |
|
||||
| gen_format_args_expr.rs:6:33:6:33 | FormatArgsArg | gen_format_args_expr.rs:6:33:6:33 | 1 |
|
||||
| gen_format_args_expr.rs:6:36:6:36 | FormatArgsArg | gen_format_args_expr.rs:6:36:6:36 | 2 |
|
||||
| gen_format_args_expr.rs:7:35:7:37 | FormatArgsArg | gen_format_args_expr.rs:7:37:7:37 | 1 |
|
||||
| gen_format_args_expr.rs:7:40:7:42 | FormatArgsArg | gen_format_args_expr.rs:7:42:7:42 | 2 |
|
||||
| gen_format_argument.rs:7:34:7:38 | FormatArgsArg | gen_format_argument.rs:7:34:7:38 | value |
|
||||
| gen_format_argument.rs:7:41:7:45 | FormatArgsArg | gen_format_argument.rs:7:41:7:45 | width |
|
||||
| gen_format_argument.rs:7:48:7:56 | FormatArgsArg | gen_format_argument.rs:7:48:7:56 | precision |
|
||||
@@ -0,0 +1,2 @@
|
||||
| gen_format_args_expr.rs:7:35:7:37 | FormatArgsArg | gen_format_args_expr.rs:7:35:7:35 | a |
|
||||
| gen_format_args_expr.rs:7:40:7:42 | FormatArgsArg | gen_format_args_expr.rs:7:40:7:40 | b |
|
||||
@@ -0,0 +1,7 @@
|
||||
| gen_format.rs:5:14:5:32 | FormatArgsExpr | getNumberOfArgs: | 1 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 1 |
|
||||
| gen_format_args_expr.rs:5:17:5:27 | FormatArgsExpr | getNumberOfArgs: | 0 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 0 |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | getNumberOfArgs: | 2 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 2 |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | getNumberOfArgs: | 2 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 2 |
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | getNumberOfArgs: | 0 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 2 |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | getNumberOfArgs: | 0 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 1 |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | getNumberOfArgs: | 3 | getNumberOfAttrs: | 0 | hasTemplate: | yes | getNumberOfFormats: | 1 |
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from FormatArgsExpr x, int getNumberOfArgs, int getNumberOfAttrs, string hasTemplate
|
||||
from
|
||||
FormatArgsExpr x, int getNumberOfArgs, int getNumberOfAttrs, string hasTemplate,
|
||||
int getNumberOfFormats
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getNumberOfArgs = x.getNumberOfArgs() and
|
||||
getNumberOfAttrs = x.getNumberOfAttrs() and
|
||||
if x.hasTemplate() then hasTemplate = "yes" else hasTemplate = "no"
|
||||
(if x.hasTemplate() then hasTemplate = "yes" else hasTemplate = "no") and
|
||||
getNumberOfFormats = x.getNumberOfFormats()
|
||||
select x, "getNumberOfArgs:", getNumberOfArgs, "getNumberOfAttrs:", getNumberOfAttrs,
|
||||
"hasTemplate:", hasTemplate
|
||||
"hasTemplate:", hasTemplate, "getNumberOfFormats:", getNumberOfFormats
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
| gen_format.rs:5:14:5:32 | FormatArgsExpr | 0 | gen_format.rs:5:26:5:32 | FormatArgsArg |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | 0 | gen_format_args_expr.rs:6:33:6:33 | FormatArgsArg |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | 1 | gen_format_args_expr.rs:6:36:6:36 | FormatArgsArg |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | 0 | gen_format_args_expr.rs:7:35:7:37 | FormatArgsArg |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | 1 | gen_format_args_expr.rs:7:40:7:42 | FormatArgsArg |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | 0 | gen_format_argument.rs:7:34:7:38 | FormatArgsArg |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | 1 | gen_format_argument.rs:7:41:7:45 | FormatArgsArg |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | 2 | gen_format_argument.rs:7:48:7:56 | FormatArgsArg |
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
| gen_format.rs:5:14:5:32 | FormatArgsExpr | 0 | gen_format.rs:5:21:5:22 | {} |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | 0 | gen_format_args_expr.rs:6:19:6:20 | {} |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | 1 | gen_format_args_expr.rs:6:26:6:29 | {:?} |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | 0 | gen_format_args_expr.rs:7:19:7:21 | {b} |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | 1 | gen_format_args_expr.rs:7:27:7:31 | {a:?} |
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | 0 | gen_format_args_expr.rs:9:19:9:21 | {x} |
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | 1 | gen_format_args_expr.rs:9:24:9:26 | {y} |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | 0 | gen_format_argument.rs:5:21:5:46 | {value:#width$.precision$} |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | 0 | gen_format_argument.rs:7:21:7:30 | {0:#1$.2$} |
|
||||
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getFormat.ql
generated
Normal file
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgsExpr_getFormat.ql
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from FormatArgsExpr x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getFormat(index)
|
||||
@@ -0,0 +1,7 @@
|
||||
| gen_format.rs:5:14:5:32 | FormatArgsExpr | gen_format.rs:5:14:5:23 | "Hello {}\\n" |
|
||||
| gen_format_args_expr.rs:5:17:5:27 | FormatArgsExpr | gen_format_args_expr.rs:5:18:5:26 | "no args" |
|
||||
| gen_format_args_expr.rs:6:17:6:37 | FormatArgsExpr | gen_format_args_expr.rs:6:18:6:30 | "{} foo {:?}" |
|
||||
| gen_format_args_expr.rs:7:17:7:43 | FormatArgsExpr | gen_format_args_expr.rs:7:18:7:32 | "{b} foo {a:?}" |
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | gen_format_args_expr.rs:9:18:9:27 | "{x}, {y}" |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | gen_format_argument.rs:5:14:5:47 | "Value {value:#width$.precision$}\\n" |
|
||||
| gen_format_argument.rs:7:14:7:56 | FormatArgsExpr | gen_format_argument.rs:7:14:7:31 | "Value {0:#1$.2$}\\n" |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | 1 | gen_format_args_expr.rs:9:20:9:20 | x |
|
||||
| gen_format_args_expr.rs:9:17:9:28 | FormatArgsExpr | 3 | gen_format_args_expr.rs:9:25:9:25 | y |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | 1 | gen_format_argument.rs:5:22:5:26 | value |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | 1 | gen_format_argument.rs:5:29:5:33 | width |
|
||||
| gen_format_argument.rs:5:14:5:47 | FormatArgsExpr | 1 | gen_format_argument.rs:5:36:5:44 | precision |
|
||||
@@ -0,0 +1,10 @@
|
||||
| gen_format_args_expr.rs:7:20:7:20 | b | getParent: | gen_format_args_expr.rs:7:19:7:21 | {b} | hasVariable: | no |
|
||||
| gen_format_args_expr.rs:7:28:7:28 | a | getParent: | gen_format_args_expr.rs:7:27:7:31 | {a:?} | hasVariable: | no |
|
||||
| gen_format_args_expr.rs:9:20:9:20 | x | getParent: | gen_format_args_expr.rs:9:19:9:21 | {x} | hasVariable: | yes |
|
||||
| gen_format_args_expr.rs:9:25:9:25 | y | getParent: | gen_format_args_expr.rs:9:24:9:26 | {y} | hasVariable: | yes |
|
||||
| gen_format_argument.rs:5:22:5:26 | value | getParent: | gen_format_argument.rs:5:21:5:46 | {value:#width$.precision$} | hasVariable: | yes |
|
||||
| gen_format_argument.rs:5:29:5:33 | width | getParent: | gen_format_argument.rs:5:21:5:46 | {value:#width$.precision$} | hasVariable: | yes |
|
||||
| gen_format_argument.rs:5:36:5:44 | precision | getParent: | gen_format_argument.rs:5:21:5:46 | {value:#width$.precision$} | hasVariable: | yes |
|
||||
| gen_format_argument.rs:7:22:7:22 | 0 | getParent: | gen_format_argument.rs:7:21:7:30 | {0:#1$.2$} | hasVariable: | no |
|
||||
| gen_format_argument.rs:7:25:7:25 | 1 | getParent: | gen_format_argument.rs:7:21:7:30 | {0:#1$.2$} | hasVariable: | no |
|
||||
| gen_format_argument.rs:7:28:7:28 | 2 | getParent: | gen_format_argument.rs:7:21:7:30 | {0:#1$.2$} | hasVariable: | no |
|
||||
11
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgument.ql
generated
Normal file
11
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgument.ql
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from FormatArgument x, Format getParent, string hasVariable
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getParent = x.getParent() and
|
||||
if x.hasVariable() then hasVariable = "yes" else hasVariable = "no"
|
||||
select x, "getParent:", getParent, "hasVariable:", hasVariable
|
||||
@@ -0,0 +1,5 @@
|
||||
| gen_format_args_expr.rs:9:20:9:20 | x | gen_format_args_expr.rs:9:20:9:20 | x |
|
||||
| gen_format_args_expr.rs:9:25:9:25 | y | gen_format_args_expr.rs:9:25:9:25 | y |
|
||||
| gen_format_argument.rs:5:22:5:26 | value | gen_format_argument.rs:5:22:5:26 | value |
|
||||
| gen_format_argument.rs:5:29:5:33 | width | gen_format_argument.rs:5:29:5:33 | width |
|
||||
| gen_format_argument.rs:5:36:5:44 | precision | gen_format_argument.rs:5:36:5:44 | precision |
|
||||
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgument_getVariable.ql
generated
Normal file
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatArgument_getVariable.ql
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from FormatArgument x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getVariable()
|
||||
@@ -0,0 +1,5 @@
|
||||
| gen_format_args_expr.rs:9:20:9:20 | x |
|
||||
| gen_format_args_expr.rs:9:25:9:25 | y |
|
||||
| gen_format_argument.rs:5:22:5:26 | value |
|
||||
| gen_format_argument.rs:5:29:5:33 | width |
|
||||
| gen_format_argument.rs:5:36:5:44 | precision |
|
||||
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatTemplateVariableAccess.ql
generated
Normal file
7
rust/ql/test/extractor-tests/generated/FormatArgsExpr/FormatTemplateVariableAccess.ql
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
// generated by codegen, do not edit
|
||||
import codeql.rust.elements
|
||||
import TestUtils
|
||||
|
||||
from FormatTemplateVariableAccess x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user