mirror of
https://github.com/github/codeql.git
synced 2026-07-07 20:45:28 +02:00
Compare commits
431 Commits
codeql-cli
...
tiferet/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
998ce38584 | ||
|
|
69974611f9 | ||
|
|
7fa039468c | ||
|
|
c35e9391ed | ||
|
|
906b922a1c | ||
|
|
5dcee41e65 | ||
|
|
4176fefe19 | ||
|
|
e71fd1691d | ||
|
|
9dae594c01 | ||
|
|
49d17f9964 | ||
|
|
a1e0f625f6 | ||
|
|
0dcd2b8765 | ||
|
|
3df95904c8 | ||
|
|
45058e2954 | ||
|
|
8c02838c38 | ||
|
|
0ab09de797 | ||
|
|
f715e2f58d | ||
|
|
20b0fc7b2c | ||
|
|
17a6c992e7 | ||
|
|
2ab175e603 | ||
|
|
4ea3887c6c | ||
|
|
9ffd984677 | ||
|
|
fbc9f4090e | ||
|
|
77f85b3a0d | ||
|
|
ddadc273a3 | ||
|
|
9685963b1c | ||
|
|
3fe67d9b86 | ||
|
|
1cf2769358 | ||
|
|
e9846c59a7 | ||
|
|
1e80a556ae | ||
|
|
68c6b59fca | ||
|
|
483cd5f795 | ||
|
|
2c941a16e1 | ||
|
|
1525c67fee | ||
|
|
9205992bd7 | ||
|
|
7a3f44b754 | ||
|
|
68aef3a791 | ||
|
|
2b8bc24bb2 | ||
|
|
794fb8995e | ||
|
|
ca32281f65 | ||
|
|
7cc2830768 | ||
|
|
878759e87a | ||
|
|
c71217ed5b | ||
|
|
27b7bbc7fd | ||
|
|
70ab280fce | ||
|
|
9b1f3ff026 | ||
|
|
3e728a7789 | ||
|
|
0f92be72b6 | ||
|
|
750ae23a79 | ||
|
|
9eda07a549 | ||
|
|
29ba00404b | ||
|
|
cf4befd670 | ||
|
|
9f74dc17fa | ||
|
|
6cf81b80cc | ||
|
|
8c56e9f7bd | ||
|
|
cf4b461c77 | ||
|
|
10faf9ae3f | ||
|
|
c5e436b4c6 | ||
|
|
d3b222988e | ||
|
|
3993ea9966 | ||
|
|
63f53eac98 | ||
|
|
afed4a058d | ||
|
|
8e4882955a | ||
|
|
467f648ea6 | ||
|
|
3009249ba9 | ||
|
|
627d5f4f8c | ||
|
|
436b790dc1 | ||
|
|
3d4e615361 | ||
|
|
193ad2345c | ||
|
|
dd82838d7a | ||
|
|
3bc1ace37d | ||
|
|
4d3bcb9d61 | ||
|
|
51973db0f3 | ||
|
|
cffae3b441 | ||
|
|
464e950166 | ||
|
|
3032a00a0a | ||
|
|
d37b5f9e1e | ||
|
|
8bd932cc82 | ||
|
|
6f7109000f | ||
|
|
fdb8e94d23 | ||
|
|
26daa1abb5 | ||
|
|
385d5cf50c | ||
|
|
2e1d733b0c | ||
|
|
fcace2a82b | ||
|
|
8643d9b4bb | ||
|
|
b530d4f440 | ||
|
|
b5f6b98706 | ||
|
|
dccddd6a93 | ||
|
|
488763cc3d | ||
|
|
c3e7161741 | ||
|
|
5bc08bad54 | ||
|
|
b11fc6005f | ||
|
|
3fde31e3cf | ||
|
|
097a1989ed | ||
|
|
6510c73e04 | ||
|
|
fd17990583 | ||
|
|
0e5a3a427a | ||
|
|
1c472a0f4a | ||
|
|
d9f174ee36 | ||
|
|
d3882552b6 | ||
|
|
77c2429269 | ||
|
|
81119f4ba1 | ||
|
|
b8942cd775 | ||
|
|
e1f639acc5 | ||
|
|
2bb034418a | ||
|
|
f32401a9c8 | ||
|
|
8b5b7af99b | ||
|
|
14c5efc9d0 | ||
|
|
aa8291e13f | ||
|
|
51b6da4183 | ||
|
|
377aa68bb3 | ||
|
|
b6a7661c7e | ||
|
|
88411ce439 | ||
|
|
533e1d818b | ||
|
|
7285704807 | ||
|
|
e895cac569 | ||
|
|
3779d8423f | ||
|
|
aa3e8d6b87 | ||
|
|
4484574301 | ||
|
|
10c222e7e2 | ||
|
|
a3c66b6032 | ||
|
|
49dccaa89d | ||
|
|
23934292f0 | ||
|
|
65c1f4a151 | ||
|
|
ba6bb79dd3 | ||
|
|
e9ffefaa96 | ||
|
|
1a876f7762 | ||
|
|
3ca04338ca | ||
|
|
c2f2a0578b | ||
|
|
219c1686fd | ||
|
|
d7325ba4e1 | ||
|
|
b410791f28 | ||
|
|
e94b492404 | ||
|
|
f976eeb909 | ||
|
|
1b128a21e6 | ||
|
|
1979a78f02 | ||
|
|
b7e36b7dec | ||
|
|
5580023ec3 | ||
|
|
1bb006f43e | ||
|
|
641f16b0df | ||
|
|
a611769b43 | ||
|
|
d61d595b21 | ||
|
|
b45c0ff848 | ||
|
|
b76e655735 | ||
|
|
ba48eaa8a6 | ||
|
|
702c22b630 | ||
|
|
f0186957ca | ||
|
|
0bfb242e63 | ||
|
|
b169f1bfdf | ||
|
|
f872a11b85 | ||
|
|
2d8d9773c4 | ||
|
|
d613bc8a28 | ||
|
|
c092851c28 | ||
|
|
2914480ff6 | ||
|
|
1cf626f712 | ||
|
|
4e60697042 | ||
|
|
83674751fc | ||
|
|
8d62d5916e | ||
|
|
672cb92fbd | ||
|
|
c44fbc1063 | ||
|
|
1caca21552 | ||
|
|
30468dd059 | ||
|
|
ab4eba11ec | ||
|
|
62f5a5dcd5 | ||
|
|
4ae8377713 | ||
|
|
78229bb264 | ||
|
|
7abc029872 | ||
|
|
9aca2d8533 | ||
|
|
c7ea08aa73 | ||
|
|
fb1a871777 | ||
|
|
09502c60d5 | ||
|
|
924ce250dd | ||
|
|
6e5f09f7bb | ||
|
|
231b0fcab2 | ||
|
|
2f268b309b | ||
|
|
ba49386e6c | ||
|
|
61aba4683f | ||
|
|
e5d89b969a | ||
|
|
f6d000eb20 | ||
|
|
0a6bb3f7ce | ||
|
|
d777fd950f | ||
|
|
99ad43b21e | ||
|
|
9d34d090ab | ||
|
|
b8c55612e5 | ||
|
|
bbb1ee9597 | ||
|
|
cb90f9af3c | ||
|
|
522a285d9e | ||
|
|
2e27447c65 | ||
|
|
e6a2528c38 | ||
|
|
49521f6de8 | ||
|
|
66f971e70d | ||
|
|
93bd2a9409 | ||
|
|
547f00c3d1 | ||
|
|
9631b6545f | ||
|
|
e0e5bb131b | ||
|
|
2579852e90 | ||
|
|
6cda285d56 | ||
|
|
8d0e3ac033 | ||
|
|
38e65ee36d | ||
|
|
f745642252 | ||
|
|
95c28967cc | ||
|
|
0c380cdd72 | ||
|
|
13ec7db1ea | ||
|
|
3c2a3abb13 | ||
|
|
03e76378ca | ||
|
|
a149c41baf | ||
|
|
bb8c3de6b2 | ||
|
|
25786f61be | ||
|
|
e4ec1ae261 | ||
|
|
88d2f65c5f | ||
|
|
cbe45f7e55 | ||
|
|
36d7370998 | ||
|
|
e65daaae49 | ||
|
|
d833850850 | ||
|
|
648f0e19ec | ||
|
|
2b41aef6a7 | ||
|
|
ea7996f1bb | ||
|
|
048fb8b953 | ||
|
|
3526b74ce7 | ||
|
|
d975ceb648 | ||
|
|
901db73d55 | ||
|
|
5272810ad9 | ||
|
|
44c1b48f94 | ||
|
|
c77cdcf4c3 | ||
|
|
ad82433a88 | ||
|
|
34d3040ce2 | ||
|
|
13b1e97caa | ||
|
|
eafef91dbc | ||
|
|
024760610a | ||
|
|
2f4a181a7d | ||
|
|
04079752f7 | ||
|
|
f87f6c8556 | ||
|
|
b728f71b4b | ||
|
|
e8e25b8e55 | ||
|
|
c7b0ae8490 | ||
|
|
518aceba64 | ||
|
|
388cb704d0 | ||
|
|
eaddb627ef | ||
|
|
73ddc0530a | ||
|
|
3687770dab | ||
|
|
ec68e91ba9 | ||
|
|
49d335695a | ||
|
|
5964daa44d | ||
|
|
a4ee35302d | ||
|
|
b3de105665 | ||
|
|
ee7d15ac5d | ||
|
|
8d5ca53126 | ||
|
|
5b8544343b | ||
|
|
5ea6cea894 | ||
|
|
fdd975b992 | ||
|
|
2a14479bf3 | ||
|
|
a87e67d89d | ||
|
|
cbe247e123 | ||
|
|
3f139bd93b | ||
|
|
edb355b47f | ||
|
|
f5702f5c69 | ||
|
|
e167d3ce00 | ||
|
|
4e49df1615 | ||
|
|
7eee589304 | ||
|
|
fa5ed04286 | ||
|
|
dba46bd324 | ||
|
|
ccb57f2a84 | ||
|
|
62dca44ee5 | ||
|
|
c250ba7f27 | ||
|
|
9db63c3a6a | ||
|
|
b0d4b31103 | ||
|
|
c7f16cd224 | ||
|
|
0d598c437d | ||
|
|
b321151a28 | ||
|
|
efb582b661 | ||
|
|
869c6d27fe | ||
|
|
74dbc71535 | ||
|
|
06bf246afe | ||
|
|
d94ed1b4a3 | ||
|
|
38826c98f1 | ||
|
|
ba982e2f85 | ||
|
|
4bca9511cd | ||
|
|
9ecba6a94d | ||
|
|
619d572d50 | ||
|
|
46da73cc11 | ||
|
|
feccd307da | ||
|
|
bfdaf6951d | ||
|
|
21414089ee | ||
|
|
8a4ca7fb84 | ||
|
|
cece307c60 | ||
|
|
f4e8656c17 | ||
|
|
352866b52d | ||
|
|
a42dbc5bab | ||
|
|
d407a689fa | ||
|
|
169bde8671 | ||
|
|
8bf4b55309 | ||
|
|
f106783c39 | ||
|
|
7b56383b52 | ||
|
|
0a26916245 | ||
|
|
77b67cbf2e | ||
|
|
0fc775027f | ||
|
|
3826b9be6c | ||
|
|
74b71ff7e3 | ||
|
|
ea54ea47b1 | ||
|
|
3e55c47e3e | ||
|
|
5ed1868324 | ||
|
|
88eb0231c1 | ||
|
|
cd661f1d9f | ||
|
|
735a7383c6 | ||
|
|
1b1838b5a8 | ||
|
|
fddbffee6f | ||
|
|
4f9c51a02b | ||
|
|
316cb95547 | ||
|
|
0e3d9e1fec | ||
|
|
8a756eced9 | ||
|
|
f0749f69c7 | ||
|
|
0db05fe4fa | ||
|
|
544997d42f | ||
|
|
523feabaa2 | ||
|
|
e648c643ca | ||
|
|
0ffe9ab8d5 | ||
|
|
f27eff4f73 | ||
|
|
8aabd28461 | ||
|
|
fde855b25f | ||
|
|
6271b6f1c3 | ||
|
|
7fb8819a08 | ||
|
|
0445509080 | ||
|
|
6890434d63 | ||
|
|
d85bcacf84 | ||
|
|
540b8391dc | ||
|
|
99320857af | ||
|
|
8a6ff95035 | ||
|
|
4daaf783e1 | ||
|
|
cd7b79f62b | ||
|
|
1afa5af3dd | ||
|
|
a9595647c4 | ||
|
|
33afcd75f1 | ||
|
|
2a23f8766e | ||
|
|
e89df255e3 | ||
|
|
4ab184fc7d | ||
|
|
4ed101fa26 | ||
|
|
a991f87728 | ||
|
|
68fe486c05 | ||
|
|
60dab3d779 | ||
|
|
68391acc98 | ||
|
|
de4cfc3239 | ||
|
|
a3976305ca | ||
|
|
bb75ed03da | ||
|
|
f4ee1a5119 | ||
|
|
9a62f51694 | ||
|
|
ca029f5718 | ||
|
|
5601ad64ef | ||
|
|
eb7e401aea | ||
|
|
e3cbebae30 | ||
|
|
96f9c40fdb | ||
|
|
a96ad600fc | ||
|
|
3e4e75cee8 | ||
|
|
e6be88b10e | ||
|
|
60544c6889 | ||
|
|
bdf1da340d | ||
|
|
f9d5e56d9c | ||
|
|
f32d77b36c | ||
|
|
68cdc3b48e | ||
|
|
33bc7eabbb | ||
|
|
859b3051b7 | ||
|
|
b2d4a82932 | ||
|
|
1ac5db3a98 | ||
|
|
31b71ea163 | ||
|
|
40dde93beb | ||
|
|
23a7cd943f | ||
|
|
416f8d5ac9 | ||
|
|
c76dbebd9b | ||
|
|
3cc9dec9c8 | ||
|
|
d304022685 | ||
|
|
ead8108aed | ||
|
|
e0aeea058e | ||
|
|
184cb74cd0 | ||
|
|
f46ea325e8 | ||
|
|
21b03927c5 | ||
|
|
ba4e3ae949 | ||
|
|
824ff8ad88 | ||
|
|
ffec22a5d2 | ||
|
|
d0529bba2b | ||
|
|
69cb138912 | ||
|
|
7e23bf3938 | ||
|
|
b1957623c1 | ||
|
|
ab70f5722e | ||
|
|
49cceb2901 | ||
|
|
cdcee5cc75 | ||
|
|
539f8f0f70 | ||
|
|
51a62b54ee | ||
|
|
d299d92025 | ||
|
|
4995f13234 | ||
|
|
83cd55cb29 | ||
|
|
18c3feb9d8 | ||
|
|
259d5b6452 | ||
|
|
c1960c6ff9 | ||
|
|
3c88590df2 | ||
|
|
725004a6fe | ||
|
|
17fe5f2317 | ||
|
|
a8151b4ee4 | ||
|
|
fb2ec15dad | ||
|
|
cc12e74c23 | ||
|
|
dfe00ffe4b | ||
|
|
3c4bd5b6a7 | ||
|
|
b5e90483f5 | ||
|
|
d65bb3b232 | ||
|
|
a0f4a5100f | ||
|
|
8691845d23 | ||
|
|
2ef6d5c7b9 | ||
|
|
d942b54a9d | ||
|
|
c13999100b | ||
|
|
eff4729577 | ||
|
|
e4b4d8a3cd | ||
|
|
79089b40b9 | ||
|
|
5a8a6f2971 | ||
|
|
4fca4b668c | ||
|
|
f0b5f9c928 | ||
|
|
acaa6a5ea7 | ||
|
|
a5162b0b7d | ||
|
|
915c969efe | ||
|
|
6ef9088076 | ||
|
|
e4ae957cdd | ||
|
|
5a01feca6c | ||
|
|
6c932bc807 | ||
|
|
56dc2a4d4e | ||
|
|
abc0c7cf24 | ||
|
|
a386c58371 | ||
|
|
3fc488167f | ||
|
|
ed48065c2d | ||
|
|
2606abfc64 | ||
|
|
868b2385d1 | ||
|
|
4b4fc97221 | ||
|
|
7ea74df4b3 | ||
|
|
204dbee14c | ||
|
|
0f4157c534 |
@@ -1 +1 @@
|
|||||||
5.0.0
|
6.1.2
|
||||||
|
|||||||
4
.github/workflows/go-tests-other-os.yml
vendored
4
.github/workflows/go-tests-other-os.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Set up Go 1.20
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.0
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
- name: Set up Go 1.20
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.0
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Set up Go 1.20
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.0
|
go-version: '1.20'
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
29
.github/workflows/ruby-build.yml
vendored
29
.github/workflows/ruby-build.yml
vendored
@@ -58,10 +58,8 @@ jobs:
|
|||||||
id: cache-extractor
|
id: cache-extractor
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
ruby/extractor/target/release/autobuilder
|
ruby/extractor/target/release/codeql-extractor-ruby
|
||||||
ruby/extractor/target/release/autobuilder.exe
|
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||||
ruby/extractor/target/release/extractor
|
|
||||||
ruby/extractor/target/release/extractor.exe
|
|
||||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
@@ -88,15 +86,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd extractor
|
cd extractor
|
||||||
cross build --release
|
cross build --release
|
||||||
mv target/x86_64-unknown-linux-gnu/release/extractor target/release/
|
mv target/x86_64-unknown-linux-gnu/release/codeql-extractor-ruby target/release/
|
||||||
mv target/x86_64-unknown-linux-gnu/release/autobuilder target/release/
|
|
||||||
mv target/x86_64-unknown-linux-gnu/release/generator target/release/
|
|
||||||
- name: Release build (windows and macos)
|
- name: Release build (windows and macos)
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && runner.os != 'Linux'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && runner.os != 'Linux'
|
||||||
run: cd extractor && cargo build --release
|
run: cd extractor && cargo build --release
|
||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
|
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
|
||||||
run: extractor/target/release/generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
run: extractor/target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
with:
|
with:
|
||||||
@@ -111,10 +107,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: extractor-${{ matrix.os }}
|
name: extractor-${{ matrix.os }}
|
||||||
path: |
|
path: |
|
||||||
ruby/extractor/target/release/autobuilder
|
ruby/extractor/target/release/codeql-extractor-ruby
|
||||||
ruby/extractor/target/release/autobuilder.exe
|
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||||
ruby/extractor/target/release/extractor
|
|
||||||
ruby/extractor/target/release/extractor.exe
|
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
compile-queries:
|
compile-queries:
|
||||||
runs-on: ubuntu-latest-xl
|
runs-on: ubuntu-latest-xl
|
||||||
@@ -172,13 +166,10 @@ jobs:
|
|||||||
mkdir -p ruby
|
mkdir -p ruby
|
||||||
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
|
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
|
||||||
mkdir -p ruby/tools/{linux64,osx64,win64}
|
mkdir -p ruby/tools/{linux64,osx64,win64}
|
||||||
cp linux64/autobuilder ruby/tools/linux64/autobuilder
|
cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
|
||||||
cp osx64/autobuilder ruby/tools/osx64/autobuilder
|
cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
|
||||||
cp win64/autobuilder.exe ruby/tools/win64/autobuilder.exe
|
cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
|
||||||
cp linux64/extractor ruby/tools/linux64/extractor
|
chmod +x ruby/tools/{linux64,osx64}/extractor
|
||||||
cp osx64/extractor ruby/tools/osx64/extractor
|
|
||||||
cp win64/extractor.exe ruby/tools/win64/extractor.exe
|
|
||||||
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
|
||||||
zip -rq codeql-ruby.zip ruby
|
zip -rq codeql-ruby.zip ruby
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ provide:
|
|||||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||||
- "go/ql/config/legacy-support/qlpack.yml"
|
- "go/ql/config/legacy-support/qlpack.yml"
|
||||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
||||||
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
- "*/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
||||||
# This pack is explicitly excluded from the workspace since most users
|
# This pack is explicitly excluded from the workspace since most users
|
||||||
# will want to use a version of this pack from the package cache. Internal
|
# will want to use a version of this pack from the package cache. Internal
|
||||||
# users can uncomment the following line and place a custom ML model
|
# users can uncomment the following line and place a custom ML model
|
||||||
# in the corresponding pack to test a custom ML model within their local
|
# in the corresponding pack to test a custom ML model within their local
|
||||||
# checkout.
|
# checkout.
|
||||||
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
# - "*/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||||
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
- "*/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||||
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
- "*/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||||
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
- "*/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
||||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<queries language="cpp"/>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.7.0
|
version: 0.7.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ class Location extends @location {
|
|||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
|
pragma[inline]
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -897,23 +897,6 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the basic block of `node`.
|
|
||||||
*/
|
|
||||||
IRBlock getBasicBlock(Node node) {
|
|
||||||
node.asInstruction().getBlock() = result
|
|
||||||
or
|
|
||||||
node.asOperand().getUse().getBlock() = result
|
|
||||||
or
|
|
||||||
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
|
|
||||||
or
|
|
||||||
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
|
|
||||||
or
|
|
||||||
node.(RawIndirectInstruction).getInstruction().getBlock() = result
|
|
||||||
or
|
|
||||||
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A local flow relation that includes both local steps, read steps and
|
* A local flow relation that includes both local steps, read steps and
|
||||||
* argument-to-return flow through summarized functions.
|
* argument-to-return flow through summarized functions.
|
||||||
@@ -999,7 +982,8 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
|
|||||||
// we pick the one with the highest edge count.
|
// we pick the one with the highest edge count.
|
||||||
result =
|
result =
|
||||||
max(SsaPhiNode phi |
|
max(SsaPhiNode phi |
|
||||||
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
|
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() =
|
||||||
|
phi.getBasicBlock() and
|
||||||
phi.getSourceVariable() = sv
|
phi.getSourceVariable() = sv
|
||||||
|
|
|
|
||||||
strictcount(phi.getAnInput())
|
strictcount(phi.getAnInput())
|
||||||
|
|||||||
@@ -160,6 +160,28 @@ class Node extends TIRDataFlowNode {
|
|||||||
/** Gets the operands corresponding to this node, if any. */
|
/** Gets the operands corresponding to this node, if any. */
|
||||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node is at index `i` in basic block `block`.
|
||||||
|
*
|
||||||
|
* Note: Phi nodes are considered to be at index `-1`.
|
||||||
|
*/
|
||||||
|
final predicate hasIndexInBlock(IRBlock block, int i) {
|
||||||
|
this.asInstruction() = block.getInstruction(i)
|
||||||
|
or
|
||||||
|
this.asOperand().getUse() = block.getInstruction(i)
|
||||||
|
or
|
||||||
|
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
||||||
|
or
|
||||||
|
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
||||||
|
or
|
||||||
|
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
||||||
|
or
|
||||||
|
this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the basic block of this node, if any. */
|
||||||
|
final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the non-conversion expression corresponding to this node, if any.
|
* Gets the non-conversion expression corresponding to this node, if any.
|
||||||
* This predicate only has a result on nodes that represent the value of
|
* This predicate only has a result on nodes that represent the value of
|
||||||
@@ -530,7 +552,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
*/
|
*/
|
||||||
final Node getAnInput(boolean fromBackEdge) {
|
final Node getAnInput(boolean fromBackEdge) {
|
||||||
localFlowStep(result, this) and
|
localFlowStep(result, this) and
|
||||||
if phi.getBasicBlock().dominates(getBasicBlock(result))
|
if phi.getBasicBlock().dominates(result.getBasicBlock())
|
||||||
then fromBackEdge = true
|
then fromBackEdge = true
|
||||||
else fromBackEdge = false
|
else fromBackEdge = false
|
||||||
}
|
}
|
||||||
@@ -1887,7 +1909,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||||
result.getConvertedExpr() = e and
|
result.getConvertedExpr() = e and
|
||||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||||
g.controls(getBasicBlock(result), edge)
|
g.controls(result.getBasicBlock(), edge)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,17 @@ predicate ignoreOperand(Operand operand) {
|
|||||||
predicate ignoreInstruction(Instruction instr) {
|
predicate ignoreInstruction(Instruction instr) {
|
||||||
DataFlowImplCommon::forceCachingInSameStage() and
|
DataFlowImplCommon::forceCachingInSameStage() and
|
||||||
(
|
(
|
||||||
|
instr instanceof CallSideEffectInstruction or
|
||||||
|
instr instanceof CallReadSideEffectInstruction or
|
||||||
|
instr instanceof ExitFunctionInstruction or
|
||||||
|
instr instanceof EnterFunctionInstruction or
|
||||||
instr instanceof WriteSideEffectInstruction or
|
instr instanceof WriteSideEffectInstruction or
|
||||||
instr instanceof PhiInstruction or
|
instr instanceof PhiInstruction or
|
||||||
instr instanceof ReadSideEffectInstruction or
|
instr instanceof ReadSideEffectInstruction or
|
||||||
instr instanceof ChiInstruction or
|
instr instanceof ChiInstruction or
|
||||||
instr instanceof InitializeIndirectionInstruction or
|
instr instanceof InitializeIndirectionInstruction or
|
||||||
instr instanceof AliasedDefinitionInstruction or
|
instr instanceof AliasedDefinitionInstruction or
|
||||||
|
instr instanceof AliasedUseInstruction or
|
||||||
instr instanceof InitializeNonLocalInstruction or
|
instr instanceof InitializeNonLocalInstruction or
|
||||||
instr instanceof ReturnIndirectionInstruction
|
instr instanceof ReturnIndirectionInstruction
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ private import semmle.code.cpp.ir.IR
|
|||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||||
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||||
|
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the lower bound of the expression.
|
* Gets the lower bound of the expression.
|
||||||
@@ -22,8 +24,10 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Rang
|
|||||||
* `lowerBound(expr.getFullyConverted())`
|
* `lowerBound(expr.getFullyConverted())`
|
||||||
*/
|
*/
|
||||||
float lowerBound(Expr expr) {
|
float lowerBound(Expr expr) {
|
||||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
exists(Instruction i, ConstantBounds::SemBound b |
|
||||||
semBounded(getSemanticExpr(i), b, result, false, _)
|
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
||||||
|
|
|
||||||
|
ConstantStage::semBounded(getSemanticExpr(i), b, result, false, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,8 +44,10 @@ float lowerBound(Expr expr) {
|
|||||||
* `upperBound(expr.getFullyConverted())`
|
* `upperBound(expr.getFullyConverted())`
|
||||||
*/
|
*/
|
||||||
float upperBound(Expr expr) {
|
float upperBound(Expr expr) {
|
||||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
exists(Instruction i, ConstantBounds::SemBound b |
|
||||||
semBounded(getSemanticExpr(i), b, result, true, _)
|
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
||||||
|
|
|
||||||
|
ConstantStage::semBounded(getSemanticExpr(i), b, result, true, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +96,15 @@ predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
|
|||||||
* does not consider the possibility that the expression might overflow
|
* does not consider the possibility that the expression might overflow
|
||||||
* due to a conversion.
|
* due to a conversion.
|
||||||
*/
|
*/
|
||||||
predicate exprMightOverflowNegatively(Expr expr) { none() }
|
predicate exprMightOverflowNegatively(Expr expr) {
|
||||||
|
lowerBound(expr) < exprMinVal(expr)
|
||||||
|
or
|
||||||
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
|
semExpr.getUnconverted().getAst() = expr and
|
||||||
|
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||||
|
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the expression might overflow negatively. Conversions
|
* Holds if the expression might overflow negatively. Conversions
|
||||||
@@ -108,7 +122,15 @@ predicate convertedExprMightOverflowNegatively(Expr expr) {
|
|||||||
* does not consider the possibility that the expression might overflow
|
* does not consider the possibility that the expression might overflow
|
||||||
* due to a conversion.
|
* due to a conversion.
|
||||||
*/
|
*/
|
||||||
predicate exprMightOverflowPositively(Expr expr) { none() }
|
predicate exprMightOverflowPositively(Expr expr) {
|
||||||
|
upperBound(expr) > exprMaxVal(expr)
|
||||||
|
or
|
||||||
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
|
semExpr.getUnconverted().getAst() = expr and
|
||||||
|
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||||
|
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the expression might overflow positively. Conversions
|
* Holds if the expression might overflow positively. Conversions
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
private import RangeAnalysisStage
|
private import RangeAnalysisStage
|
||||||
|
private import RangeAnalysisImpl
|
||||||
|
|
||||||
module FloatDelta implements DeltaSig {
|
module FloatDelta implements DeltaSig {
|
||||||
class Delta = float;
|
class Delta = float;
|
||||||
@@ -18,3 +19,36 @@ module FloatDelta implements DeltaSig {
|
|||||||
bindingset[f]
|
bindingset[f]
|
||||||
Delta fromFloat(float f) { result = f }
|
Delta fromFloat(float f) { result = f }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module FloatOverflow implements OverflowSig<FloatDelta> {
|
||||||
|
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr) {
|
||||||
|
exists(float lb, float ub, float delta |
|
||||||
|
typeBounds(expr.getSemType(), lb, ub) and
|
||||||
|
ConstantStage::initialBounded(expr, any(ConstantBounds::SemZeroBound b), delta, positively, _,
|
||||||
|
_, _)
|
||||||
|
|
|
||||||
|
positively = true and delta < ub
|
||||||
|
or
|
||||||
|
positively = false and delta > lb
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
additional predicate typeBounds(SemType t, float lb, float ub) {
|
||||||
|
exists(SemIntegerType integralType, float limit |
|
||||||
|
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
||||||
|
|
|
||||||
|
if integralType instanceof SemBooleanType
|
||||||
|
then lb = 0 and ub = 1
|
||||||
|
else
|
||||||
|
if integralType.isSigned()
|
||||||
|
then (
|
||||||
|
lb = -(limit / 2) and ub = (limit / 2) - 1
|
||||||
|
) else (
|
||||||
|
lb = 0 and ub = limit - 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// This covers all floating point types. The range is (-Inf, +Inf).
|
||||||
|
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
import RangeAnalysisImpl
|
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||||
|
private import RangeAnalysisImpl as Impl
|
||||||
|
import Impl::Public
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
|||||||
private import RangeAnalysisStage
|
private import RangeAnalysisStage
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
|
|
||||||
module CppLangImpl implements LangSig<FloatDelta> {
|
module CppLangImplConstant implements LangSig<FloatDelta> {
|
||||||
/**
|
/**
|
||||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||||
*
|
*
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
private import RangeAnalysisStage
|
private import RangeAnalysisStage
|
||||||
private import RangeAnalysisSpecific
|
private import RangeAnalysisConstantSpecific
|
||||||
|
private import RangeAnalysisRelativeSpecific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
private import RangeUtils
|
private import RangeUtils
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
|
||||||
@@ -28,7 +29,7 @@ module ConstantBounds implements BoundSig<FloatDelta> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module RelativeBounds implements BoundSig<FloatDelta> {
|
module RelativeBounds implements BoundSig<FloatDelta> {
|
||||||
class SemBound instanceof SemanticBound::SemBound {
|
class SemBound instanceof SemanticBound::SemBound {
|
||||||
SemBound() { not this instanceof SemanticBound::SemZeroBound }
|
SemBound() { not this instanceof SemanticBound::SemZeroBound }
|
||||||
|
|
||||||
@@ -46,11 +47,13 @@ private module RelativeBounds implements BoundSig<FloatDelta> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module ConstantStage =
|
module ConstantStage =
|
||||||
RangeStage<FloatDelta, ConstantBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
|
RangeStage<FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||||
|
RangeUtil<FloatDelta, CppLangImplConstant>>;
|
||||||
|
|
||||||
private module RelativeStage =
|
module RelativeStage =
|
||||||
RangeStage<FloatDelta, RelativeBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
|
RangeStage<FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||||
|
RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||||
|
|
||||||
private newtype TSemReason =
|
private newtype TSemReason =
|
||||||
TSemNoReason() or
|
TSemNoReason() or
|
||||||
@@ -60,48 +63,52 @@ private newtype TSemReason =
|
|||||||
guard = any(RelativeStage::SemCondReason reason).getCond()
|
guard = any(RelativeStage::SemCondReason reason).getCond()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ConstantStage::SemReason constantReason(SemReason reason) {
|
||||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
|
||||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
|
||||||
* without going through a bounding condition.
|
|
||||||
*/
|
|
||||||
abstract class SemReason extends TSemReason {
|
|
||||||
/** Gets a textual representation of this reason. */
|
|
||||||
abstract string toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A reason for an inferred bound that indicates that the bound is inferred
|
|
||||||
* without going through a bounding condition.
|
|
||||||
*/
|
|
||||||
class SemNoReason extends SemReason, TSemNoReason {
|
|
||||||
override string toString() { result = "NoReason" }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A reason for an inferred bound pointing to a condition. */
|
|
||||||
class SemCondReason extends SemReason, TSemCondReason {
|
|
||||||
/** Gets the condition that is the reason for the bound. */
|
|
||||||
SemGuard getCond() { this = TSemCondReason(result) }
|
|
||||||
|
|
||||||
override string toString() { result = getCond().toString() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConstantStage::SemReason constantReason(SemReason reason) {
|
|
||||||
result instanceof ConstantStage::SemNoReason and reason instanceof SemNoReason
|
result instanceof ConstantStage::SemNoReason and reason instanceof SemNoReason
|
||||||
or
|
or
|
||||||
result.(ConstantStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
result.(ConstantStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||||
}
|
}
|
||||||
|
|
||||||
private RelativeStage::SemReason relativeReason(SemReason reason) {
|
RelativeStage::SemReason relativeReason(SemReason reason) {
|
||||||
result instanceof RelativeStage::SemNoReason and reason instanceof SemNoReason
|
result instanceof RelativeStage::SemNoReason and reason instanceof SemNoReason
|
||||||
or
|
or
|
||||||
result.(RelativeStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
result.(RelativeStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate semBounded(
|
import Public
|
||||||
|
|
||||||
|
module Public {
|
||||||
|
predicate semBounded(
|
||||||
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
|
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
|
||||||
) {
|
) {
|
||||||
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
|
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
|
||||||
or
|
or
|
||||||
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
|
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||||
|
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||||
|
* without going through a bounding condition.
|
||||||
|
*/
|
||||||
|
abstract class SemReason extends TSemReason {
|
||||||
|
/** Gets a textual representation of this reason. */
|
||||||
|
abstract string toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reason for an inferred bound that indicates that the bound is inferred
|
||||||
|
* without going through a bounding condition.
|
||||||
|
*/
|
||||||
|
class SemNoReason extends SemReason, TSemNoReason {
|
||||||
|
override string toString() { result = "NoReason" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A reason for an inferred bound pointing to a condition. */
|
||||||
|
class SemCondReason extends SemReason, TSemCondReason {
|
||||||
|
/** Gets the condition that is the reason for the bound. */
|
||||||
|
SemGuard getCond() { this = TSemCondReason(result) }
|
||||||
|
|
||||||
|
override string toString() { result = getCond().toString() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
* C++-specific implementation of range analysis.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
|
private import RangeAnalysisStage
|
||||||
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.IntDelta
|
||||||
|
private import RangeAnalysisImpl
|
||||||
|
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||||
|
|
||||||
|
module CppLangImplRelative implements LangSig<FloatDelta> {
|
||||||
|
/**
|
||||||
|
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||||
|
*
|
||||||
|
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||||
|
* removed once we have the new implementation matching the old results exactly.
|
||||||
|
*/
|
||||||
|
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore the bound on this expression.
|
||||||
|
*
|
||||||
|
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||||
|
* removed once we have the new implementation matching the old results exactly.
|
||||||
|
*/
|
||||||
|
predicate ignoreExprBound(SemExpr e) {
|
||||||
|
exists(boolean upper, float delta, ConstantBounds::SemZeroBound b, float lb, float ub |
|
||||||
|
ConstantStage::semBounded(e, b, delta, upper, _) and
|
||||||
|
typeBounds(e.getSemType(), lb, ub) and
|
||||||
|
(
|
||||||
|
upper = false and
|
||||||
|
delta < lb
|
||||||
|
or
|
||||||
|
upper = true and
|
||||||
|
delta > ub
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate typeBounds(SemType t, float lb, float ub) {
|
||||||
|
exists(SemIntegerType integralType, float limit |
|
||||||
|
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
||||||
|
|
|
||||||
|
if integralType instanceof SemBooleanType
|
||||||
|
then lb = 0 and ub = 1
|
||||||
|
else
|
||||||
|
if integralType.isSigned()
|
||||||
|
then (
|
||||||
|
lb = -(limit / 2) and ub = (limit / 2) - 1
|
||||||
|
) else (
|
||||||
|
lb = 0 and ub = limit - 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// This covers all floating point types. The range is (-Inf, +Inf).
|
||||||
|
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore any inferred zero lower bound on this expression.
|
||||||
|
*
|
||||||
|
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||||
|
* removed once we have the new implementation matching the old results exactly.
|
||||||
|
*/
|
||||||
|
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||||
|
*
|
||||||
|
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||||
|
* removed once we have the new implementation matching the old results exactly.
|
||||||
|
*/
|
||||||
|
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||||
|
*
|
||||||
|
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||||
|
* removed once we have the new implementation matching the old results exactly.
|
||||||
|
*/
|
||||||
|
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||||
|
*
|
||||||
|
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||||
|
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||||
|
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||||
|
* or not they come from a post-increment/decrement expression.
|
||||||
|
*/
|
||||||
|
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||||
|
*/
|
||||||
|
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||||
|
*/
|
||||||
|
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the value of `dest` is known to be `src + delta`.
|
||||||
|
*/
|
||||||
|
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||||
|
* if a type other than the original type of the expression is to be used.
|
||||||
|
*
|
||||||
|
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||||
|
* actually references but whose values can be tracked as the type contained in the box.
|
||||||
|
*/
|
||||||
|
SemType getAlternateType(SemExpr e) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type that range analysis should use to track the result of the specified source
|
||||||
|
* variable, if a type other than the original type of the expression is to be used.
|
||||||
|
*
|
||||||
|
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||||
|
* actually references but whose values can be tracked as the type contained in the box.
|
||||||
|
*/
|
||||||
|
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||||
|
}
|
||||||
@@ -73,6 +73,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
|||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
|
||||||
private import ConstantAnalysis
|
private import ConstantAnalysis
|
||||||
|
private import Sign
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,11 +241,19 @@ signature module BoundSig<DeltaSig D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<D> UtilParam> {
|
signature module OverflowSig<DeltaSig D> {
|
||||||
|
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
module RangeStage<
|
||||||
|
DeltaSig D, BoundSig<D> Bounds, OverflowSig<D> OverflowParam, LangSig<D> LangParam,
|
||||||
|
UtilSig<D> UtilParam>
|
||||||
|
{
|
||||||
private import Bounds
|
private import Bounds
|
||||||
private import LangParam
|
private import LangParam
|
||||||
private import UtilParam
|
private import UtilParam
|
||||||
private import D
|
private import D
|
||||||
|
private import OverflowParam
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression that does conversion, boxing, or unboxing
|
* An expression that does conversion, boxing, or unboxing
|
||||||
@@ -920,6 +929,81 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
|||||||
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate bounded(
|
||||||
|
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
|
||||||
|
SemReason reason
|
||||||
|
) {
|
||||||
|
initialBounded(e, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||||
|
(
|
||||||
|
semExprDoesNotOverflow(upper.booleanNot(), e)
|
||||||
|
or
|
||||||
|
not potentiallyOverflowingExpr(upper.booleanNot(), e)
|
||||||
|
or
|
||||||
|
exists(D::Delta otherDelta |
|
||||||
|
initialBounded(e, _, otherDelta, upper.booleanNot(), _, _, _) and
|
||||||
|
(
|
||||||
|
upper = true and D::toFloat(otherDelta) >= 0
|
||||||
|
or
|
||||||
|
upper = false and D::toFloat(otherDelta) <= 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate potentiallyOverflowingExpr(boolean positively, SemExpr expr) {
|
||||||
|
(
|
||||||
|
expr.getOpcode() instanceof Opcode::Add or
|
||||||
|
expr.getOpcode() instanceof Opcode::PointerAdd
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
positively = true and
|
||||||
|
(
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
positively = false and
|
||||||
|
(
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
expr.getOpcode() instanceof Opcode::Sub or
|
||||||
|
expr.getOpcode() instanceof Opcode::PointerSub
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
positively = true and
|
||||||
|
(
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
positively = false and
|
||||||
|
(
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
|
||||||
|
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
positively in [true, false] and
|
||||||
|
(
|
||||||
|
expr.getOpcode() instanceof Opcode::Mul or
|
||||||
|
expr.getOpcode() instanceof Opcode::ShiftLeft
|
||||||
|
)
|
||||||
|
or
|
||||||
|
positively = false and
|
||||||
|
(
|
||||||
|
expr.getOpcode() instanceof Opcode::Negate or
|
||||||
|
expr.getOpcode() instanceof Opcode::SubOne or
|
||||||
|
expr.(SemDivExpr).getSemType() instanceof SemFloatingPointType
|
||||||
|
)
|
||||||
|
or
|
||||||
|
positively = true and
|
||||||
|
expr.getOpcode() instanceof Opcode::AddOne
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
|
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
|
||||||
* needed on the lesser side of a floating-point comparison or on both sides of
|
* needed on the lesser side of a floating-point comparison or on both sides of
|
||||||
@@ -934,7 +1018,7 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
|||||||
* - `upper = true` : `e <= b + delta`
|
* - `upper = true` : `e <= b + delta`
|
||||||
* - `upper = false` : `e >= b + delta`
|
* - `upper = false` : `e >= b + delta`
|
||||||
*/
|
*/
|
||||||
private predicate bounded(
|
predicate initialBounded(
|
||||||
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
|
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
|
||||||
SemReason reason
|
SemReason reason
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
private import RangeAnalysisSpecific
|
private import RangeAnalysisRelativeSpecific
|
||||||
private import RangeAnalysisStage as Range
|
private import RangeAnalysisStage as Range
|
||||||
private import ConstantAnalysis
|
private import ConstantAnalysis
|
||||||
|
|
||||||
|
|||||||
@@ -314,9 +314,8 @@ class FreadBA extends BufferAccess {
|
|||||||
* but not:
|
* but not:
|
||||||
* &buffer[ix]
|
* &buffer[ix]
|
||||||
*/
|
*/
|
||||||
class ArrayExprBA extends BufferAccess {
|
class ArrayExprBA extends BufferAccess, ArrayExpr {
|
||||||
ArrayExprBA() {
|
ArrayExprBA() {
|
||||||
exists(this.(ArrayExpr).getArrayOffset().getValue().toInt()) and
|
|
||||||
not exists(AddressOfExpr aoe | aoe.getAChild() = this) and
|
not exists(AddressOfExpr aoe | aoe.getAChild() = this) and
|
||||||
// exclude accesses in macro implementation of `strcmp`,
|
// exclude accesses in macro implementation of `strcmp`,
|
||||||
// which are carefully controlled but can look dangerous.
|
// which are carefully controlled but can look dangerous.
|
||||||
|
|||||||
10
cpp/ql/src/Critical/DoubleFree.cpp
Normal file
10
cpp/ql/src/Critical/DoubleFree.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
int* f() {
|
||||||
|
int *buff = malloc(SIZE*sizeof(int));
|
||||||
|
do_stuff(buff);
|
||||||
|
free(buff);
|
||||||
|
int *new_buffer = malloc(SIZE*sizeof(int));
|
||||||
|
free(buff); // BAD: If new_buffer is assigned the same address as buff,
|
||||||
|
// the memory allocator will free the new buffer memory region,
|
||||||
|
// leading to use-after-free problems and memory corruption.
|
||||||
|
return new_buffer;
|
||||||
|
}
|
||||||
33
cpp/ql/src/Critical/DoubleFree.qhelp
Normal file
33
cpp/ql/src/Critical/DoubleFree.qhelp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
|
||||||
|
|
||||||
|
<overview>
|
||||||
|
<p>
|
||||||
|
Deallocating memory more than once can lead to a double-free vulnerability. This can be exploited to
|
||||||
|
corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing
|
||||||
|
the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
<recommendation>
|
||||||
|
<p>
|
||||||
|
Ensure that all execution paths deallocate the allocated memory at most once. If possible, reassign
|
||||||
|
the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since
|
||||||
|
most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</recommendation>
|
||||||
|
<example><sample src="DoubleFree.cpp" />
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
OWASP:
|
||||||
|
<a href="https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory">Doubly freeing memory</a>.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
49
cpp/ql/src/Critical/DoubleFree.ql
Normal file
49
cpp/ql/src/Critical/DoubleFree.ql
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @name Potential double free
|
||||||
|
* @description Freeing a resource more than once can lead to undefined behavior and cause memory corruption.
|
||||||
|
* @kind path-problem
|
||||||
|
* @precision medium
|
||||||
|
* @id cpp/double-free
|
||||||
|
* @problem.severity warning
|
||||||
|
* @security-severity 9.3
|
||||||
|
* @tags reliability
|
||||||
|
* security
|
||||||
|
* external/cwe/cwe-415
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
|
import FlowAfterFree
|
||||||
|
import DoubleFree::PathGraph
|
||||||
|
|
||||||
|
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `dealloc1` is a deallocation expression and `e` is an expression such
|
||||||
|
* that is deallocated by a deallocation expression, and the `(dealloc1, e)` pair
|
||||||
|
* should be excluded by the `FlowFromFree` library.
|
||||||
|
*
|
||||||
|
* Note that `e` is not necessarily the expression deallocated by `dealloc1`. It will
|
||||||
|
* be bound to the second deallocation as identified by the `FlowFromFree` library.
|
||||||
|
*/
|
||||||
|
bindingset[dealloc1, e]
|
||||||
|
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
|
||||||
|
exists(DeallocationExpr dealloc2 | isFree(_, e, dealloc2) |
|
||||||
|
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||||
|
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||||
|
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||||
|
// to release the memory that was allocated for the MDL structure."
|
||||||
|
isExFreePoolCall(dealloc2, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module DoubleFree = FlowFromFree<isFree/2, isExcludeFreePair/2>;
|
||||||
|
|
||||||
|
from DoubleFree::PathNode source, DoubleFree::PathNode sink, DeallocationExpr dealloc, Expr e2
|
||||||
|
where
|
||||||
|
DoubleFree::flowPath(source, sink) and
|
||||||
|
isFree(source.getNode(), _, dealloc) and
|
||||||
|
isFree(sink.getNode(), e2)
|
||||||
|
select sink.getNode(), source, sink,
|
||||||
|
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,
|
||||||
|
dealloc.toString()
|
||||||
129
cpp/ql/src/Critical/FlowAfterFree.qll
Normal file
129
cpp/ql/src/Critical/FlowAfterFree.qll
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature for a predicate that holds if `n.asExpr() = e` and `n` is a sink in
|
||||||
|
* the `FlowFromFreeConfig` module.
|
||||||
|
*/
|
||||||
|
private signature predicate isSinkSig(DataFlow::Node n, Expr e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `dealloc` is a deallocation expression and `e` is an expression such
|
||||||
|
* that `isFree(_, e)` holds for some `isFree` predicate satisfying `isSinkSig`,
|
||||||
|
* and this source-sink pair should be excluded from the analysis.
|
||||||
|
*/
|
||||||
|
bindingset[dealloc, e]
|
||||||
|
private signature predicate isExcludedSig(DeallocationExpr dealloc, Expr e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `(b1, i1)` strictly post-dominates `(b2, i2)`
|
||||||
|
*/
|
||||||
|
bindingset[i1, i2]
|
||||||
|
predicate strictlyPostDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||||
|
b1 = b2 and
|
||||||
|
i1 > i2
|
||||||
|
or
|
||||||
|
b1.strictlyPostDominates(b2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `(b1, i1)` strictly dominates `(b2, i2)`
|
||||||
|
*/
|
||||||
|
bindingset[i1, i2]
|
||||||
|
predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||||
|
b1 = b2 and
|
||||||
|
i1 < i2
|
||||||
|
or
|
||||||
|
b1.strictlyDominates(b2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a `FlowFromFreeConfig` module that can be used to find flow between
|
||||||
|
* a pointer being freed by some deallocation function, and a user-specified sink.
|
||||||
|
*
|
||||||
|
* In order to reduce false positives, the set of sinks is restricted to only those
|
||||||
|
* that satisfy at least one of the following two criteria:
|
||||||
|
* 1. The source dominates the sink, or
|
||||||
|
* 2. The sink post-dominates the source.
|
||||||
|
*/
|
||||||
|
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
|
||||||
|
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
|
||||||
|
class FlowState instanceof Expr {
|
||||||
|
FlowState() { isFree(_, this, _) }
|
||||||
|
|
||||||
|
string toString() { result = super.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||||
|
exists(
|
||||||
|
Expr e, DataFlow::Node source, IRBlock b1, int i1, IRBlock b2, int i2,
|
||||||
|
DeallocationExpr dealloc
|
||||||
|
|
|
||||||
|
isASink(sink, e) and
|
||||||
|
isFree(source, state, dealloc) and
|
||||||
|
e != state and
|
||||||
|
source.hasIndexInBlock(b1, i1) and
|
||||||
|
sink.hasIndexInBlock(b2, i2) and
|
||||||
|
not isExcluded(dealloc, e)
|
||||||
|
|
|
||||||
|
strictlyDominates(b1, i1, b2, i2)
|
||||||
|
or
|
||||||
|
strictlyPostDominates(b2, i2, b1, i1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrierIn(DataFlow::Node n) {
|
||||||
|
n.asIndirectExpr() = any(AddressOfExpr aoe)
|
||||||
|
or
|
||||||
|
n.asIndirectExpr() = any(Call call).getAnArgument()
|
||||||
|
or
|
||||||
|
exists(Expr e |
|
||||||
|
n.asIndirectExpr() = e.(PointerDereferenceExpr).getOperand() or
|
||||||
|
n.asIndirectExpr() = e.(ArrayExpr).getArrayBase()
|
||||||
|
|
|
||||||
|
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node n, FlowState state) { none() }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node n1, FlowState state1, DataFlow::Node n2, FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import DataFlow::GlobalWithState<FlowFromFreeConfig>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
|
||||||
|
* is being freed by a deallocation expression `dealloc`.
|
||||||
|
*/
|
||||||
|
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
|
||||||
|
e = dealloc.getFreedExpr() and
|
||||||
|
e = n.asExpr() and
|
||||||
|
// Ignore realloc functions
|
||||||
|
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `fc` is a function call that is the result of expanding
|
||||||
|
* the `ExFreePool` macro.
|
||||||
|
*/
|
||||||
|
predicate isExFreePoolCall(FunctionCall fc, Expr e) {
|
||||||
|
e = fc.getArgument(0) and
|
||||||
|
(
|
||||||
|
exists(MacroInvocation mi |
|
||||||
|
mi.getMacroName() = "ExFreePool" and
|
||||||
|
mi.getExpr() = fc
|
||||||
|
)
|
||||||
|
or
|
||||||
|
fc.getTarget().hasGlobalName("ExFreePool")
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -16,160 +16,133 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.commons.Scanf
|
import semmle.code.cpp.commons.Scanf
|
||||||
import semmle.code.cpp.controlflow.Guards
|
import semmle.code.cpp.controlflow.Guards
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import semmle.code.cpp.dataflow.new.DataFlow::DataFlow
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.ValueNumbering
|
import semmle.code.cpp.ir.ValueNumbering
|
||||||
|
|
||||||
/**
|
/** Holds if `n` reaches an argument to a call to a `scanf`-like function. */
|
||||||
* Holds if `call` is a `scanf`-like function that may write to `output` at index `index`.
|
pragma[nomagic]
|
||||||
*
|
predicate revFlow0(Node n) {
|
||||||
* Furthermore, `instr` is the instruction that defines the address of the `index`'th argument
|
isSink(_, _, n, _)
|
||||||
* of `call`, and `vn` is the value number of `instr.`
|
or
|
||||||
*/
|
exists(Node succ | revFlow0(succ) | localFlowStep(n, succ))
|
||||||
predicate isSource(ScanfFunctionCall call, int index, Instruction instr, ValueNumber vn, Expr output) {
|
|
||||||
output = call.getOutputArgument(index).getFullyConverted() and
|
|
||||||
instr.getConvertedResultExpression() = output and
|
|
||||||
vn.getAnInstruction() = instr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `instr` is control-flow reachable in 0 or more steps from
|
* Holds if `n` represents an uninitialized stack-allocated variable, or a
|
||||||
* a call to a `scanf`-like function.
|
* newly (and presumed uninitialized) heap allocation.
|
||||||
*/
|
*/
|
||||||
|
predicate isUninitialized(Node n) {
|
||||||
|
exists(n.asUninitialized()) or
|
||||||
|
n.asIndirectExpr(1) instanceof AllocationExpr
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow0(Instruction instr) {
|
predicate fwdFlow0(Node n) {
|
||||||
isSource(_, _, instr, _, _)
|
revFlow0(n) and
|
||||||
|
(
|
||||||
|
isUninitialized(n)
|
||||||
or
|
or
|
||||||
exists(Instruction prev |
|
exists(Node prev |
|
||||||
fwdFlow0(prev) and
|
fwdFlow0(prev) and
|
||||||
prev.getASuccessor() = instr
|
localFlowStep(prev, n)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
predicate isSink(ScanfFunctionCall call, int index, Node n, Expr input) {
|
||||||
* Holds if `instr` is part of the IR translation of `access` that
|
input = call.getOutputArgument(index) and
|
||||||
* is not an expression being deallocated, and `instr` has value
|
n.asIndirectExpr() = input
|
||||||
* number `vn`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Instruction instr, Access access, ValueNumber vn) {
|
|
||||||
instr.getAst() = access and
|
|
||||||
not any(DeallocationExpr dealloc).getFreedExpr() = access and
|
|
||||||
vn.getAnInstruction() = instr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
* Holds if `call` is a `scanf`-like call and `output` is the `index`'th
|
||||||
|
* argument that has not been previously initialized.
|
||||||
|
*/
|
||||||
|
predicate isRelevantScanfCall(ScanfFunctionCall call, int index, Expr output) {
|
||||||
|
exists(Node n | fwdFlow0(n) and isSink(call, index, n, output))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `call` is a `scanf`-like function that may write to `output` at
|
||||||
|
* index `index` and `n` is the dataflow node that represents the data after
|
||||||
|
* it has been written to by `call`.
|
||||||
|
*/
|
||||||
|
predicate isSource(ScanfFunctionCall call, int index, Node n, Expr output) {
|
||||||
|
isRelevantScanfCall(call, index, output) and
|
||||||
|
output = call.getOutputArgument(index) and
|
||||||
|
n.asDefiningArgument() = output
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is reachable from an output argument of a relevant call to
|
||||||
|
* a `scanf`-like function.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate fwdFlow(Node n) {
|
||||||
|
isSource(_, _, n, _)
|
||||||
|
or
|
||||||
|
exists(Node prev |
|
||||||
|
fwdFlow(prev) and
|
||||||
|
localFlowStep(prev, n) and
|
||||||
|
not isSanitizerOut(prev)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `n` should not have outgoing flow. */
|
||||||
|
predicate isSanitizerOut(Node n) {
|
||||||
|
// We disable flow out of sinks to reduce result duplication
|
||||||
|
isSink(n, _)
|
||||||
|
or
|
||||||
|
// If the node is being passed to a function it may be
|
||||||
|
// modified, and thus it's safe to later read the value.
|
||||||
|
exists(n.asIndirectArgument())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is a node such that `n.asExpr() = e` and `e` is not an
|
||||||
|
* argument of a deallocation expression.
|
||||||
|
*/
|
||||||
|
predicate isSink(Node n, Expr e) {
|
||||||
|
n.asExpr() = e and
|
||||||
|
not any(DeallocationExpr dealloc).getFreedExpr() = e
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is part of a path from a call to a `scanf`-like function
|
||||||
* to a use of the written variable.
|
* to a use of the written variable.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow0(Instruction instr) {
|
predicate revFlow(Node n) {
|
||||||
fwdFlow0(instr) and
|
fwdFlow(n) and
|
||||||
(
|
(
|
||||||
isSink(instr, _, _)
|
isSink(n, _)
|
||||||
or
|
or
|
||||||
exists(Instruction succ | revFlow0(succ) | instr.getASuccessor() = succ)
|
exists(Node succ |
|
||||||
)
|
revFlow(succ) and
|
||||||
}
|
localFlowStep(n, succ) and
|
||||||
|
not isSanitizerOut(n)
|
||||||
/**
|
|
||||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
|
||||||
* that writes to a variable with value number `vn`, without passing through
|
|
||||||
* redefinitions of the variable.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlow(Instruction instr, ValueNumber vn) {
|
|
||||||
revFlow0(instr) and
|
|
||||||
(
|
|
||||||
isSource(_, _, instr, vn, _)
|
|
||||||
or
|
|
||||||
exists(Instruction prev |
|
|
||||||
fwdFlow(prev, vn) and
|
|
||||||
prev.getASuccessor() = instr and
|
|
||||||
not isBarrier(instr, vn)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** A local flow step, restricted to relevant dataflow nodes. */
|
||||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
private predicate step(Node n1, Node n2) {
|
||||||
* that writes to a variable with value number `vn`, without passing through
|
revFlow(n1) and
|
||||||
* redefinitions of the variable.
|
revFlow(n2) and
|
||||||
*
|
localFlowStep(n1, n2)
|
||||||
* Note: This predicate only holds for the `(intr, vn)` pairs that are also
|
|
||||||
* control-flow reachable from an argument to a `scanf`-like function call.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
predicate revFlow(Instruction instr, ValueNumber vn) {
|
|
||||||
fwdFlow(instr, pragma[only_bind_out](vn)) and
|
|
||||||
(
|
|
||||||
isSink(instr, _, vn)
|
|
||||||
or
|
|
||||||
exists(Instruction succ | revFlow(succ, vn) |
|
|
||||||
instr.getASuccessor() = succ and
|
|
||||||
not isBarrier(succ, vn)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
predicate hasFlow(Node n1, Node n2) = fastTC(step/2)(n1, n2)
|
||||||
* A type that bundles together a reachable instruction with the appropriate
|
|
||||||
* value number (i.e., the value number that's transferred from the source
|
|
||||||
* to the sink).
|
|
||||||
*/
|
|
||||||
newtype TNode = MkNode(Instruction instr, ValueNumber vn) { revFlow(instr, vn) }
|
|
||||||
|
|
||||||
class Node extends MkNode {
|
|
||||||
ValueNumber vn;
|
|
||||||
Instruction instr;
|
|
||||||
|
|
||||||
Node() { this = MkNode(instr, vn) }
|
|
||||||
|
|
||||||
final string toString() { result = instr.toString() }
|
|
||||||
|
|
||||||
final Node getASuccessor() { result = MkNode(pragma[only_bind_out](instr.getASuccessor()), vn) }
|
|
||||||
|
|
||||||
final Location getLocation() { result = instr.getLocation() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `instr` is an instruction with value number `vn` that is
|
|
||||||
* used in a store operation, or is overwritten by another call to
|
|
||||||
* a `scanf`-like function.
|
|
||||||
*/
|
|
||||||
private predicate isBarrier(Instruction instr, ValueNumber vn) {
|
|
||||||
// We only need to compute barriers for instructions that we
|
|
||||||
// managed to hit during the initial flow stage.
|
|
||||||
revFlow0(pragma[only_bind_into](instr)) and
|
|
||||||
valueNumber(instr) = vn and
|
|
||||||
exists(Expr e | instr.getAst() = e |
|
|
||||||
instr = any(StoreInstruction s).getDestinationAddress()
|
|
||||||
or
|
|
||||||
isSource(_, _, _, _, [e, e.getParent().(AddressOfExpr)])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `n1` steps to `n2` in a single step. */
|
|
||||||
predicate isSuccessor(Node n1, Node n2) { n1.getASuccessor() = n2 }
|
|
||||||
|
|
||||||
predicate hasFlow(Node n1, Node n2) = fastTC(isSuccessor/2)(n1, n2)
|
|
||||||
|
|
||||||
Node getNode(Instruction instr, ValueNumber vn) { result = MkNode(instr, vn) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
|
* Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
|
||||||
* an instruction that is part of the translation of `access` which is a transitive
|
* a dataflow node that represents the expression `e`.
|
||||||
* control-flow successor of `call`.
|
|
||||||
*
|
|
||||||
* Furthermore, `source` and `sink` have identical global value numbers.
|
|
||||||
*/
|
*/
|
||||||
predicate hasFlow(
|
predicate hasFlow(Node source, ScanfFunctionCall call, int index, Node sink, Expr e) {
|
||||||
Instruction source, ScanfFunctionCall call, int index, Instruction sink, Access access
|
isSource(call, index, source, _) and
|
||||||
) {
|
hasFlow(source, sink) and
|
||||||
exists(ValueNumber vn |
|
isSink(sink, e)
|
||||||
isSource(call, index, source, vn, _) and
|
|
||||||
hasFlow(getNode(source, pragma[only_bind_into](vn)), getNode(sink, pragma[only_bind_into](vn))) and
|
|
||||||
isSink(sink, access, vn)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,7 +150,7 @@ predicate hasFlow(
|
|||||||
* success in writing the output argument at index `index`.
|
* success in writing the output argument at index `index`.
|
||||||
*/
|
*/
|
||||||
int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
|
int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
|
||||||
isSource(call, index, _, _, _) and
|
isSource(call, index, _, _) and
|
||||||
result =
|
result =
|
||||||
index + 1 -
|
index + 1 -
|
||||||
count(ScanfFormatLiteral f, int n |
|
count(ScanfFormatLiteral f, int n |
|
||||||
@@ -191,7 +164,7 @@ int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
|
|||||||
* Holds the access to `e` isn't guarded by a check that ensures that `call` returned
|
* Holds the access to `e` isn't guarded by a check that ensures that `call` returned
|
||||||
* at least `minGuard`.
|
* at least `minGuard`.
|
||||||
*/
|
*/
|
||||||
predicate hasNonGuardedAccess(ScanfFunctionCall call, Access e, int minGuard) {
|
predicate hasNonGuardedAccess(ScanfFunctionCall call, Expr e, int minGuard) {
|
||||||
exists(int index |
|
exists(int index |
|
||||||
hasFlow(_, call, index, _, e) and
|
hasFlow(_, call, index, _, e) and
|
||||||
minGuard = getMinimumGuardConstant(call, index)
|
minGuard = getMinimumGuardConstant(call, index)
|
||||||
@@ -211,7 +184,7 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
|
|||||||
exists(GuardCondition g, Expr left, Expr right |
|
exists(GuardCondition g, Expr left, Expr right |
|
||||||
right = g.getAChild() and
|
right = g.getAChild() and
|
||||||
value = left.getValue().toInt() and
|
value = left.getValue().toInt() and
|
||||||
DataFlow::localExprFlow(call, right)
|
localExprFlow(call, right)
|
||||||
|
|
|
|
||||||
g.ensuresEq(left, right, 0, result, true) and op = "=="
|
g.ensuresEq(left, right, 0, result, true) and op = "=="
|
||||||
or
|
or
|
||||||
@@ -221,9 +194,9 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
from ScanfFunctionCall call, Access access, int minGuard
|
from ScanfFunctionCall call, Expr e, int minGuard
|
||||||
where hasNonGuardedAccess(call, access, minGuard)
|
where hasNonGuardedAccess(call, e, minGuard)
|
||||||
select access,
|
select e,
|
||||||
"This variable is read, but may not have been written. " +
|
"This variable is read, but may not have been written. " +
|
||||||
"It should be guarded by a check that the $@ returns at least " + minGuard + ".", call,
|
"It should be guarded by a check that the $@ returns at least " + minGuard + ".", call,
|
||||||
call.toString()
|
call.toString()
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* @name Potential use after free
|
* @name Potential use after free
|
||||||
* @description An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.
|
* @description An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.
|
||||||
* @kind problem
|
* @kind path-problem
|
||||||
|
* @precision medium
|
||||||
* @id cpp/use-after-free
|
* @id cpp/use-after-free
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @security-severity 9.3
|
* @security-severity 9.3
|
||||||
@@ -11,56 +12,159 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
import FlowAfterFree
|
||||||
predicate isFreeExpr(Expr e, StackVariable v) {
|
import UseAfterFree::PathGraph
|
||||||
exists(VariableAccess va | va.getTarget() = v |
|
|
||||||
exists(FunctionCall fc | fc = e |
|
|
||||||
fc.getTarget().hasGlobalOrStdName("free") and
|
|
||||||
va = fc.getArgument(0)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
e.(DeleteExpr).getExpr() = va
|
|
||||||
or
|
|
||||||
e.(DeleteArrayExpr).getExpr() = va
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** `e` is an expression that (may) dereference `v`. */
|
|
||||||
predicate isDerefExpr(Expr e, StackVariable v) {
|
|
||||||
v.getAnAccess() = e and dereferenced(e)
|
|
||||||
or
|
|
||||||
isDerefByCallExpr(_, _, e, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `va` is passed by value as (part of) the `i`th argument in
|
* Holds if `call` is a call to a function that obviously
|
||||||
* call `c`. The target function is either a library function
|
* doesn't dereference its `i`'th argument.
|
||||||
* or a source code function that dereferences the relevant
|
|
||||||
* parameter.
|
|
||||||
*/
|
*/
|
||||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
|
private predicate externalCallNeverDereferences(FormattingFunctionCall call, int arg) {
|
||||||
v.getAnAccess() = va and
|
exists(int formatArg |
|
||||||
va = c.getAnArgumentSubExpr(i) and
|
pragma[only_bind_out](call.getFormatArgument(formatArg)) =
|
||||||
not c.passesByReference(i, va) and
|
pragma[only_bind_out](call.getArgument(arg)) and
|
||||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
call.getFormat().(FormatLiteral).getConvSpec(formatArg) != "%s"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class UseAfterFreeReachability extends StackVariableReachability {
|
predicate isUse0(DataFlow::Node n, Expr e) {
|
||||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
e = n.asExpr() and
|
||||||
|
not isFree(_, e, _) and
|
||||||
|
(
|
||||||
|
e = any(PointerDereferenceExpr pde).getOperand()
|
||||||
|
or
|
||||||
|
e = any(PointerFieldAccess pfa).getQualifier()
|
||||||
|
or
|
||||||
|
e = any(ArrayExpr ae).getArrayBase()
|
||||||
|
or
|
||||||
|
e = any(Call call).getQualifier()
|
||||||
|
or
|
||||||
|
// Assume any function without a body will dereference the pointer
|
||||||
|
exists(int i, Call call, Function f |
|
||||||
|
n.asExpr() = call.getArgument(i) and
|
||||||
|
f = call.getTarget() and
|
||||||
|
not f.hasEntryPoint() and
|
||||||
|
// Exclude known functions we know won't dereference the pointer.
|
||||||
|
// For example, a call such as `printf("%p", myPointer)`.
|
||||||
|
not externalCallNeverDereferences(call, i)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
|
module ParameterSinks {
|
||||||
|
import semmle.code.cpp.ir.ValueNumbering
|
||||||
|
|
||||||
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
|
predicate flowsToUse(DataFlow::Node n) {
|
||||||
|
isUse0(n, _)
|
||||||
|
or
|
||||||
|
exists(DataFlow::Node succ |
|
||||||
|
flowsToUse(succ) and
|
||||||
|
DataFlow::localFlowStep(n, succ)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
private predicate flowsFromParam(DataFlow::Node n) {
|
||||||
definitionBarrier(v, node) or
|
flowsToUse(n) and
|
||||||
isFreeExpr(node, v)
|
(
|
||||||
|
n.asParameter().getUnspecifiedType() instanceof PointerType
|
||||||
|
or
|
||||||
|
exists(DataFlow::Node prev |
|
||||||
|
flowsFromParam(prev) and
|
||||||
|
DataFlow::localFlowStep(prev, n)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||||
|
flowsFromParam(n1) and
|
||||||
|
flowsFromParam(n2) and
|
||||||
|
DataFlow::localFlowStep(n1, n2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate paramToUse(DataFlow::Node n1, DataFlow::Node n2) = fastTC(step/2)(n1, n2)
|
||||||
|
|
||||||
|
private predicate hasFlow(
|
||||||
|
DataFlow::Node source, InitializeParameterInstruction init, DataFlow::Node sink
|
||||||
|
) {
|
||||||
|
pragma[only_bind_out](source.asParameter()) = pragma[only_bind_out](init.getParameter()) and
|
||||||
|
paramToUse(source, sink) and
|
||||||
|
isUse0(sink, _)
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitializeParameterInstruction getAnAlwaysDereferencedParameter0() {
|
||||||
|
exists(DataFlow::Node source, DataFlow::Node sink, IRBlock b1, int i1, IRBlock b2, int i2 |
|
||||||
|
hasFlow(pragma[only_bind_into](source), result, pragma[only_bind_into](sink)) and
|
||||||
|
source.hasIndexInBlock(b1, pragma[only_bind_into](i1)) and
|
||||||
|
sink.hasIndexInBlock(b2, pragma[only_bind_into](i2)) and
|
||||||
|
strictlyPostDominates(b2, i2, b1, i1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallInstruction getAnAlwaysReachedCallInstruction(IRFunction f) {
|
||||||
|
result.getBlock().postDominates(f.getEntryBlock())
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate callHasTargetAndArgument(Function f, int i, CallInstruction call, Instruction argument) {
|
||||||
|
call.getStaticCallTarget() = f and
|
||||||
|
call.getArgument(i) = argument
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) {
|
||||||
|
pragma[only_bind_out](init.getEnclosingFunction()) = f and
|
||||||
|
init.hasIndex(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeParameterInstruction getAnAlwaysDereferencedParameter() {
|
||||||
|
result = getAnAlwaysDereferencedParameter0()
|
||||||
|
or
|
||||||
|
exists(
|
||||||
|
CallInstruction call, int i, InitializeParameterInstruction p, Instruction argument,
|
||||||
|
Function f
|
||||||
|
|
|
||||||
|
callHasTargetAndArgument(f, i, call, argument) and
|
||||||
|
initializeParameterInFunction(f, i, p) and
|
||||||
|
p = getAnAlwaysDereferencedParameter() and
|
||||||
|
result =
|
||||||
|
pragma[only_bind_out](pragma[only_bind_into](valueNumber(argument)).getAnInstruction()) and
|
||||||
|
call = getAnAlwaysReachedCallInstruction(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
predicate isUse(DataFlow::Node n, Expr e) {
|
||||||
where r.reaches(free, v, e)
|
isUse0(n, e)
|
||||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
|
or
|
||||||
"been previously freed"
|
exists(CallInstruction call, int i, InitializeParameterInstruction init |
|
||||||
|
n.asOperand().getDef().getUnconvertedResultExpression() = e and
|
||||||
|
init = ParameterSinks::getAnAlwaysDereferencedParameter() and
|
||||||
|
call.getArgumentOperand(i) = n.asOperand() and
|
||||||
|
init.hasIndex(i) and
|
||||||
|
init.getEnclosingFunction() = call.getStaticCallTarget()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
|
||||||
|
* pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
|
||||||
|
*/
|
||||||
|
bindingset[dealloc1, e]
|
||||||
|
predicate isExcludeFreeUsePair(DeallocationExpr dealloc1, Expr e) {
|
||||||
|
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||||
|
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||||
|
// to release the memory that was allocated for the MDL structure."
|
||||||
|
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||||
|
isExFreePoolCall(_, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
module UseAfterFree = FlowFromFree<isUse/2, isExcludeFreeUsePair/2>;
|
||||||
|
|
||||||
|
from UseAfterFree::PathNode source, UseAfterFree::PathNode sink, DeallocationExpr dealloc
|
||||||
|
where
|
||||||
|
UseAfterFree::flowPath(source, sink) and
|
||||||
|
isFree(source.getNode(), _, dealloc)
|
||||||
|
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
|
||||||
|
dealloc.toString()
|
||||||
|
|||||||
4
cpp/ql/src/change-notes/2023-04-11-double-free.md
Normal file
4
cpp/ql/src/change-notes/2023-04-11-double-free.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: newQuery
|
||||||
|
---
|
||||||
|
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||||
4
cpp/ql/src/change-notes/2023-04-11-use-after-free.md
Normal file
4
cpp/ql/src/change-notes/2023-04-11-use-after-free.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: newQuery
|
||||||
|
---
|
||||||
|
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Errors When Double Free
|
* @name Errors When Double Free
|
||||||
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
|
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/double-free
|
* @id cpp/experimental-double-free
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @precision medium
|
* @precision medium
|
||||||
* @tags security
|
* @tags security
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.6.0
|
version: 0.6.1-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<queries language="cpp"/>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
||||||
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
||||||
| type_attributes.c:10:54:10:54 | union <unnamed> | type_attributes.c:10:30:10:50 | transparent_union |
|
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
|
||||||
| type_attributes.c:16:54:16:54 | union <unnamed> | type_attributes.c:16:30:16:50 | transparent_union |
|
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
|
||||||
| type_attributes.c:21:37:21:45 | unusedInt | type_attributes.c:21:24:21:29 | unused |
|
| type_attributes.c:21:37:21:45 | unusedInt | type_attributes.c:21:24:21:29 | unused |
|
||||||
| type_attributes.c:23:13:23:18 | depInt | type_attributes.c:23:36:23:45 | deprecated |
|
| type_attributes.c:23:13:23:18 | depInt | type_attributes.c:23:36:23:45 | deprecated |
|
||||||
| type_attributes_ms.cpp:1:29:1:29 | X | type_attributes_ms.cpp:1:19:1:26 | novtable |
|
| type_attributes_ms.cpp:1:29:1:29 | X | type_attributes_ms.cpp:1:19:1:26 | novtable |
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
| (unnamed class/struct/union) |
|
||||||
| float[3] |
|
| float[3] |
|
||||||
| float[3][3] |
|
| float[3][3] |
|
||||||
| foo[1] |
|
| foo[1] |
|
||||||
| struct <unnamed> |
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnaly
|
|||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
import semmle.code.cpp.ir.IR as IR
|
import semmle.code.cpp.ir.IR as IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
module ModulusAnalysisInstantiated =
|
module ModulusAnalysisInstantiated =
|
||||||
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImpl>>;
|
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||||
|
|
||||||
class ModulusAnalysisTest extends InlineExpectationsTest {
|
class ModulusAnalysisTest extends InlineExpectationsTest {
|
||||||
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
||||||
|
|||||||
23
cpp/ql/test/library-tests/ir/range-analysis/Overflow.ql
Normal file
23
cpp/ql/test/library-tests/ir/range-analysis/Overflow.ql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
|
||||||
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
|
class RangeAnalysisTest extends InlineExpectationsTest {
|
||||||
|
RangeAnalysisTest() { this = "RangeAnalysisTest" }
|
||||||
|
|
||||||
|
override string getARelevantTag() { result = "overflow" }
|
||||||
|
|
||||||
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
exists(Expr e |
|
||||||
|
tag = "overflow" and
|
||||||
|
element = e.toString() and
|
||||||
|
location = e.getLocation() and
|
||||||
|
value =
|
||||||
|
strictconcat(string s |
|
||||||
|
s = "+" and exprMightOverflowPositively(e)
|
||||||
|
or
|
||||||
|
s = "-" and exprMightOverflowNegatively(e)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,9 @@ int test1(struct List* p) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (; p; p = p->next) {
|
for (; p; p = p->next) {
|
||||||
count = count+1;
|
count = count+1;
|
||||||
range(count); // $ range===count:p+1 range=>=1
|
range(count); // $ range===count:p+1
|
||||||
}
|
}
|
||||||
range(count); // $ range=>=0
|
range(count);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,13 +40,13 @@ int test4() {
|
|||||||
int total = 0;
|
int total = 0;
|
||||||
for (i = 0; i < 2; i = i+1) {
|
for (i = 0; i < 2; i = i+1) {
|
||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total); // $ range=>=0
|
range(total);
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 range=<=i+1 range=>=0 range=>=i+0
|
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
range(i); // $ range===2
|
range(i); // $ range===2
|
||||||
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
|
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,13 +55,13 @@ int test5() {
|
|||||||
int total = 0;
|
int total = 0;
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total); // $ range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
|
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
range(i); // $ range===2
|
range(i); // $ range===2
|
||||||
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
|
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +70,9 @@ int test6() {
|
|||||||
int total = 0;
|
int total = 0;
|
||||||
for (i = 0; i+2 < 4; i = i+1) {
|
for (i = 0; i+2 < 4; i = i+1) {
|
||||||
range(i); // $ range=<=1 range=>=0
|
range(i); // $ range=<=1 range=>=0
|
||||||
range(total); // $ range=>=0
|
range(total); // $ MISSING: range=>=0
|
||||||
total += i;
|
total += i;
|
||||||
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
|
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||||
}
|
}
|
||||||
return total + i;
|
return total + i;
|
||||||
}
|
}
|
||||||
@@ -168,19 +168,19 @@ typedef unsigned long long size_type;
|
|||||||
|
|
||||||
size_type test12_helper() {
|
size_type test12_helper() {
|
||||||
static size_type n = 0;
|
static size_type n = 0;
|
||||||
return n++;
|
return n++; // $ overflow=+
|
||||||
}
|
}
|
||||||
|
|
||||||
int test12() {
|
int test12() {
|
||||||
size_type Start = 0;
|
size_type Start = 0;
|
||||||
while (Start <= test12_helper()-1)
|
while (Start <= test12_helper()-1)
|
||||||
{
|
{
|
||||||
range(Start);
|
range(Start); // $ MISSING:range=>=0
|
||||||
const size_type Length = test12_helper();
|
const size_type Length = test12_helper();
|
||||||
Start += Length + 1;
|
Start += Length + 1; // $ overflow=+
|
||||||
range(Start);
|
range(Start); // $ MISSING:range=>=1 MISSING:range=>=Start+1 MISSING:range=">=call to test12_helper+1"
|
||||||
}
|
}
|
||||||
range(Start);
|
range(Start); // $ MISSING:range=>=0
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -190,13 +190,13 @@ int test13(char c, int i) {
|
|||||||
unsigned char uc = c;
|
unsigned char uc = c;
|
||||||
range(uc);
|
range(uc);
|
||||||
unsigned int x = 0;
|
unsigned int x = 0;
|
||||||
unsigned int y = x-1;
|
unsigned int y = x-1; // $ overflow=-
|
||||||
range(y); // $ range===-1
|
range(y); // $ range===-1 overflow=-
|
||||||
int z = i+1;
|
int z = i+1; // $ overflow=+
|
||||||
range(z); // $ range===i+1
|
range(z); // $ range===i+1
|
||||||
range(c + i + uc + x + y + z);
|
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
||||||
range((double)(c + i + uc + x + y + z));
|
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
||||||
return (double)(c + i + uc + x + y + z);
|
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regression test for ODASA-6013.
|
// Regression test for ODASA-6013.
|
||||||
@@ -213,8 +213,8 @@ int test14(int x) {
|
|||||||
range(c0);
|
range(c0);
|
||||||
unsigned short s0 = x;
|
unsigned short s0 = x;
|
||||||
range(s0);
|
range(s0);
|
||||||
range(x0 + x1 + x2 + x3 + c0 + s0);
|
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
|
||||||
return x0 + x1 + x2 + x3 + c0 + s0;
|
return x0 + x1 + x2 + x3 + c0 + s0; // $ overflow=+ overflow=+-
|
||||||
}
|
}
|
||||||
|
|
||||||
long long test15(long long x) {
|
long long test15(long long x) {
|
||||||
@@ -243,7 +243,7 @@ int test_unary(int a) {
|
|||||||
range(b); // $ range=<=11 range=>=0
|
range(b); // $ range=<=11 range=>=0
|
||||||
int c = -a;
|
int c = -a;
|
||||||
range(c); // $ range=<=0 range=>=-11
|
range(c); // $ range=<=0 range=>=-11
|
||||||
range(b+c); // $ range=<=11 range=>=-11
|
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
|
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
|
||||||
}
|
}
|
||||||
@@ -273,7 +273,7 @@ int test_unary(int a) {
|
|||||||
range(b); // $ range=<=0 range=>=-7
|
range(b); // $ range=<=0 range=>=-7
|
||||||
int c = -a;
|
int c = -a;
|
||||||
range(c); // $ range=<=7 range=>=0
|
range(c); // $ range=<=7 range=>=0
|
||||||
range(b+c); // $ range=>=-7 range=<=7
|
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
|
||||||
total += b+c;
|
total += b+c;
|
||||||
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
|
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
|
||||||
}
|
}
|
||||||
@@ -315,9 +315,9 @@ int test_mult01(int a, int b) {
|
|||||||
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // -143 .. 253
|
int r = a*b; // $ overflow=+- -143 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+
|
||||||
range(total); // $ MISSING: range=">=... * ...+0"
|
range(total); // $ MISSING: range=">=... * ...+0"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||||
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=<=3+0 range=>=3-143
|
range(total); // $ range=>=3-143
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
|
|||||||
int r = a*b; // -143 .. -21
|
int r = a*b; // -143 .. -21
|
||||||
range(r); // $ range=<=-21 range=>=-143
|
range(r); // $ range=<=-21 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=<=3-21 range=>=3-143 range=>=3-286
|
range(total); // $ range=>=3-143 range=>=3-286
|
||||||
}
|
}
|
||||||
range(total); // $ range=<=3+0 range=>=3-143 range=>=3-286
|
range(total); // $ range=>=3-143 range=>=3-286
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,9 +363,9 @@ int test_mult02(int a, int b) {
|
|||||||
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=0
|
range(a); // $ range=<=11 range=>=0
|
||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // -143 .. 253
|
int r = a*b; // $ overflow=+- -143 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+
|
||||||
range(total); // $ MISSING: range=">=... * ...+0"
|
range(total); // $ MISSING: range=">=... * ...+0"
|
||||||
}
|
}
|
||||||
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||||
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=<=0+0 range=>=0-143
|
range(total); // $ range=>=0-143
|
||||||
}
|
}
|
||||||
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=11 range=>=0
|
range(a); // $ range=<=11 range=>=0
|
||||||
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
|
|||||||
int r = a*b; // -143 .. 0
|
int r = a*b; // -143 .. 0
|
||||||
range(r); // $ range=<=0 range=>=-143
|
range(r); // $ range=<=0 range=>=-143
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
|
range(total); // $ range=>=0-143 range=>=0-286
|
||||||
}
|
}
|
||||||
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
|
range(total); // $range=>=0-143 range=>=0-286
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ int test_mult03(int a, int b) {
|
|||||||
if (-17 <= a && a <= 11 && 5 <= b && b <= 23) {
|
if (-17 <= a && a <= 11 && 5 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=-17
|
range(a); // $ range=<=11 range=>=-17
|
||||||
range(b); // $ range=<=23 range=>=5
|
range(b); // $ range=<=23 range=>=5
|
||||||
int r = a*b; // -391 .. 253
|
int r = a*b; // $ overflow=+- -391 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r;
|
||||||
range(total);
|
range(total);
|
||||||
@@ -403,33 +403,33 @@ int test_mult03(int a, int b) {
|
|||||||
if (-17 <= a && a <= 11 && 0 <= b && b <= 23) {
|
if (-17 <= a && a <= 11 && 0 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=-17
|
range(a); // $ range=<=11 range=>=-17
|
||||||
range(b); // $ range=<=23 range=>=0
|
range(b); // $ range=<=23 range=>=0
|
||||||
int r = a*b; // -391 .. 253
|
int r = a*b; // $ overflow=+- -391 .. 253
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+-
|
||||||
range(total);
|
range(total);
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 11 && -13 <= b && b <= 23) {
|
if (-17 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=-17
|
range(a); // $ range=<=11 range=>=-17
|
||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // -391 .. 253
|
int r = a*b; // $ overflow=+- -391 .. 25
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+-
|
||||||
range(total);
|
range(total);
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 11 && -13 <= b && b <= 0) {
|
if (-17 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||||
range(a); // $ range=<=11 range=>=-17
|
range(a); // $ range=<=11 range=>=-17
|
||||||
range(b); // $ range=<=0 range=>=-13
|
range(b); // $ range=<=0 range=>=-13
|
||||||
int r = a*b; // -143 .. 221
|
int r = a*b; // $ overflow=+- -143 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+-
|
||||||
range(total);
|
range(total);
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 11 && -13 <= b && b <= -7) {
|
if (-17 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=11 range=>=-17
|
range(a); // $ range=<=11 range=>=-17
|
||||||
range(b); // $ range=<=-7 range=>=-13
|
range(b); // $ range=<=-7 range=>=-13
|
||||||
int r = a*b; // -143 .. 221
|
int r = a*b; // $ overflow=+- -143 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=+-
|
||||||
range(total);
|
range(total);
|
||||||
}
|
}
|
||||||
range(total);
|
range(total);
|
||||||
@@ -458,9 +458,9 @@ int test_mult04(int a, int b) {
|
|||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=0 range=>=-17
|
range(a); // $ range=<=0 range=>=-17
|
||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // -391 .. 221
|
int r = a*b; // $ overflow=+- -391 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=-
|
||||||
range(total); // $ MISSING: range="<=... * ...+0"
|
range(total); // $ MISSING: range="<=... * ...+0"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
||||||
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221" range=">=- ...+0"
|
range(total); // $ range="<=- ...+221"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=0 range=>=-17
|
range(a); // $ range=<=0 range=>=-17
|
||||||
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||||
}
|
}
|
||||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,9 +506,9 @@ int test_mult05(int a, int b) {
|
|||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=-2 range=>=-17
|
range(a); // $ range=<=-2 range=>=-17
|
||||||
range(b); // $ range=<=23 range=>=-13
|
range(b); // $ range=<=23 range=>=-13
|
||||||
int r = a*b; // -391 .. 221
|
int r = a*b; // $ overflow=+- -391 .. 221
|
||||||
range(r);
|
range(r);
|
||||||
total += r;
|
total += r; // $ overflow=-
|
||||||
range(total); // $ MISSING: range="<=... * ...+0"
|
range(total); // $ MISSING: range="<=... * ...+0"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
||||||
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
|
|||||||
int r = a*b; // 0 .. 221
|
int r = a*b; // 0 .. 221
|
||||||
range(r); // $ range=<=221 range=>=0
|
range(r); // $ range=<=221 range=>=0
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221" range=">=- ...+0"
|
range(total); // $ range="<=- ...+221"
|
||||||
}
|
}
|
||||||
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
||||||
range(a); // $ range=<=-2 range=>=-17
|
range(a); // $ range=<=-2 range=>=-17
|
||||||
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
|
|||||||
int r = a*b; // 14 .. 221
|
int r = a*b; // 14 .. 221
|
||||||
range(r); // $ range=<=221 range=>=14
|
range(r); // $ range=<=221 range=>=14
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range="<=- ...+221" range="<=- ...+442" range=">=- ...+14"
|
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||||
}
|
}
|
||||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ int test16(int x) {
|
|||||||
while (i < 3) {
|
while (i < 3) {
|
||||||
range(i); // $ range=<=2 range=>=0
|
range(i); // $ range=<=2 range=>=0
|
||||||
i++;
|
i++;
|
||||||
range(i); // $ range="==... = ...:i+1" range=<=3 range=>=1
|
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
|
||||||
}
|
}
|
||||||
range(d);
|
range(d);
|
||||||
d = i;
|
d = i;
|
||||||
@@ -586,7 +586,7 @@ unsigned int test_ternary01(unsigned int x) {
|
|||||||
(range(x), 500);
|
(range(x), 500);
|
||||||
range(y4); // $ range=<=500
|
range(y4); // $ range=<=500
|
||||||
y5 = (x+1) ?:
|
y5 = (x+1) ?:
|
||||||
(range(x), 500); // $ range===-1
|
(range(x), 500); // $ overflow=- range===-1
|
||||||
range(y5); // $ range=<=500
|
range(y5); // $ range=<=500
|
||||||
y6 = ((unsigned char)(x+1)) ?:
|
y6 = ((unsigned char)(x+1)) ?:
|
||||||
(range(x), 5); // $ range=<=299
|
(range(x), 5); // $ range=<=299
|
||||||
@@ -598,8 +598,8 @@ unsigned int test_ternary01(unsigned int x) {
|
|||||||
(range(x), 500); // $ range=<=299
|
(range(x), 500); // $ range=<=299
|
||||||
range(y8); // y8 <= 300
|
range(y8); // y8 <= 300
|
||||||
}
|
}
|
||||||
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ overflow=+ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||||
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8;
|
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8; // $ overflow=+
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test ternary expression lower bounds.
|
// Test ternary expression lower bounds.
|
||||||
@@ -628,8 +628,8 @@ unsigned int test_ternary02(unsigned int x) {
|
|||||||
(range(x), 5); // $ range=>=300
|
(range(x), 5); // $ range=>=300
|
||||||
range(y5); // y6 >= 0
|
range(y5); // y6 >= 0
|
||||||
}
|
}
|
||||||
range(y1 + y2 + y3 + y4 + y5); // $ range=">=call to range+207" MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
range(y1 + y2 + y3 + y4 + y5); // $ overflow=+ MISSING: range=">=call to range+207" range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||||
return y1 + y2 + y3 + y4 + y5;
|
return y1 + y2 + y3 + y4 + y5; // $ overflow=+
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the comma expression.
|
// Test the comma expression.
|
||||||
@@ -691,9 +691,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
|||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
range(b); // $ range=<=23 range=>=0
|
range(b); // $ range=<=23 range=>=0
|
||||||
int r = a*b; // 0 .. 253
|
int r = a*b; // 0 .. 253
|
||||||
range(r); // $ range=>=0 range=<=253
|
range(r);// $ range=>=0 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
|
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
|
||||||
}
|
}
|
||||||
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
||||||
range(a); // $ range=<=11 range=>=3
|
range(a); // $ range=<=11 range=>=3
|
||||||
@@ -701,7 +701,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
|||||||
int r = a*b; // 39 .. 253
|
int r = a*b; // 39 .. 253
|
||||||
range(r); // $ range=>=39 range=<=253
|
range(r); // $ range=>=39 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=39 range=<=759 range=">=(unsigned int)...+39" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||||
return total;
|
return total;
|
||||||
@@ -722,14 +722,14 @@ int test_unsigned_mult02(unsigned b) {
|
|||||||
int r = 11*b; // 0 .. 253
|
int r = 11*b; // 0 .. 253
|
||||||
range(r); // $ range=>=0 range=<=253
|
range(r); // $ range=>=0 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
|
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
|
||||||
}
|
}
|
||||||
if (13 <= b && b <= 23) {
|
if (13 <= b && b <= 23) {
|
||||||
range(b); // $ range=<=23 range=>=13
|
range(b); // $ range=<=23 range=>=13
|
||||||
int r = 11*b; // 143 .. 253
|
int r = 11*b; // 143 .. 253
|
||||||
range(r); // $ range=>=143 range=<=253
|
range(r); // $ range=>=143 range=<=253
|
||||||
total += r;
|
total += r;
|
||||||
range(total); // $ range=>=143 range=<=759 range=">=(unsigned int)...+143" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
|
||||||
}
|
}
|
||||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||||
return total;
|
return total;
|
||||||
@@ -751,7 +751,7 @@ unsigned long mult_overflow() {
|
|||||||
range(x); // $ range===274177
|
range(x); // $ range===274177
|
||||||
y = 67280421310721UL;
|
y = 67280421310721UL;
|
||||||
range(y);
|
range(y);
|
||||||
xy = x * y;
|
xy = x * y; // $ overflow=+-
|
||||||
range(xy);
|
range(xy);
|
||||||
return xy; // BUG: upper bound should be >= 18446744073709551617UL
|
return xy; // BUG: upper bound should be >= 18446744073709551617UL
|
||||||
}
|
}
|
||||||
@@ -760,14 +760,14 @@ unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
|
|||||||
if (ui >= 10) {
|
if (ui >= 10) {
|
||||||
range(ui); // $ range=>=10
|
range(ui); // $ range=>=10
|
||||||
range((unsigned long)ui); // $ range=>=10
|
range((unsigned long)ui); // $ range=>=10
|
||||||
unsigned long result = (unsigned long)ui * ui;
|
unsigned long result = (unsigned long)ui * ui; // $ overflow=+
|
||||||
range(result); // $ range=>=100 range=>=100
|
range(result); // $ MISSING: range=>=100
|
||||||
return result; // BUG: upper bound should be >= 18446744065119617025
|
return result; // BUG: upper bound should be >= 18446744065119617025
|
||||||
}
|
}
|
||||||
if (ul >= 10) {
|
if (ul >= 10) {
|
||||||
range(ul); // $ range=>=10
|
range(ul); // $ range=>=10
|
||||||
unsigned long result = ul * ul;
|
unsigned long result = ul * ul; // $ overflow=+
|
||||||
range(result); // $ range=>=100
|
range(result); // $ MISSING: range=>=100
|
||||||
return result; // BUG: lower bound should be 0 (overflow is possible)
|
return result; // BUG: lower bound should be 0 (overflow is possible)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -800,13 +800,13 @@ int mul_by_constant(int i, int j) {
|
|||||||
i = 5 * i;
|
i = 5 * i;
|
||||||
range(i); // $ range=<=10 range=>=-5
|
range(i); // $ range=<=10 range=>=-5
|
||||||
|
|
||||||
i = i * -3;
|
i = i * -3; // $ overflow=+-
|
||||||
range(i); // -30 .. 15
|
range(i); // -30 .. 15
|
||||||
|
|
||||||
i *= 7;
|
i *= 7; // $ overflow=+-
|
||||||
range(i); // -210 .. 105
|
range(i); // -210 .. 105
|
||||||
|
|
||||||
i *= -11;
|
i *= -11; // $ overflow=+-
|
||||||
range(i); // -1155 .. 2310
|
range(i); // -1155 .. 2310
|
||||||
}
|
}
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
@@ -815,7 +815,7 @@ int mul_by_constant(int i, int j) {
|
|||||||
i = i * (int)0xffFFffFF; // fully converted literal is -1
|
i = i * (int)0xffFFffFF; // fully converted literal is -1
|
||||||
range(i); // $ range===1
|
range(i); // $ range===1
|
||||||
}
|
}
|
||||||
i = i * -1;
|
i = i * -1; // $ overflow=+-
|
||||||
range( i); // -2^31 .. 2^31-1
|
range( i); // -2^31 .. 2^31-1
|
||||||
|
|
||||||
signed char sc = 1;
|
signed char sc = 1;
|
||||||
@@ -873,11 +873,11 @@ void notequal_refinement(short n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (n != 0) {
|
while (n != 0) {
|
||||||
range(n); // $ range=<=n+0
|
range(n); // $ MISSING:range=<=n+0
|
||||||
n--; // 1 ..
|
n--; // 1 ..
|
||||||
}
|
}
|
||||||
|
|
||||||
range(n); // $ range=<=n+0 // 0 .. 0
|
range(n); // $ MISSING:range=<=n+0 // 0 .. 0
|
||||||
}
|
}
|
||||||
|
|
||||||
void notequal_variations(short n, float f) {
|
void notequal_variations(short n, float f) {
|
||||||
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n >= 5) {
|
if (n >= 5) {
|
||||||
if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow)
|
if (2 * n - 10 == 0) { // $ overflow=+
|
||||||
range(n); // $ range=>=5 MISSING: range===5
|
range(n); // $ range=>=5 MISSING: range===5
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -921,7 +921,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
|
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
|
||||||
range(ss); // $ range=<=32768 MISSING: range=>=-32768
|
range(ss); // $ overflow=+ range=<=32768 MISSING: range=>=-32768
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((short)us >= 0) {
|
if ((short)us >= 0) {
|
||||||
@@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
|||||||
range(ss); // -32768 .. 32767
|
range(ss); // -32768 .. 32767
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ss + 1 < sizeof(int)) {
|
if (ss + 1 < sizeof(int)) { // $ overflow=+
|
||||||
range(ss); // -1 .. 2
|
range(ss); // -1 .. 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1020,7 @@ void test_overflow() {
|
|||||||
|
|
||||||
void test_negate_unsigned(unsigned u) {
|
void test_negate_unsigned(unsigned u) {
|
||||||
if(10 < u && u < 20) {
|
if(10 < u && u < 20) {
|
||||||
range<unsigned>(-u); // underflows
|
range<unsigned>(-u); // $ overflow=-
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,17 @@
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y - 2 == x && y > 300) {
|
if (y - 2 == x && y > 300) { // $ overflow=-
|
||||||
range(x + y); // $ range=<=802 range=>=600
|
range(x + y); // $ range=<=802 range=>=600
|
||||||
return x + y;
|
return x + y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x != y + 1) {
|
if (x != y + 1) { // $ overflow=+
|
||||||
range(x); // $ range=<=400
|
range(x); // $ range=<=400
|
||||||
int sum = x + y;
|
int sum = x + y; // $ overflow=+-
|
||||||
} else {
|
} else {
|
||||||
if (y > 300) {
|
if (y > 300) {
|
||||||
range(x); // $ range=>=302 range=<=400 range===y+1
|
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
|
||||||
range(y); // $ range=>=301 range=<=399 range===x-1
|
range(y); // $ range=>=301 range=<=399 range===x-1
|
||||||
int sum = x + y;
|
int sum = x + y;
|
||||||
}
|
}
|
||||||
@@ -38,10 +38,10 @@
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) {
|
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
|
||||||
range(x); // $ range===349 range===y+1 range===z-1
|
range(x); // $ range===349 range===y+1 range===z-1
|
||||||
range(y); // $ range===348 range===x-1 range===z-2
|
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
|
||||||
range(z); // $ range===350 range===x+1 range===y+2
|
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
|
||||||
return x + y + z;
|
return x + y + z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysis
|
|||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
import semmle.code.cpp.ir.IR as IR
|
import semmle.code.cpp.ir.IR as IR
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
module SignAnalysisInstantiated = SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImpl>>;
|
module SignAnalysisInstantiated =
|
||||||
|
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||||
|
|
||||||
class SignAnalysisTest extends InlineExpectationsTest {
|
class SignAnalysisTest extends InlineExpectationsTest {
|
||||||
SignAnalysisTest() { this = "SignAnalysisTest" }
|
SignAnalysisTest() { this = "SignAnalysisTest" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
| a1.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
|
| a1.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
|
||||||
| a1.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||||
| a1.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
||||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
||||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 0 | empty |
|
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 0 | empty |
|
||||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 1 | nonempty |
|
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 1 | nonempty |
|
||||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 2 | i |
|
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 2 | i |
|
||||||
| a2.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
|
| a2.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
|
||||||
| a2.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||||
| a2.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
||||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
||||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
| a1.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||||
| a1.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||||
| a1.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
| a1.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
||||||
| a1.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
| a1.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
||||||
| a1.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
| a1.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
| a1.c:36:8:36:10 | Bar | 0 | file://:0:0:0:0 | Empty * | 1 types |
|
| a1.c:36:8:36:10 | Bar | 0 | file://:0:0:0:0 | Empty * | 1 types |
|
||||||
| a1.c:36:8:36:10 | Bar | 1 | file://:0:0:0:0 | NonEmpty * | 1 types |
|
| a1.c:36:8:36:10 | Bar | 1 | file://:0:0:0:0 | NonEmpty * | 1 types |
|
||||||
| a1.c:36:8:36:10 | Bar | 2 | file://:0:0:0:0 | int | 1 types |
|
| a1.c:36:8:36:10 | Bar | 2 | file://:0:0:0:0 | int | 1 types |
|
||||||
| a2.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||||
| a2.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||||
| a2.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
| a2.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
||||||
| a2.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
| a2.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
||||||
| a2.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
| a2.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<queries language="cpp"/>
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
edges
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||||
|
| test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a |
|
||||||
|
| test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||||
|
| test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a |
|
||||||
|
| test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||||
|
nodes
|
||||||
|
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:30:10:30:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:31:27:31:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:35:10:35:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:37:27:37:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:50:27:50:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:51:10:51:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:103:10:103:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:128:10:128:11 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||||
|
subpaths
|
||||||
|
#select
|
||||||
|
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Critical/DoubleFree.ql
|
||||||
@@ -26,6 +26,72 @@
|
|||||||
| test.cpp:128:15:128:16 | v4 |
|
| test.cpp:128:15:128:16 | v4 |
|
||||||
| test.cpp:185:10:185:12 | cpy |
|
| test.cpp:185:10:185:12 | cpy |
|
||||||
| test.cpp:199:10:199:12 | cpy |
|
| test.cpp:199:10:199:12 | cpy |
|
||||||
|
| test_free.cpp:11:10:11:10 | a |
|
||||||
|
| test_free.cpp:14:10:14:10 | a |
|
||||||
|
| test_free.cpp:16:10:16:10 | a |
|
||||||
|
| test_free.cpp:18:18:18:18 | a |
|
||||||
|
| test_free.cpp:23:10:23:10 | a |
|
||||||
|
| test_free.cpp:25:10:25:10 | a |
|
||||||
|
| test_free.cpp:26:10:26:10 | b |
|
||||||
|
| test_free.cpp:30:10:30:10 | a |
|
||||||
|
| test_free.cpp:31:27:31:27 | a |
|
||||||
|
| test_free.cpp:35:10:35:10 | a |
|
||||||
|
| test_free.cpp:37:27:37:27 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a |
|
||||||
|
| test_free.cpp:46:10:46:10 | a |
|
||||||
|
| test_free.cpp:50:27:50:27 | a |
|
||||||
|
| test_free.cpp:51:10:51:10 | a |
|
||||||
|
| test_free.cpp:55:27:55:27 | a |
|
||||||
|
| test_free.cpp:57:10:57:10 | a |
|
||||||
|
| test_free.cpp:61:10:61:10 | a |
|
||||||
|
| test_free.cpp:63:10:63:10 | b |
|
||||||
|
| test_free.cpp:69:10:69:10 | a |
|
||||||
|
| test_free.cpp:72:14:72:14 | a |
|
||||||
|
| test_free.cpp:83:12:83:12 | a |
|
||||||
|
| test_free.cpp:85:12:85:12 | a |
|
||||||
|
| test_free.cpp:90:10:90:10 | a |
|
||||||
|
| test_free.cpp:95:10:95:10 | a |
|
||||||
|
| test_free.cpp:101:10:101:10 | a |
|
||||||
|
| test_free.cpp:102:23:102:23 | a |
|
||||||
|
| test_free.cpp:103:10:103:10 | a |
|
||||||
|
| test_free.cpp:104:10:104:10 | b |
|
||||||
|
| test_free.cpp:107:23:107:23 | a |
|
||||||
|
| test_free.cpp:112:14:112:14 | a |
|
||||||
|
| test_free.cpp:114:10:114:10 | b |
|
||||||
|
| test_free.cpp:118:23:118:23 | a |
|
||||||
|
| test_free.cpp:119:17:119:17 | b |
|
||||||
|
| test_free.cpp:121:14:121:14 | a |
|
||||||
|
| test_free.cpp:126:10:126:11 | * ... |
|
||||||
|
| test_free.cpp:128:10:128:11 | * ... |
|
||||||
|
| test_free.cpp:129:10:129:11 | * ... |
|
||||||
|
| test_free.cpp:131:10:131:13 | access to array |
|
||||||
|
| test_free.cpp:132:10:132:13 | access to array |
|
||||||
|
| test_free.cpp:143:27:143:30 | data |
|
||||||
|
| test_free.cpp:145:14:145:22 | * ... |
|
||||||
|
| test_free.cpp:148:10:148:17 | list_ptr |
|
||||||
|
| test_free.cpp:152:27:152:27 | a |
|
||||||
|
| test_free.cpp:154:10:154:10 | a |
|
||||||
|
| test_free.cpp:159:14:159:15 | * ... |
|
||||||
|
| test_free.cpp:162:10:162:10 | a |
|
||||||
|
| test_free.cpp:167:23:167:23 | a |
|
||||||
|
| test_free.cpp:173:10:173:10 | a |
|
||||||
|
| test_free.cpp:181:10:181:10 | a |
|
||||||
|
| test_free.cpp:183:10:183:10 | a |
|
||||||
|
| test_free.cpp:185:10:185:10 | a |
|
||||||
|
| test_free.cpp:188:10:188:10 | a |
|
||||||
|
| test_free.cpp:193:20:193:20 | a |
|
||||||
|
| test_free.cpp:199:20:199:20 | a |
|
||||||
|
| test_free.cpp:205:10:205:10 | a |
|
||||||
|
| test_free.cpp:207:10:207:10 | a |
|
||||||
|
| test_free.cpp:209:10:209:10 | a |
|
||||||
|
| test_free.cpp:213:10:213:10 | a |
|
||||||
|
| test_free.cpp:216:10:216:10 | a |
|
||||||
|
| test_free.cpp:220:10:220:10 | a |
|
||||||
|
| test_free.cpp:227:24:227:45 | memory_descriptor_list |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... |
|
||||||
| virtual.cpp:18:10:18:10 | a |
|
| virtual.cpp:18:10:18:10 | a |
|
||||||
| virtual.cpp:19:10:19:10 | c |
|
| virtual.cpp:19:10:19:10 | c |
|
||||||
| virtual.cpp:38:10:38:10 | b |
|
| virtual.cpp:38:10:38:10 | b |
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
| test_free.cpp:36:22:36:35 | ... = ... | This memory allocation may not be released at $@. | test_free.cpp:38:1:38:1 | return ... | this exit point |
|
||||||
|
|||||||
@@ -11,3 +11,4 @@
|
|||||||
| test.cpp:156:3:156:26 | new | This memory is never freed. |
|
| test.cpp:156:3:156:26 | new | This memory is never freed. |
|
||||||
| test.cpp:157:3:157:26 | new[] | This memory is never freed. |
|
| test.cpp:157:3:157:26 | new[] | This memory is never freed. |
|
||||||
| test.cpp:169:14:169:19 | call to strdup | This memory is never freed. |
|
| test.cpp:169:14:169:19 | call to strdup | This memory is never freed. |
|
||||||
|
| test_free.cpp:167:15:167:21 | call to realloc | This memory is never freed. |
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
edges
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
|
||||||
|
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
|
||||||
|
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
|
||||||
|
| test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a |
|
||||||
|
| test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||||
|
nodes
|
||||||
|
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:13:6:13:6 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:71:9:71:9 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:91:5:91:5 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:95:10:95:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:96:9:96:9 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:102:23:102:23 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:153:5:153:5 | a | semmle.label | a |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:241:10:241:10 | b | semmle.label | b |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
||||||
|
subpaths
|
||||||
|
#select
|
||||||
|
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:96:9:96:9 | a | test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a | Memory may have been previously freed by $@. | test_free.cpp:95:5:95:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:102:23:102:23 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a | Memory may have been previously freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
|
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Critical/UseAfterFree.ql
|
||||||
247
cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp
Normal file
247
cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
void *malloc(int);
|
||||||
|
void free(void *);
|
||||||
|
bool condition();
|
||||||
|
void use(void*);
|
||||||
|
void *realloc(void*, unsigned long);
|
||||||
|
int strlen(char*);
|
||||||
|
int asprintf(char ** strp, const char * fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
|
void* test_double_free1(int *a) {
|
||||||
|
free(a); // GOOD
|
||||||
|
a[5] = 5; // BAD
|
||||||
|
*a = 5; // BAD
|
||||||
|
free(a); // BAD
|
||||||
|
a = (int*) malloc(8);
|
||||||
|
free(a); // GOOD
|
||||||
|
a = (int*) malloc(8);
|
||||||
|
if (!a) free(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_double_free_aliasing(void *a, void* b) {
|
||||||
|
free(a); // GOOD
|
||||||
|
a = b;
|
||||||
|
free(a); // GOOD
|
||||||
|
free(b); // BAD [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dominance1(void *a) {
|
||||||
|
free(a);
|
||||||
|
if (condition()) free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dominance2(void *a) {
|
||||||
|
free(a);
|
||||||
|
if (condition()) a = malloc(10);
|
||||||
|
if (condition()) free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_post_dominance1(int *a)
|
||||||
|
{
|
||||||
|
if (condition()) free(a);
|
||||||
|
if (condition()) a[2] = 5; // BAD [NOT DETECTED]
|
||||||
|
if (condition()) free(a); // BAD [NOT DETECTED]
|
||||||
|
a[2] = 5; // BAD
|
||||||
|
free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_post_dominance2(void *a) {
|
||||||
|
if (condition()) free(a);
|
||||||
|
free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_post_dominance3(void *a) {
|
||||||
|
if (condition()) free(a);
|
||||||
|
a = malloc(10);
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_use_after_free6(int *a, int *b) {
|
||||||
|
free(a);
|
||||||
|
a=b;
|
||||||
|
free(b);
|
||||||
|
if (condition()) a[0] = 5; // BAD [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_use_after_free7(int *a) {
|
||||||
|
a[0] = 42;
|
||||||
|
free(a);
|
||||||
|
|
||||||
|
if (a[3]) { // BAD
|
||||||
|
free(a); // BAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
void f();
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_new1() {
|
||||||
|
A *a = new A();
|
||||||
|
delete(a);
|
||||||
|
a->f(); // BAD [NOT DETECTED]
|
||||||
|
delete(a); // BAD [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dereference1(A *a) {
|
||||||
|
a->f(); // GOOD
|
||||||
|
free(a);
|
||||||
|
a->f(); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void* use_after_free(void *a) {
|
||||||
|
free(a);
|
||||||
|
use(a); // BAD
|
||||||
|
return a; // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc1(void *a) {
|
||||||
|
free(a);
|
||||||
|
void *b = realloc(a, sizeof(a)*3); // BAD [NOT DETECTED by cpp/double-free]
|
||||||
|
free(a); // BAD
|
||||||
|
free(b); // GOOD
|
||||||
|
}
|
||||||
|
void* test_realloc2(char *a) {
|
||||||
|
void *b = realloc(a, strlen(a)+3); // GOOD
|
||||||
|
|
||||||
|
// From the man page on return values from realloc and reallocarray:
|
||||||
|
// "If these functions fail, the original block is left untouched; it is not freed or moved."
|
||||||
|
if (!b) {
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
free(b); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc3(void *a) {
|
||||||
|
void *b = realloc(a, 100);
|
||||||
|
if (b) free(b); // GOOD
|
||||||
|
if (!b) {
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ptr_deref(void ** a) {
|
||||||
|
free(*a);
|
||||||
|
*a = malloc(10);
|
||||||
|
free(*a); // GOOD
|
||||||
|
free(*a); // BAD [NOT DETECTED]
|
||||||
|
*a = malloc(10);
|
||||||
|
free(a[0]); // GOOD
|
||||||
|
free(a[1]); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
struct list {
|
||||||
|
struct list *next;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_loop1(struct list ** list_ptr) {
|
||||||
|
struct list *next;
|
||||||
|
while (*list_ptr) { // GOOD
|
||||||
|
free((*list_ptr)->data); // GOOD
|
||||||
|
next = (*list_ptr)->next; // GOOD
|
||||||
|
free(*list_ptr); // GOOD
|
||||||
|
*list_ptr = next; // GOOD
|
||||||
|
}
|
||||||
|
free(list_ptr); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_use_after_free8(struct list * a) {
|
||||||
|
if (condition()) free(a);
|
||||||
|
a->data = malloc(10); // BAD
|
||||||
|
free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_loop2(char ** a) {
|
||||||
|
while (*a) { // GOOD
|
||||||
|
free(*a); // GOOD
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void* test_realloc4() {
|
||||||
|
void *a = 0;
|
||||||
|
void *b = realloc(a, 10); // BAD for cpp/memory-never-freed
|
||||||
|
if (!b) { return a; }
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sizeof(int *a) {
|
||||||
|
free(a);
|
||||||
|
int x = sizeof(a[0]); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void call_by_reference(char * &a);
|
||||||
|
int custom_alloc_func(char ** a);
|
||||||
|
|
||||||
|
void test_reassign(char *a) {
|
||||||
|
free(a); // GOOD
|
||||||
|
asprintf(&a, "Hello world"); // GOOD
|
||||||
|
free(a); //GOOD
|
||||||
|
call_by_reference(a); // GOOD
|
||||||
|
free(a); // GOOD
|
||||||
|
int v;
|
||||||
|
if (v = custom_alloc_func(&a)) return;
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
char* test_return1(char *a) {
|
||||||
|
int ret = condition();
|
||||||
|
if (!ret) free(a);
|
||||||
|
return (ret ? a : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* test_return2(char *a) {
|
||||||
|
int ret = condition();
|
||||||
|
if (!ret) free(a);
|
||||||
|
if (ret) return a;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_condition1(char *a) {
|
||||||
|
free(a);
|
||||||
|
if (asprintf(&a, "Hello world") || condition());
|
||||||
|
free(a); //GOOD
|
||||||
|
if (condition() || asprintf(&a, "Hello world"));
|
||||||
|
free(a); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_condition2(char *a) {
|
||||||
|
free(a);
|
||||||
|
if (condition()) a = (char*) malloc(10);
|
||||||
|
else custom_alloc_func(&a);
|
||||||
|
free(a); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void* test_return1(void *a) {
|
||||||
|
free(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MmFreePagesFromMdl(void*);
|
||||||
|
void ExFreePool(void*);
|
||||||
|
void test_ms_free(void * memory_descriptor_list) {
|
||||||
|
MmFreePagesFromMdl(memory_descriptor_list); //GOOD
|
||||||
|
ExFreePool(memory_descriptor_list); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_loop3(char ** a, char ** b) {
|
||||||
|
if (*a) {
|
||||||
|
free(*a);
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
use(*a); // GOOD [FALSE POSITIVE]
|
||||||
|
|
||||||
|
for (;*b; b++) {
|
||||||
|
free(*b);
|
||||||
|
}
|
||||||
|
use(*b); // GOOD [FALSE POSITIVE]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_deref(char **a) {
|
||||||
|
free(*a);
|
||||||
|
use(*a); // GOOD [FALSE POSITIVE]
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
| test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
| test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:51:7:51:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:50:3:50:7 | call to scanf | call to scanf |
|
|
||||||
| test.cpp:68:7:68:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:67:3:67:7 | call to scanf | call to scanf |
|
| test.cpp:68:7:68:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:67:3:67:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:80:7:80:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:79:3:79:7 | call to scanf | call to scanf |
|
| test.cpp:80:7:80:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:79:3:79:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:90:8:90:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
|
| test.cpp:90:7:90:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:98:8:98:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
|
| test.cpp:98:7:98:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:108:7:108:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:107:3:107:8 | call to fscanf | call to fscanf |
|
| test.cpp:108:7:108:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:107:3:107:8 | call to fscanf | call to fscanf |
|
||||||
| test.cpp:115:7:115:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:114:3:114:8 | call to sscanf | call to sscanf |
|
| test.cpp:115:7:115:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:114:3:114:8 | call to sscanf | call to sscanf |
|
||||||
| test.cpp:164:8:164:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:162:7:162:11 | call to scanf | call to scanf |
|
| test.cpp:164:8:164:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:162:7:162:11 | call to scanf | call to scanf |
|
||||||
@@ -12,13 +11,9 @@
|
|||||||
| test.cpp:224:8:224:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:221:7:221:11 | call to scanf | call to scanf |
|
| test.cpp:224:8:224:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:221:7:221:11 | call to scanf | call to scanf |
|
||||||
| test.cpp:248:9:248:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:246:25:246:29 | call to scanf | call to scanf |
|
| test.cpp:248:9:248:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:246:25:246:29 | call to scanf | call to scanf |
|
||||||
| test.cpp:252:9:252:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:250:14:250:18 | call to scanf | call to scanf |
|
| test.cpp:252:9:252:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:250:14:250:18 | call to scanf | call to scanf |
|
||||||
| test.cpp:264:7:264:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:263:3:263:7 | call to scanf | call to scanf |
|
|
||||||
| test.cpp:272:7:272:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:3:271:7 | call to scanf | call to scanf |
|
| test.cpp:272:7:272:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:3:271:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:280:7:280:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:279:3:279:7 | call to scanf | call to scanf |
|
| test.cpp:280:7:280:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:279:3:279:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:292:7:292:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:291:3:291:7 | call to scanf | call to scanf |
|
| test.cpp:292:7:292:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:291:3:291:7 | call to scanf | call to scanf |
|
||||||
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
|
|
||||||
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
|
|
||||||
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
|
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
|
||||||
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
|
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
|
||||||
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
||||||
| test.cpp:430:6:430:6 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:429:2:429:6 | call to scanf | call to scanf |
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ int main()
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(i); // BAD. Design choice: already initialized variables shouldn't make a difference.
|
use(i); // GOOD. Design choice: already initialized variables are fine.
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -261,7 +261,7 @@ int main()
|
|||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(i); // BAD
|
use(i); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -269,7 +269,7 @@ int main()
|
|||||||
|
|
||||||
set_by_ref(i);
|
set_by_ref(i);
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(i); // BAD
|
use(i); // GOOD [FALSE POSITIVE]
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -277,7 +277,7 @@ int main()
|
|||||||
|
|
||||||
set_by_ptr(&i);
|
set_by_ptr(&i);
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(i); // BAD
|
use(i); // GOOD [FALSE POSITIVE]
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -299,7 +299,7 @@ int main()
|
|||||||
int *ptr_i = &i;
|
int *ptr_i = &i;
|
||||||
|
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(*ptr_i); // BAD: may not have written `i`
|
use(*ptr_i); // BAD [NOT DETECTED]: may not have written `i`
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -307,7 +307,7 @@ int main()
|
|||||||
int *ptr_i = &i;
|
int *ptr_i = &i;
|
||||||
|
|
||||||
scanf("%d", ptr_i);
|
scanf("%d", ptr_i);
|
||||||
use(i); // BAD: may not have written `*ptr_i`
|
use(i); // BAD [NOT DETECTED]: may not have written `*ptr_i`
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -427,5 +427,5 @@ void scan_and_write() {
|
|||||||
void scan_and_static_variable() {
|
void scan_and_static_variable() {
|
||||||
static int i;
|
static int i;
|
||||||
scanf("%d", &i);
|
scanf("%d", &i);
|
||||||
use(i); // GOOD [FALSE POSITIVE]: static variables are always 0-initialized
|
use(i); // GOOD: static variables are always 0-initialized
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,74 @@
|
|||||||
| test.cpp:36:6:36:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:35:2:35:5 | call to free | been previously freed |
|
edges
|
||||||
| test.cpp:70:7:70:10 | data | Memory pointed to by 'data' may have $@. | test.cpp:67:2:67:5 | call to free | been previously freed |
|
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
|
||||||
| test.cpp:107:6:107:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:105:2:105:5 | call to free | been previously freed |
|
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
|
||||||
| test.cpp:117:6:117:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:115:2:115:5 | call to free | been previously freed |
|
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
|
||||||
| test.cpp:150:2:150:2 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
|
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
|
||||||
| test.cpp:151:4:151:4 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
|
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
|
||||||
| test.cpp:170:6:170:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:165:2:165:5 | call to free | been previously freed |
|
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
|
||||||
| test.cpp:193:6:193:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:191:3:191:6 | call to free | been previously freed |
|
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
|
||||||
| test.cpp:201:6:201:6 | x | Memory pointed to by 'x' may have $@. | test.cpp:200:2:200:9 | delete | been previously freed |
|
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
|
||||||
|
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
|
||||||
|
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
|
||||||
|
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
|
||||||
|
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
|
||||||
|
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
|
||||||
|
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
|
||||||
|
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
|
||||||
|
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
|
||||||
|
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
|
||||||
|
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
|
||||||
|
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
|
||||||
|
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
|
||||||
|
nodes
|
||||||
|
| test.cpp:39:7:39:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:39:7:39:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:41:6:41:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:75:7:75:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:75:7:75:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:79:7:79:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:106:7:106:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:106:7:106:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:108:6:108:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:116:7:116:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:116:7:116:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:119:6:119:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:127:7:127:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:127:7:127:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:130:6:130:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:138:7:138:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:138:7:138:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:141:6:141:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:181:7:181:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:181:7:181:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:186:6:186:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:192:7:192:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:192:7:192:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:197:6:197:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:203:7:203:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:203:7:203:10 | data | semmle.label | data |
|
||||||
|
| test.cpp:207:8:207:11 | data | semmle.label | data |
|
||||||
|
| test.cpp:207:8:207:11 | data | semmle.label | data |
|
||||||
|
| test.cpp:209:6:209:9 | data | semmle.label | data |
|
||||||
|
| test.cpp:209:6:209:9 | data | semmle.label | data |
|
||||||
|
subpaths
|
||||||
|
#select
|
||||||
|
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
|
||||||
|
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
|
||||||
|
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
|
||||||
|
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
|
||||||
|
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
|
||||||
|
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
|
||||||
|
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
|
||||||
|
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
|
||||||
|
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
|
||||||
|
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
|
||||||
|
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
|
||||||
|
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
|
||||||
|
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
|
||||||
|
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
|
||||||
|
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
|
||||||
|
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
|
||||||
|
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
|
||||||
|
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
|
||||||
|
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
|
||||||
|
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
|
||||||
|
|||||||
@@ -6,14 +6,18 @@ typedef unsigned long size_t;
|
|||||||
void *malloc(size_t size);
|
void *malloc(size_t size);
|
||||||
void free(void *ptr);
|
void free(void *ptr);
|
||||||
|
|
||||||
void useExternal(char* data);
|
void useExternal(...);
|
||||||
|
|
||||||
void use(char* data)
|
void use_if_nonzero(char* data)
|
||||||
{
|
{
|
||||||
if (data)
|
if (data)
|
||||||
useExternal(data);
|
useExternal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void use(char* data) {
|
||||||
|
useExternal(*data);
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void noReturn();
|
void noReturn();
|
||||||
|
|
||||||
@@ -31,8 +35,9 @@ void test1()
|
|||||||
{
|
{
|
||||||
char* data;
|
char* data;
|
||||||
data = (char *)malloc(100*sizeof(char));
|
data = (char *)malloc(100*sizeof(char));
|
||||||
use(data); // GOOD
|
use_if_nonzero(data); // GOOD
|
||||||
free(data);
|
free(data);
|
||||||
|
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||||
use(data); // BAD
|
use(data); // BAD
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,9 +47,11 @@ void test2()
|
|||||||
data = (char *)malloc(100*sizeof(char));
|
data = (char *)malloc(100*sizeof(char));
|
||||||
free(data);
|
free(data);
|
||||||
myMalloc(&data);
|
myMalloc(&data);
|
||||||
|
use_if_nonzero(data); // GOOD
|
||||||
use(data); // GOOD
|
use(data); // GOOD
|
||||||
free(data);
|
free(data);
|
||||||
myMalloc2(data);
|
myMalloc2(data);
|
||||||
|
use_if_nonzero(data); // GOOD
|
||||||
use(data); // GOOD
|
use(data); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +63,7 @@ void test3()
|
|||||||
data = NULL;
|
data = NULL;
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
|
use_if_nonzero(data); // GOOD
|
||||||
use(data); // GOOD
|
use(data); // GOOD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,6 +75,7 @@ void test4()
|
|||||||
free(data);
|
free(data);
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
|
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||||
use(data); // BAD
|
use(data); // BAD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +94,8 @@ char* returnsFreedData(int i)
|
|||||||
void test5()
|
void test5()
|
||||||
{
|
{
|
||||||
char* data = returnsFreedData(1);
|
char* data = returnsFreedData(1);
|
||||||
use(data); // BAD (NOT REPORTED)
|
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||||
|
use(data); // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test6()
|
void test6()
|
||||||
@@ -94,7 +104,8 @@ void test6()
|
|||||||
data = (char *)malloc(100*sizeof(char));
|
data = (char *)malloc(100*sizeof(char));
|
||||||
data2 = data;
|
data2 = data;
|
||||||
free(data);
|
free(data);
|
||||||
use(data2); // BAD (NOT REPORTED)
|
use_if_nonzero(data2); // BAD [NOT DETECTED]
|
||||||
|
use(data); // BAD
|
||||||
}
|
}
|
||||||
|
|
||||||
void test7()
|
void test7()
|
||||||
@@ -104,6 +115,7 @@ void test7()
|
|||||||
data2 = data;
|
data2 = data;
|
||||||
free(data);
|
free(data);
|
||||||
data2 = NULL;
|
data2 = NULL;
|
||||||
|
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||||
use(data); // BAD
|
use(data); // BAD
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +126,7 @@ void test8()
|
|||||||
data = data2;
|
data = data2;
|
||||||
free(data);
|
free(data);
|
||||||
data2 = NULL;
|
data2 = NULL;
|
||||||
|
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||||
use(data); // BAD
|
use(data); // BAD
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,13 +137,15 @@ void test9()
|
|||||||
char *data, *data2;
|
char *data, *data2;
|
||||||
free(data);
|
free(data);
|
||||||
noReturnWrapper();
|
noReturnWrapper();
|
||||||
use(data); // GOOD
|
use_if_nonzero(data); // GOOD
|
||||||
|
use(data); // GOOD [FALSE POSITIVE]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test10()
|
void test10()
|
||||||
{
|
{
|
||||||
for (char *data; true; data = NULL)
|
for (char *data; true; data = NULL)
|
||||||
{
|
{
|
||||||
|
use_if_nonzero(data); // GOOD
|
||||||
use(data); // GOOD
|
use(data); // GOOD
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
@@ -156,7 +171,8 @@ template<class T> T test()
|
|||||||
T* x;
|
T* x;
|
||||||
use(x); // GOOD
|
use(x); // GOOD
|
||||||
delete x;
|
delete x;
|
||||||
use(x); // BAD
|
use_if_nonzero(x); // BAD [NOT DETECTED]
|
||||||
|
use(x); // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test12(int count)
|
void test12(int count)
|
||||||
@@ -178,7 +194,7 @@ void test13()
|
|||||||
{
|
{
|
||||||
data = NULL;
|
data = NULL;
|
||||||
}
|
}
|
||||||
use(data); // GOOD
|
use(data); // GOOD [FALSE POSITIVE]
|
||||||
}
|
}
|
||||||
|
|
||||||
void test14()
|
void test14()
|
||||||
@@ -198,7 +214,7 @@ template<class T> T test15()
|
|||||||
T* x;
|
T* x;
|
||||||
use(x); // GOOD
|
use(x); // GOOD
|
||||||
delete x;
|
delete x;
|
||||||
use(x); // BAD
|
use(x); // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
void test15runner(void)
|
void test15runner(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-all
|
name: codeql/csharp-solorigate-all
|
||||||
version: 1.5.0
|
version: 1.5.1-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-queries
|
name: codeql/csharp-solorigate-queries
|
||||||
version: 1.5.0
|
version: 1.5.1-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<queries language="csharp"/>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-all
|
name: codeql/csharp-all
|
||||||
version: 0.6.0
|
version: 0.6.1-dev
|
||||||
groups: csharp
|
groups: csharp
|
||||||
dbscheme: semmlecode.csharp.dbscheme
|
dbscheme: semmlecode.csharp.dbscheme
|
||||||
extractor: csharp
|
extractor: csharp
|
||||||
|
|||||||
@@ -52,23 +52,24 @@ class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation {
|
|||||||
class DapperCommandDefinitionMethodCallSqlExpr extends SqlExpr, ObjectCreation {
|
class DapperCommandDefinitionMethodCallSqlExpr extends SqlExpr, ObjectCreation {
|
||||||
DapperCommandDefinitionMethodCallSqlExpr() {
|
DapperCommandDefinitionMethodCallSqlExpr() {
|
||||||
this.getObjectType() instanceof Dapper::CommandDefinitionStruct and
|
this.getObjectType() instanceof Dapper::CommandDefinitionStruct and
|
||||||
exists(Conf c | c.hasFlow(DataFlow::exprNode(this), _))
|
DapperCommandDefinitionMethodCallSql::flow(DataFlow::exprNode(this), _)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getSql() { result = this.getArgumentForName("commandText") }
|
override Expr getSql() { result = this.getArgumentForName("commandText") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Conf extends DataFlow4::Configuration {
|
private module DapperCommandDefitionMethodCallSqlConfig implements DataFlow::ConfigSig {
|
||||||
Conf() { this = "DapperCommandDefinitionFlowConfig" }
|
predicate isSource(DataFlow::Node node) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) {
|
|
||||||
node.asExpr().(ObjectCreation).getObjectType() instanceof Dapper::CommandDefinitionStruct
|
node.asExpr().(ObjectCreation).getObjectType() instanceof Dapper::CommandDefinitionStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) {
|
predicate isSink(DataFlow::Node node) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
mc.getTarget() = any(Dapper::SqlMapperClass c).getAQueryMethod() and
|
mc.getTarget() = any(Dapper::SqlMapperClass c).getAQueryMethod() and
|
||||||
node.asExpr() = mc.getArgumentForName("command")
|
node.asExpr() = mc.getArgumentForName("command")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module DapperCommandDefinitionMethodCallSql =
|
||||||
|
DataFlow::Global<DapperCommandDefitionMethodCallSqlConfig>;
|
||||||
|
|||||||
@@ -162,18 +162,14 @@ class XmlReaderSettingsCreation extends ObjectCreation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SettingsDataFlowConfig extends DataFlow3::Configuration {
|
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
|
||||||
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof XmlReaderSettingsCreation }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof XmlReaderSettingsInstance }
|
||||||
source.asExpr() instanceof XmlReaderSettingsCreation
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() instanceof XmlReaderSettingsInstance
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
|
||||||
|
|
||||||
/** A call to `XmlReader.Create`. */
|
/** A call to `XmlReader.Create`. */
|
||||||
class XmlReaderCreateCall extends MethodCall {
|
class XmlReaderCreateCall extends MethodCall {
|
||||||
XmlReaderCreateCall() { this.getTarget() = any(SystemXmlXmlReaderClass r).getCreateMethod() }
|
XmlReaderCreateCall() { this.getTarget() = any(SystemXmlXmlReaderClass r).getCreateMethod() }
|
||||||
@@ -190,8 +186,6 @@ class XmlReaderSettingsInstance extends Expr {
|
|||||||
|
|
||||||
/** Gets a possible creation point for this instance of `XmlReaderSettings`. */
|
/** Gets a possible creation point for this instance of `XmlReaderSettings`. */
|
||||||
XmlReaderSettingsCreation getASettingsCreation() {
|
XmlReaderSettingsCreation getASettingsCreation() {
|
||||||
exists(SettingsDataFlowConfig settingsFlow |
|
SettingsDataFlow::flow(DataFlow::exprNode(result), DataFlow::exprNode(this))
|
||||||
settingsFlow.hasFlow(DataFlow::exprNode(result), DataFlow::exprNode(this))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,10 +78,12 @@ predicate isExponentialRegex(StringLiteral s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `ExponentialRegexDataflow` instead.
|
||||||
|
*
|
||||||
* A data flow configuration for tracking exponential worst case time regular expression string
|
* A data flow configuration for tracking exponential worst case time regular expression string
|
||||||
* literals to the pattern argument of a regex.
|
* literals to the pattern argument of a regex.
|
||||||
*/
|
*/
|
||||||
class ExponentialRegexDataflow extends DataFlow2::Configuration {
|
deprecated class ExponentialRegexDataflow extends DataFlow2::Configuration {
|
||||||
ExponentialRegexDataflow() { this = "ExponentialRegex" }
|
ExponentialRegexDataflow() { this = "ExponentialRegex" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
|
override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
|
||||||
@@ -89,15 +91,27 @@ class ExponentialRegexDataflow extends DataFlow2::Configuration {
|
|||||||
override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
|
override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data flow configuration for tracking exponential worst case time regular expression string
|
||||||
|
* literals to the pattern argument of a regex.
|
||||||
|
*/
|
||||||
|
private module ExponentialRegexDataFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
|
||||||
|
}
|
||||||
|
|
||||||
|
module ExponentialRegexDataFlow = DataFlow::Global<ExponentialRegexDataFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
|
* An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
|
||||||
* have exponential behavior.
|
* have exponential behavior.
|
||||||
*/
|
*/
|
||||||
class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
|
class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
|
||||||
ExponentialRegexSink() {
|
ExponentialRegexSink() {
|
||||||
exists(ExponentialRegexDataflow regexDataflow, RegexOperation regexOperation |
|
exists(RegexOperation regexOperation |
|
||||||
// Exponential regex flows to the pattern argument
|
// Exponential regex flows to the pattern argument
|
||||||
regexDataflow.hasFlow(_, DataFlow::exprNode(regexOperation.getPattern()))
|
ExponentialRegexDataFlow::flow(_, DataFlow::exprNode(regexOperation.getPattern()))
|
||||||
|
|
|
|
||||||
// This is used as an input for this pattern
|
// This is used as an input for this pattern
|
||||||
this.getExpr() = regexOperation.getInput() and
|
this.getExpr() = regexOperation.getInput() and
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
|||||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `TaintedPath` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "TaintedPath" }
|
TaintTrackingConfiguration() { this = "TaintedPath" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -38,6 +40,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||||
|
*/
|
||||||
|
private module TaintedPathConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for uncontrolled data in path expression vulnerabilities.
|
||||||
|
*/
|
||||||
|
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
|
|
||||||
|
|||||||
@@ -75,9 +75,11 @@ class JsonConvertTrackingConfig extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `TypeNameTracking` instead.
|
||||||
|
*
|
||||||
* Tracks unsafe `TypeNameHandling` setting to `JsonConvert` call
|
* Tracks unsafe `TypeNameHandling` setting to `JsonConvert` call
|
||||||
*/
|
*/
|
||||||
class TypeNameTrackingConfig extends DataFlow::Configuration {
|
deprecated class TypeNameTrackingConfig extends DataFlow::Configuration {
|
||||||
TypeNameTrackingConfig() { this = "TypeNameTrackingConfig" }
|
TypeNameTrackingConfig() { this = "TypeNameTrackingConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
@@ -127,6 +129,62 @@ class TypeNameTrackingConfig extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
|
||||||
|
*/
|
||||||
|
private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
(
|
||||||
|
source.asExpr() instanceof MemberConstantAccess and
|
||||||
|
source.getType() instanceof TypeNameHandlingEnum
|
||||||
|
or
|
||||||
|
source.asExpr() instanceof IntegerLiteral
|
||||||
|
) and
|
||||||
|
source.asExpr().hasValue() and
|
||||||
|
not source.asExpr().getValue() = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(MethodCall mc, Method m, Expr expr |
|
||||||
|
m = mc.getTarget() and
|
||||||
|
(
|
||||||
|
not mc.getArgument(0).hasValue() and
|
||||||
|
m instanceof NewtonsoftJsonConvertClassDeserializeObjectMethod
|
||||||
|
) and
|
||||||
|
expr = mc.getAnArgument() and
|
||||||
|
sink.asExpr() = expr and
|
||||||
|
expr.getType() instanceof JsonSerializerSettingsClass
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
node1.asExpr() instanceof IntegerLiteral and
|
||||||
|
node2.asExpr().(CastExpr).getExpr() = node1.asExpr()
|
||||||
|
or
|
||||||
|
node1.getType() instanceof TypeNameHandlingEnum and
|
||||||
|
exists(PropertyWrite pw, Property p, Assignment a |
|
||||||
|
a.getLValue() = pw and
|
||||||
|
pw.getProperty() = p and
|
||||||
|
p.getDeclaringType() instanceof JsonSerializerSettingsClass and
|
||||||
|
p.hasName("TypeNameHandling") and
|
||||||
|
(
|
||||||
|
node1.asExpr() = a.getRValue() and
|
||||||
|
node2.asExpr() = pw.getQualifier()
|
||||||
|
or
|
||||||
|
exists(ObjectInitializer oi |
|
||||||
|
node1.asExpr() = oi.getAMemberInitializer().getRValue() and
|
||||||
|
node2.asExpr() = oi
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
|
||||||
|
*/
|
||||||
|
module TypeNameTracking = DataFlow::Global<TypeNameTrackingConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User input to static method or constructor call deserialization flow tracking.
|
* User input to static method or constructor call deserialization flow tracking.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ abstract class Sanitizer extends DataFlow::ExprNode { }
|
|||||||
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
|
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `UrlRedirect` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
|
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "UrlRedirect" }
|
TaintTrackingConfiguration() { this = "UrlRedirect" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -49,6 +51,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
|
||||||
|
*/
|
||||||
|
private module UrlRedirectConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for reasoning about unvalidated URL redirect vulnerabilities.
|
||||||
|
*/
|
||||||
|
module UrlRedirect = TaintTracking::Global<UrlRedirectConfig>;
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,11 @@ private class InsecureXmlSink extends Sink {
|
|||||||
abstract class Sanitizer extends DataFlow::Node { }
|
abstract class Sanitizer extends DataFlow::Node { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `XmlEntityInjection` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for untrusted user input used in XML processing.
|
* A taint-tracking configuration for untrusted user input used in XML processing.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "XMLInjection" }
|
TaintTrackingConfiguration() { this = "XMLInjection" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -61,6 +63,36 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for untrusted user input used in XML processing.
|
||||||
|
*/
|
||||||
|
private module XmlEntityInjectionConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for untrusted user input used in XML processing.
|
||||||
|
*/
|
||||||
|
module XmlEntityInjection implements DataFlow::GlobalFlowSig {
|
||||||
|
import TaintTracking::Global<XmlEntityInjectionConfig> as Super
|
||||||
|
import Super
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data can flow from `source` to `sink`.
|
||||||
|
*
|
||||||
|
* The corresponding paths are generated from the end-points and the graph
|
||||||
|
* included in the module `PathGraph`.
|
||||||
|
*/
|
||||||
|
predicate flowPath(XmlEntityInjection::PathNode source, XmlEntityInjection::PathNode sink) {
|
||||||
|
Super::flowPath(source, sink) and
|
||||||
|
exists(sink.getNode().(Sink).getReason())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||||
|
|
||||||
private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
|
private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
|||||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `XpathInjection` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for untrusted user input used in XPath expression.
|
* A taint-tracking configuration for untrusted user input used in XPath expression.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "XPathInjection" }
|
TaintTrackingConfiguration() { this = "XPathInjection" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -36,6 +38,32 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for untrusted user input used in XPath expression.
|
||||||
|
*/
|
||||||
|
module XpathInjectionConfig implements DataFlow::ConfigSig {
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant data flow source.
|
||||||
|
*/
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant data flow sink.
|
||||||
|
*/
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `node` is prohibited. This completely removes
|
||||||
|
* `node` from the data flow graph.
|
||||||
|
*/
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for untrusted user input used in XPath expression.
|
||||||
|
*/
|
||||||
|
module XpathInjection = TaintTracking::Global<XpathInjectionConfig>;
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,12 @@ abstract class Sanitizer extends DataFlow::ExprNode { }
|
|||||||
*/
|
*/
|
||||||
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
|
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||||
|
|
||||||
/** A taint tracking configuration for Zip Slip */
|
/**
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
* DEPRECATED: Use `ZipSlip` instead.
|
||||||
|
*
|
||||||
|
* A taint tracking configuration for Zip Slip.
|
||||||
|
*/
|
||||||
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "ZipSlipTaintTracking" }
|
TaintTrackingConfiguration() { this = "ZipSlipTaintTracking" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -42,6 +46,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking configuration for Zip Slip.
|
||||||
|
*/
|
||||||
|
private module ZipSlipConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking module for Zip Slip.
|
||||||
|
*/
|
||||||
|
module ZipSlip = TaintTracking::Global<ZipSlipConfig>;
|
||||||
|
|
||||||
/** An access to the `FullName` property of a `ZipArchiveEntry`. */
|
/** An access to the `FullName` property of a `ZipArchiveEntry`. */
|
||||||
class ArchiveFullNameSource extends Source {
|
class ArchiveFullNameSource extends Source {
|
||||||
ArchiveFullNameSource() {
|
ArchiveFullNameSource() {
|
||||||
|
|||||||
@@ -172,26 +172,24 @@ module XmlReader {
|
|||||||
isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
|
isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
|
||||||
or
|
or
|
||||||
// bad settings flow here
|
// bad settings flow here
|
||||||
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
|
exists(ObjectCreation settings |
|
||||||
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
|
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
|
||||||
XmlSettings::dtdEnabledSettings(settings, evidence, reason)
|
XmlSettings::dtdEnabledSettings(settings, evidence, reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate insecureResolver(string reason, Expr evidence) {
|
private predicate insecureResolver(string reason, Expr evidence) {
|
||||||
// bad settings flow here
|
// bad settings flow here
|
||||||
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
|
exists(ObjectCreation settings |
|
||||||
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
|
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
|
||||||
XmlSettings::insecureResolverSettings(settings, evidence, reason)
|
XmlSettings::insecureResolverSettings(settings, evidence, reason)
|
||||||
)
|
)
|
||||||
// default is secure
|
// default is secure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SettingsDataFlowConfig extends DataFlow2::Configuration {
|
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
|
||||||
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
// flow from places where we construct an XmlReaderSettings
|
// flow from places where we construct an XmlReaderSettings
|
||||||
source
|
source
|
||||||
.asExpr()
|
.asExpr()
|
||||||
@@ -202,10 +200,12 @@ module XmlReader {
|
|||||||
.hasQualifiedName("System.Xml", "XmlReaderSettings")
|
.hasQualifiedName("System.Xml", "XmlReaderSettings")
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
|
sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides predicates related to `System.Xml.XmlTextReader`. */
|
/** Provides predicates related to `System.Xml.XmlTextReader`. */
|
||||||
|
|||||||
@@ -12,38 +12,36 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.frameworks.Format
|
import semmle.code.csharp.frameworks.Format
|
||||||
import DataFlow::PathGraph
|
import FormatInvalid::PathGraph
|
||||||
|
|
||||||
private class FormatConfiguration extends DataFlow::Configuration {
|
module FormatInvalidConfig implements DataFlow::ConfigSig {
|
||||||
FormatConfiguration() { this = "format" }
|
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
|
predicate isSink(DataFlow::Node n) { exists(FormatCall c | n.asExpr() = c.getFormatExpr()) }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node n) {
|
|
||||||
exists(FormatCall c | n.asExpr() = c.getFormatExpr())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module FormatInvalid = DataFlow::Global<FormatInvalidConfig>;
|
||||||
|
|
||||||
private predicate invalidFormatString(
|
private predicate invalidFormatString(
|
||||||
InvalidFormatString src, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
|
InvalidFormatString src, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
|
||||||
FormatCall call, string callString
|
FormatCall call, string callString
|
||||||
) {
|
) {
|
||||||
source.getNode().asExpr() = src and
|
source.getNode().asExpr() = src and
|
||||||
sink.getNode().asExpr() = call.getFormatExpr() and
|
sink.getNode().asExpr() = call.getFormatExpr() and
|
||||||
any(FormatConfiguration conf).hasFlowPath(source, sink) and
|
FormatInvalid::flowPath(source, sink) and
|
||||||
call.hasInsertions() and
|
call.hasInsertions() and
|
||||||
msg = "Invalid format string used in $@ formatting call." and
|
msg = "Invalid format string used in $@ formatting call." and
|
||||||
callString = "this"
|
callString = "this"
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate unusedArgument(
|
private predicate unusedArgument(
|
||||||
FormatCall call, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
|
FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
|
||||||
ValidFormatString src, string srcString, Expr unusedExpr, string unusedString
|
ValidFormatString src, string srcString, Expr unusedExpr, string unusedString
|
||||||
) {
|
) {
|
||||||
exists(int unused |
|
exists(int unused |
|
||||||
source.getNode().asExpr() = src and
|
source.getNode().asExpr() = src and
|
||||||
sink.getNode().asExpr() = call.getFormatExpr() and
|
sink.getNode().asExpr() = call.getFormatExpr() and
|
||||||
any(FormatConfiguration conf).hasFlowPath(source, sink) and
|
FormatInvalid::flowPath(source, sink) and
|
||||||
unused = call.getASuppliedArgument() and
|
unused = call.getASuppliedArgument() and
|
||||||
not unused = src.getAnInsert() and
|
not unused = src.getAnInsert() and
|
||||||
not src.getValue() = "" and
|
not src.getValue() = "" and
|
||||||
@@ -55,13 +53,13 @@ private predicate unusedArgument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate missingArgument(
|
private predicate missingArgument(
|
||||||
FormatCall call, DataFlow::PathNode source, DataFlow::PathNode sink, string msg,
|
FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
|
||||||
ValidFormatString src, string srcString
|
ValidFormatString src, string srcString
|
||||||
) {
|
) {
|
||||||
exists(int used, int supplied |
|
exists(int used, int supplied |
|
||||||
source.getNode().asExpr() = src and
|
source.getNode().asExpr() = src and
|
||||||
sink.getNode().asExpr() = call.getFormatExpr() and
|
sink.getNode().asExpr() = call.getFormatExpr() and
|
||||||
any(FormatConfiguration conf).hasFlowPath(source, sink) and
|
FormatInvalid::flowPath(source, sink) and
|
||||||
used = src.getAnInsert() and
|
used = src.getAnInsert() and
|
||||||
supplied = call.getSuppliedArguments() and
|
supplied = call.getSuppliedArguments() and
|
||||||
used >= supplied and
|
used >= supplied and
|
||||||
@@ -71,8 +69,8 @@ private predicate missingArgument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
Element alert, DataFlow::PathNode source, DataFlow::PathNode sink, string msg, Element extra1,
|
Element alert, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
|
||||||
string extra1String, Element extra2, string extra2String
|
Element extra1, string extra1String, Element extra2, string extra2String
|
||||||
where
|
where
|
||||||
invalidFormatString(alert, source, sink, msg, extra1, extra1String) and
|
invalidFormatString(alert, source, sink, msg, extra1, extra1String) and
|
||||||
extra2 = extra1 and
|
extra2 = extra1 and
|
||||||
|
|||||||
@@ -24,10 +24,8 @@ private class ReturnNode extends DataFlow::ExprNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Conf extends DataFlow::Configuration {
|
module DisposeCallOnLocalIDisposableConfig implements DataFlow::ConfigSig {
|
||||||
Conf() { this = "NoDisposeCallOnLocalIDisposable" }
|
predicate isSource(DataFlow::Node node) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) {
|
|
||||||
node.asExpr() =
|
node.asExpr() =
|
||||||
any(LocalScopeDisposableCreation disposable |
|
any(LocalScopeDisposableCreation disposable |
|
||||||
// Only care about library types - user types often have spurious IDisposable declarations
|
// Only care about library types - user types often have spurious IDisposable declarations
|
||||||
@@ -37,7 +35,7 @@ private class Conf extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) {
|
predicate isSink(DataFlow::Node node) {
|
||||||
// Things that return may be disposed elsewhere
|
// Things that return may be disposed elsewhere
|
||||||
node instanceof ReturnNode
|
node instanceof ReturnNode
|
||||||
or
|
or
|
||||||
@@ -80,23 +78,27 @@ private class Conf extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
node2.asExpr() =
|
node2.asExpr() =
|
||||||
any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr())
|
any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isBarrierOut(DataFlow::Node node) {
|
predicate isBarrierOut(DataFlow::Node node) {
|
||||||
this.isSink(node) and
|
isSink(node) and
|
||||||
not node instanceof ReturnNode
|
not node instanceof ReturnNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module DisposeCallOnLocalIDisposable = DataFlow::Global<DisposeCallOnLocalIDisposableConfig>;
|
||||||
|
|
||||||
/** Holds if `disposable` may not be disposed. */
|
/** Holds if `disposable` may not be disposed. */
|
||||||
predicate mayNotBeDisposed(LocalScopeDisposableCreation disposable) {
|
predicate mayNotBeDisposed(LocalScopeDisposableCreation disposable) {
|
||||||
exists(Conf conf, DataFlow::ExprNode e |
|
exists(DataFlow::ExprNode e |
|
||||||
e.getExpr() = disposable and
|
e.getExpr() = disposable and
|
||||||
conf.isSource(e) and
|
DisposeCallOnLocalIDisposableConfig::isSource(e) and
|
||||||
not exists(DataFlow::Node sink | conf.hasFlow(DataFlow::exprNode(disposable), sink) |
|
not exists(DataFlow::Node sink |
|
||||||
|
DisposeCallOnLocalIDisposable::flow(DataFlow::exprNode(disposable), sink)
|
||||||
|
|
|
||||||
sink instanceof ReturnNode
|
sink instanceof ReturnNode
|
||||||
implies
|
implies
|
||||||
sink.getEnclosingCallable() = disposable.getEnclosingCallable()
|
sink.getEnclosingCallable() = disposable.getEnclosingCallable()
|
||||||
|
|||||||
@@ -37,19 +37,19 @@ predicate inForeachStmtBody(ForeachStmt loop, Element e) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class LambdaDataFlowConfiguration extends DataFlow::Configuration {
|
module LambdaDataFlowConfig implements DataFlow::ConfigSig {
|
||||||
LambdaDataFlowConfiguration() { this = "LambdaDataFlowConfiguration" }
|
predicate isSource(DataFlow::Node source) { lambdaCapturesLoopVariable(source.asExpr(), _, _) }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
|
||||||
lambdaCapturesLoopVariable(source.asExpr(), _, _)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
|
module LambdaDataFlow {
|
||||||
|
private import DataFlow::Global<LambdaDataFlowConfig>
|
||||||
|
|
||||||
predicate capturesLoopVarAndIsStoredIn(
|
predicate capturesLoopVarAndIsStoredIn(
|
||||||
AnonymousFunctionExpr lambda, Variable loopVar, Element storage
|
AnonymousFunctionExpr lambda, Variable loopVar, Element storage
|
||||||
) {
|
) {
|
||||||
exists(DataFlow::Node sink | this.hasFlow(DataFlow::exprNode(lambda), sink) |
|
exists(DataFlow::Node sink | flow(DataFlow::exprNode(lambda), sink) |
|
||||||
storage = getAssignmentTarget(sink.asExpr())
|
storage = getAssignmentTarget(sink.asExpr())
|
||||||
) and
|
) and
|
||||||
exists(ForeachStmt loop | lambdaCapturesLoopVariable(lambda, loop, loopVar) |
|
exists(ForeachStmt loop | lambdaCapturesLoopVariable(lambda, loop, loopVar) |
|
||||||
@@ -109,7 +109,7 @@ predicate declaredInsideLoop(ForeachStmt loop, LocalVariable v) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
from LambdaDataFlowConfiguration c, AnonymousFunctionExpr lambda, Variable loopVar, Element storage
|
from AnonymousFunctionExpr lambda, Variable loopVar, Element storage
|
||||||
where c.capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
|
where LambdaDataFlow::capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
|
||||||
select lambda, "Function which may be stored in $@ captures variable $@.", storage,
|
select lambda, "Function which may be stored in $@ captures variable $@.", storage,
|
||||||
storage.toString(), loopVar, loopVar.getName()
|
storage.toString(), loopVar, loopVar.getName()
|
||||||
|
|||||||
@@ -10,21 +10,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import DataFlow::PathGraph
|
import UnsafeYearCreationFromArithmetic::PathGraph
|
||||||
|
|
||||||
class UnsafeYearCreationFromArithmeticConfiguration extends TaintTracking::Configuration {
|
module UnsafeYearCreationFromArithmeticConfig implements DataFlow::ConfigSig {
|
||||||
UnsafeYearCreationFromArithmeticConfiguration() {
|
predicate isSource(DataFlow::Node source) {
|
||||||
this = "UnsafeYearCreationFromArithmeticConfiguration"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
exists(ArithmeticOperation ao, PropertyAccess pa | ao = source.asExpr() |
|
exists(ArithmeticOperation ao, PropertyAccess pa | ao = source.asExpr() |
|
||||||
pa = ao.getAChild*() and
|
pa = ao.getAChild*() and
|
||||||
pa.getProperty().hasQualifiedName("System.DateTime", "Year")
|
pa.getProperty().hasQualifiedName("System.DateTime", "Year")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(ObjectCreation oc |
|
exists(ObjectCreation oc |
|
||||||
sink.asExpr() = oc.getArgumentForName("year") and
|
sink.asExpr() = oc.getArgumentForName("year") and
|
||||||
oc.getObjectType().getABaseType*().hasQualifiedName("System", "DateTime")
|
oc.getObjectType().getABaseType*().hasQualifiedName("System", "DateTime")
|
||||||
@@ -32,10 +28,12 @@ class UnsafeYearCreationFromArithmeticConfiguration extends TaintTracking::Confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module UnsafeYearCreationFromArithmetic =
|
||||||
|
TaintTracking::Global<UnsafeYearCreationFromArithmeticConfig>;
|
||||||
|
|
||||||
from
|
from
|
||||||
UnsafeYearCreationFromArithmeticConfiguration config, DataFlow::PathNode source,
|
UnsafeYearCreationFromArithmetic::PathNode source, UnsafeYearCreationFromArithmetic::PathNode sink
|
||||||
DataFlow::PathNode sink
|
where UnsafeYearCreationFromArithmetic::flowPath(source, sink)
|
||||||
where config.hasFlowPath(source, sink)
|
|
||||||
select sink, source, sink,
|
select sink, source, sink,
|
||||||
"This $@ based on a 'System.DateTime.Year' property is used in a construction of a new 'System.DateTime' object, flowing to the 'year' argument.",
|
"This $@ based on a 'System.DateTime.Year' property is used in a construction of a new 'System.DateTime' object, flowing to the 'year' argument.",
|
||||||
source, "arithmetic operation"
|
source, "arithmetic operation"
|
||||||
|
|||||||
@@ -18,21 +18,20 @@ import csharp
|
|||||||
import ParallelSink
|
import ParallelSink
|
||||||
import ICryptoTransform
|
import ICryptoTransform
|
||||||
|
|
||||||
class NotThreadSafeCryptoUsageIntoParallelInvokeConfig extends TaintTracking::Configuration {
|
module NotThreadSafeCryptoUsageIntoParallelInvokeConfig implements DataFlow::ConfigSig {
|
||||||
NotThreadSafeCryptoUsageIntoParallelInvokeConfig() {
|
predicate isSource(DataFlow::Node source) {
|
||||||
this = "NotThreadSafeCryptoUsageIntoParallelInvokeConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source instanceof LambdaCapturingICryptoTransformSource
|
source instanceof LambdaCapturingICryptoTransformSource
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ParallelSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof ParallelSink }
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr e, string m, LambdaExpr l, NotThreadSafeCryptoUsageIntoParallelInvokeConfig config
|
module NotThreadSafeCryptoUsageIntoParallelInvoke =
|
||||||
|
TaintTracking::Global<NotThreadSafeCryptoUsageIntoParallelInvokeConfig>;
|
||||||
|
|
||||||
|
from Expr e, string m, LambdaExpr l
|
||||||
where
|
where
|
||||||
config.hasFlow(DataFlow::exprNode(l), DataFlow::exprNode(e)) and
|
NotThreadSafeCryptoUsageIntoParallelInvoke::flow(DataFlow::exprNode(l), DataFlow::exprNode(e)) and
|
||||||
m =
|
m =
|
||||||
"A $@ seems to be used to start a new thread is capturing a local variable that either implements 'System.Security.Cryptography.ICryptoTransform' or has a field of this type."
|
"A $@ seems to be used to start a new thread is capturing a local variable that either implements 'System.Security.Cryptography.ICryptoTransform' or has a field of this type."
|
||||||
select e, m, l, "lambda expression"
|
select e, m, l, "lambda expression"
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.TaintedPathQuery
|
import semmle.code.csharp.security.dataflow.TaintedPathQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import TaintedPath::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from TaintedPath::PathNode source, TaintedPath::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where TaintedPath::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.ZipSlipQuery
|
import semmle.code.csharp.security.dataflow.ZipSlipQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import ZipSlip::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration zipTaintTracking, DataFlow::PathNode source, DataFlow::PathNode sink
|
from ZipSlip::PathNode source, ZipSlip::PathNode sink
|
||||||
where zipTaintTracking.hasFlowPath(source, sink)
|
where ZipSlip::flowPath(source, sink)
|
||||||
select source.getNode(), source, sink,
|
select source.getNode(), source, sink,
|
||||||
"Unsanitized archive entry, which may contain '..', is used in a $@.", sink.getNode(),
|
"Unsanitized archive entry, which may contain '..', is used in a $@.", sink.getNode(),
|
||||||
"file system operation"
|
"file system operation"
|
||||||
|
|||||||
@@ -12,19 +12,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import DataFlow::PathGraph
|
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
import semmle.code.csharp.frameworks.system.Xml
|
import semmle.code.csharp.frameworks.system.Xml
|
||||||
|
import XmlInjection::PathGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taint-tracking configuration for untrusted user input used in XML.
|
* A taint-tracking configuration for untrusted user input used in XML.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
module XmlInjectionConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "XMLInjection" }
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
mc.getTarget().hasName("WriteRaw") and
|
mc.getTarget().hasName("WriteRaw") and
|
||||||
mc.getTarget().getDeclaringType().getABaseType*().hasQualifiedName("System.Xml", "XmlWriter")
|
mc.getTarget().getDeclaringType().getABaseType*().hasQualifiedName("System.Xml", "XmlWriter")
|
||||||
@@ -33,7 +31,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) {
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
mc.getTarget().hasName("Escape") and
|
mc.getTarget().hasName("Escape") and
|
||||||
mc.getTarget()
|
mc.getTarget()
|
||||||
@@ -46,7 +44,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
/**
|
||||||
where c.hasFlowPath(source, sink)
|
* A taint-tracking module for untrusted user input used in XML.
|
||||||
|
*/
|
||||||
|
module XmlInjection = TaintTracking::Global<XmlInjectionConfig>;
|
||||||
|
|
||||||
|
from XmlInjection::PathNode source, XmlInjection::PathNode sink
|
||||||
|
where XmlInjection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This XML element depends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "This XML element depends on a $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -15,20 +15,18 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
import semmle.code.csharp.commons.Util
|
import semmle.code.csharp.commons.Util
|
||||||
import DataFlow::PathGraph
|
import AssemblyPathInjection::PathGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taint-tracking configuration for untrusted user input used to load a DLL.
|
* A taint-tracking configuration for untrusted user input used to load a DLL.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
module AssemblyPathInjectionConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "DLLInjection" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source instanceof RemoteFlowSource or
|
source instanceof RemoteFlowSource or
|
||||||
source.asExpr() = any(MainMethod main).getParameter(0).getAnAccess()
|
source.asExpr() = any(MainMethod main).getParameter(0).getAnAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodCall mc, string name, int arg |
|
exists(MethodCall mc, string name, int arg |
|
||||||
mc.getTarget().getName().matches(name) and
|
mc.getTarget().getName().matches(name) and
|
||||||
mc.getTarget()
|
mc.getTarget()
|
||||||
@@ -48,7 +46,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
/**
|
||||||
where c.hasFlowPath(source, sink)
|
* A taint-tracking module for untrusted user input used to load a DLL.
|
||||||
|
*/
|
||||||
|
module AssemblyPathInjection = TaintTracking::Global<AssemblyPathInjectionConfig>;
|
||||||
|
|
||||||
|
from AssemblyPathInjection::PathNode source, AssemblyPathInjection::PathNode sink
|
||||||
|
where AssemblyPathInjection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This assembly path depends on a $@.", source,
|
select sink.getNode(), source, sink, "This assembly path depends on a $@.", source,
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -15,29 +15,29 @@ import csharp
|
|||||||
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Local
|
import semmle.code.csharp.security.dataflow.flowsources.Local
|
||||||
import semmle.code.csharp.frameworks.Format
|
import semmle.code.csharp.frameworks.Format
|
||||||
import DataFlow::PathGraph
|
import FormatString::PathGraph
|
||||||
|
|
||||||
class FormatStringConfiguration extends TaintTracking::Configuration {
|
module FormatStringConfig implements DataFlow::ConfigSig {
|
||||||
FormatStringConfiguration() { this = "FormatStringConfiguration" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source instanceof RemoteFlowSource
|
source instanceof RemoteFlowSource
|
||||||
or
|
or
|
||||||
source instanceof LocalFlowSource
|
source instanceof LocalFlowSource
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
sink.asExpr() = any(FormatCall call | call.hasInsertions()).getFormatExpr()
|
sink.asExpr() = any(FormatCall call | call.hasInsertions()).getFormatExpr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module FormatString = TaintTracking::Global<FormatStringConfig>;
|
||||||
|
|
||||||
string getSourceType(DataFlow::Node node) {
|
string getSourceType(DataFlow::Node node) {
|
||||||
result = node.(RemoteFlowSource).getSourceType()
|
result = node.(RemoteFlowSource).getSourceType()
|
||||||
or
|
or
|
||||||
result = node.(LocalFlowSource).getSourceType()
|
result = node.(LocalFlowSource).getSourceType()
|
||||||
}
|
}
|
||||||
|
|
||||||
from FormatStringConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
from FormatString::PathNode source, FormatString::PathNode sink
|
||||||
where config.hasFlowPath(source, sink)
|
where FormatString::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This format string depends on $@.", source.getNode(),
|
select sink.getNode(), source, sink, "This format string depends on $@.", source.getNode(),
|
||||||
("this" + getSourceType(source.getNode()))
|
("this" + getSourceType(source.getNode()))
|
||||||
|
|||||||
@@ -15,12 +15,10 @@ import semmle.code.csharp.security.SensitiveActions
|
|||||||
import semmle.code.csharp.security.dataflow.flowsinks.Remote
|
import semmle.code.csharp.security.dataflow.flowsinks.Remote
|
||||||
import semmle.code.csharp.frameworks.system.data.Common
|
import semmle.code.csharp.frameworks.system.data.Common
|
||||||
import semmle.code.csharp.frameworks.System
|
import semmle.code.csharp.frameworks.System
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import ExposureInTransmittedData::PathGraph
|
||||||
|
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
module ExposureInTransmittedDataConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "Exposure through transmitted data" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
// `source` may contain a password
|
// `source` may contain a password
|
||||||
source.asExpr() instanceof PasswordExpr
|
source.asExpr() instanceof PasswordExpr
|
||||||
or
|
or
|
||||||
@@ -42,10 +40,12 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration configuration, DataFlow::PathNode source, DataFlow::PathNode sink
|
module ExposureInTransmittedData = TaintTracking::Global<ExposureInTransmittedDataConfig>;
|
||||||
where configuration.hasFlowPath(source, sink)
|
|
||||||
|
from ExposureInTransmittedData::PathNode source, ExposureInTransmittedData::PathNode sink
|
||||||
|
where ExposureInTransmittedData::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This data transmitted to the user depends on $@.",
|
select sink.getNode(), source, sink, "This data transmitted to the user depends on $@.",
|
||||||
source.getNode(), "sensitive information"
|
source.getNode(), "sensitive information"
|
||||||
|
|||||||
@@ -16,15 +16,13 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.frameworks.System
|
import semmle.code.csharp.frameworks.System
|
||||||
import semmle.code.csharp.security.dataflow.flowsinks.Remote
|
import semmle.code.csharp.security.dataflow.flowsinks.Remote
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import ExceptionInformationExposure::PathGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taint-tracking configuration for reasoning about stack traces that flow to web page outputs.
|
* A taint-tracking configuration for reasoning about stack traces that flow to web page outputs.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
module ExceptionInformationExposureConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "StackTrace" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
exists(Expr exceptionExpr |
|
exists(Expr exceptionExpr |
|
||||||
// Writing an exception directly is bad
|
// Writing an exception directly is bad
|
||||||
source.asExpr() = exceptionExpr
|
source.asExpr() = exceptionExpr
|
||||||
@@ -40,7 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node sink) {
|
predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) {
|
||||||
sink.asExpr() =
|
sink.asExpr() =
|
||||||
any(MethodCall mc |
|
any(MethodCall mc |
|
||||||
source.asExpr() = mc.getQualifier() and
|
source.asExpr() = mc.getQualifier() and
|
||||||
@@ -49,20 +47,25 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof RemoteFlowSink }
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||||
// Do not flow through Message
|
// Do not flow through Message
|
||||||
sanitizer.asExpr() = any(SystemExceptionClass se).getProperty("Message").getAnAccess()
|
sanitizer.asExpr() = any(SystemExceptionClass se).getProperty("Message").getAnAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerIn(DataFlow::Node sanitizer) {
|
predicate isBarrierIn(DataFlow::Node sanitizer) {
|
||||||
// Do not flow through Message
|
// Do not flow through Message
|
||||||
sanitizer.asExpr().getType().(RefType).getABaseType*() instanceof SystemExceptionClass
|
sanitizer.asExpr().getType().(RefType).getABaseType*() instanceof SystemExceptionClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
/**
|
||||||
where c.hasFlowPath(source, sink)
|
* A taint-tracking module for reasoning about stack traces that flow to web page outputs.
|
||||||
|
*/
|
||||||
|
module ExceptionInformationExposure = TaintTracking::Global<ExceptionInformationExposureConfig>;
|
||||||
|
|
||||||
|
from ExceptionInformationExposure::PathNode source, ExceptionInformationExposure::PathNode sink
|
||||||
|
where ExceptionInformationExposure::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This information exposed to the user depends on $@.",
|
select sink.getNode(), source, sink, "This information exposed to the user depends on $@.",
|
||||||
source.getNode(), "exception information"
|
source.getNode(), "exception information"
|
||||||
|
|||||||
@@ -12,12 +12,10 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow
|
import semmle.code.csharp.dataflow.DataFlow::DataFlow
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import AddCertToRootStore::PathGraph
|
||||||
|
|
||||||
class AddCertToRootStoreConfig extends DataFlow::Configuration {
|
module AddCertToRootStoreConfig implements DataFlow::ConfigSig {
|
||||||
AddCertToRootStoreConfig() { this = "Adding Certificate To Root Store" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
exists(ObjectCreation oc | oc = source.asExpr() |
|
exists(ObjectCreation oc | oc = source.asExpr() |
|
||||||
oc.getType()
|
oc.getType()
|
||||||
.(RefType)
|
.(RefType)
|
||||||
@@ -26,7 +24,7 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
(
|
(
|
||||||
mc.getTarget()
|
mc.getTarget()
|
||||||
@@ -40,6 +38,8 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from DataFlow::PathNode oc, DataFlow::PathNode mc, AddCertToRootStoreConfig config
|
module AddCertToRootStore = DataFlow::Global<AddCertToRootStoreConfig>;
|
||||||
where config.hasFlowPath(oc, mc)
|
|
||||||
|
from AddCertToRootStore::PathNode oc, AddCertToRootStore::PathNode mc
|
||||||
|
where AddCertToRootStore::flowPath(oc, mc)
|
||||||
select mc.getNode(), oc, mc, "This certificate is added to the root certificate store."
|
select mc.getNode(), oc, mc, "This certificate is added to the root certificate store."
|
||||||
|
|||||||
@@ -11,15 +11,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import DataFlow::PathGraph
|
import InsecureSqlConnection::PathGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
|
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends DataFlow::Configuration {
|
module InsecureSqlConnectionConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "TaintTrackingConfiguration" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
exists(string s | s = source.asExpr().(StringLiteral).getValue().toLowerCase() |
|
exists(string s | s = source.asExpr().(StringLiteral).getValue().toLowerCase() |
|
||||||
s.matches("%encrypt=false%")
|
s.matches("%encrypt=false%")
|
||||||
or
|
or
|
||||||
@@ -27,7 +25,7 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(ObjectCreation oc |
|
exists(ObjectCreation oc |
|
||||||
oc.getRuntimeArgument(0) = sink.asExpr() and
|
oc.getRuntimeArgument(0) = sink.asExpr() and
|
||||||
(
|
(
|
||||||
@@ -39,8 +37,13 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
/**
|
||||||
where c.hasFlowPath(source, sink)
|
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
|
||||||
|
*/
|
||||||
|
module InsecureSqlConnection = DataFlow::Global<InsecureSqlConnectionConfig>;
|
||||||
|
|
||||||
|
from InsecureSqlConnection::PathNode source, InsecureSqlConnection::PathNode sink
|
||||||
|
where InsecureSqlConnection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"$@ flows to this SQL connection and does not specify `Encrypt=True`.", source.getNode(),
|
"$@ flows to this SQL connection and does not specify `Encrypt=True`.", source.getNode(),
|
||||||
"Connection string"
|
"Connection string"
|
||||||
|
|||||||
@@ -48,12 +48,9 @@ where
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// JsonConvert static method call, but with additional unsafe typename tracking
|
// JsonConvert static method call, but with additional unsafe typename tracking
|
||||||
exists(
|
exists(JsonConvertTrackingConfig taintTrackingJsonConvert, DataFlow::Node settingsCallArg |
|
||||||
JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
|
|
||||||
DataFlow::Node settingsCallArg
|
|
||||||
|
|
|
||||||
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
|
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
|
||||||
typenameTracking.hasFlow(_, settingsCallArg) and
|
TypeNameTracking::flow(_, settingsCallArg) and
|
||||||
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
|
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
|
||||||
)
|
)
|
||||||
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",
|
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.UrlRedirectQuery
|
import semmle.code.csharp.security.dataflow.UrlRedirectQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import UrlRedirect::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from UrlRedirect::PathNode source, UrlRedirect::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where UrlRedirect::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(),
|
select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.XMLEntityInjectionQuery
|
import semmle.code.csharp.security.dataflow.XMLEntityInjectionQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import XmlEntityInjection::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from XmlEntityInjection::PathNode source, XmlEntityInjection::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where XmlEntityInjection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"This insecure XML processing depends on a $@ (" + sink.getNode().(Sink).getReason() + ").",
|
"This insecure XML processing depends on a $@ (" + sink.getNode().(Sink).getReason() + ").",
|
||||||
source.getNode(), "user-provided value"
|
source.getNode(), "user-provided value"
|
||||||
|
|||||||
@@ -13,14 +13,20 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Stored
|
import semmle.code.csharp.security.dataflow.flowsources.Stored
|
||||||
import semmle.code.csharp.security.dataflow.XPathInjectionQuery as XPathInjection
|
import semmle.code.csharp.security.dataflow.XPathInjectionQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import StoredXpathInjection::PathGraph
|
||||||
|
|
||||||
class StoredTaintTrackingConfiguration extends XPathInjection::TaintTrackingConfiguration {
|
module StoredXpathInjectionConfig implements DataFlow::ConfigSig {
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
|
predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
|
||||||
|
|
||||||
|
predicate isSink = XpathInjectionConfig::isSink/1;
|
||||||
|
|
||||||
|
predicate isBarrier = XpathInjectionConfig::isBarrier/1;
|
||||||
}
|
}
|
||||||
|
|
||||||
from StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
module StoredXpathInjection = TaintTracking::Global<StoredXpathInjectionConfig>;
|
||||||
where c.hasFlowPath(source, sink)
|
|
||||||
|
from StoredXpathInjection::PathNode source, StoredXpathInjection::PathNode sink
|
||||||
|
where StoredXpathInjection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
|
||||||
"stored (potentially user-provided) value"
|
"stored (potentially user-provided) value"
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.security.dataflow.XPathInjectionQuery
|
import semmle.code.csharp.security.dataflow.XPathInjectionQuery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import XpathInjection::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from XpathInjection::PathNode source, XpathInjection::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where XpathInjection::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "This XPath expression depends on a $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.frameworks.Test
|
import semmle.code.csharp.frameworks.Test
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import Random::InsecureRandomness::PathGraph
|
||||||
|
|
||||||
module Random {
|
module Random {
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
@@ -38,21 +38,24 @@ module Random {
|
|||||||
/**
|
/**
|
||||||
* A taint-tracking configuration for insecure randomness in security sensitive context.
|
* A taint-tracking configuration for insecure randomness in security sensitive context.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
module InsecureRandomnessConfig implements DataFlow::ConfigSig {
|
||||||
TaintTrackingConfiguration() { this = "RandomDataFlowConfiguration" }
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
|
||||||
// succ = array_or_indexer[pred] - use of random numbers in an index
|
// succ = array_or_indexer[pred] - use of random numbers in an index
|
||||||
succ.asExpr().(ElementAccess).getAnIndex() = pred.asExpr()
|
succ.asExpr().(ElementAccess).getAnIndex() = pred.asExpr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for insecure randomness in security sensitive context.
|
||||||
|
*/
|
||||||
|
module InsecureRandomness = TaintTracking::Global<InsecureRandomnessConfig>;
|
||||||
|
|
||||||
/** A source of cryptographically insecure random numbers. */
|
/** A source of cryptographically insecure random numbers. */
|
||||||
class RandomSource extends Source {
|
class RandomSource extends Source {
|
||||||
RandomSource() {
|
RandomSource() {
|
||||||
@@ -112,10 +115,8 @@ module Random {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from
|
from Random::InsecureRandomness::PathNode source, Random::InsecureRandomness::PathNode sink
|
||||||
Random::TaintTrackingConfiguration randomTracking, DataFlow::PathNode source,
|
where Random::InsecureRandomness::flowPath(source, sink)
|
||||||
DataFlow::PathNode sink
|
|
||||||
where randomTracking.hasFlowPath(source, sink)
|
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"This uses a cryptographically insecure random number generated at $@ in a security context.",
|
"This uses a cryptographically insecure random number generated at $@ in a security context.",
|
||||||
source.getNode(), source.getNode().toString()
|
source.getNode(), source.getNode().toString()
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import TaintedWebClientLib
|
import TaintedWebClientLib
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import TaintedWebClient::PathGraph
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from TaintedWebClient::PathNode source, TaintedWebClient::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where TaintedWebClient::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "A method of WebClient depepends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "A method of WebClient depepends on a $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
|||||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `TaintedWebClient` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||||
*/
|
*/
|
||||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
TaintTrackingConfiguration() { this = "TaintedWebClientLib" }
|
TaintTrackingConfiguration() { this = "TaintedWebClientLib" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -50,6 +52,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||||
|
*/
|
||||||
|
private module TaintedWebClientConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking module for uncontrolled data in path expression vulnerabilities.
|
||||||
|
*/
|
||||||
|
module TaintedWebClient = TaintTracking::Global<TaintedWebClientConfig>;
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import RequestForgery::RequestForgery
|
import RequestForgery::RequestForgery
|
||||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
import RequestForgeryFlow::PathGraph
|
||||||
|
|
||||||
from RequestForgeryConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
|
||||||
where c.hasFlowPath(source, sink)
|
where RequestForgeryFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
|
||||||
"user-provided value"
|
"user-provided value"
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ module RequestForgery {
|
|||||||
abstract private class Barrier extends DataFlow::Node { }
|
abstract private class Barrier extends DataFlow::Node { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `RequestForgeryFlow` instead.
|
||||||
|
*
|
||||||
* A data flow configuration for detecting server side request forgery vulnerabilities.
|
* A data flow configuration for detecting server side request forgery vulnerabilities.
|
||||||
*/
|
*/
|
||||||
class RequestForgeryConfiguration extends DataFlow::Configuration {
|
deprecated class RequestForgeryConfiguration extends DataFlow::Configuration {
|
||||||
RequestForgeryConfiguration() { this = "Server Side Request forgery" }
|
RequestForgeryConfiguration() { this = "Server Side Request forgery" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
@@ -54,6 +56,40 @@ module RequestForgery {
|
|||||||
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
|
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data flow configuration for detecting server side request forgery vulnerabilities.
|
||||||
|
*/
|
||||||
|
private module RequestForgeryFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||||
|
interpolatedStringFlowStep(prev, succ)
|
||||||
|
or
|
||||||
|
stringReplaceStep(prev, succ)
|
||||||
|
or
|
||||||
|
uriCreationStep(prev, succ)
|
||||||
|
or
|
||||||
|
formatConvertStep(prev, succ)
|
||||||
|
or
|
||||||
|
toStringStep(prev, succ)
|
||||||
|
or
|
||||||
|
stringConcatStep(prev, succ)
|
||||||
|
or
|
||||||
|
stringFormatStep(prev, succ)
|
||||||
|
or
|
||||||
|
pathCombineStep(prev, succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data flow module for detecting server side request forgery vulnerabilities.
|
||||||
|
*/
|
||||||
|
module RequestForgeryFlow = DataFlow::Global<RequestForgeryFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A remote data flow source taken as a source
|
* A remote data flow source taken as a source
|
||||||
* for Server Side Request Forgery(SSRF) Vulnerabilities.
|
* for Server Side Request Forgery(SSRF) Vulnerabilities.
|
||||||
|
|||||||
@@ -36,13 +36,10 @@ where
|
|||||||
iResponse.getAppendMethod() = mc.getTarget() and
|
iResponse.getAppendMethod() = mc.getTarget() and
|
||||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||||
not exists(OnAppendCookieHttpOnlyTrackingConfig config | config.hasFlowTo(_)) and
|
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||||
// Passed as third argument to `IResponseCookies.Append`
|
// Passed as third argument to `IResponseCookies.Append`
|
||||||
exists(
|
exists(DataFlow::Node creation, DataFlow::Node append |
|
||||||
CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation,
|
CookieOptionsTracking::flow(creation, append) and
|
||||||
DataFlow::Node append
|
|
||||||
|
|
|
||||||
cookieTracking.hasFlow(creation, append) and
|
|
||||||
creation.asExpr() = oc and
|
creation.asExpr() = oc and
|
||||||
append.asExpr() = mc.getArgument(2)
|
append.asExpr() = mc.getArgument(2)
|
||||||
)
|
)
|
||||||
@@ -70,7 +67,7 @@ where
|
|||||||
// default is not configured or is not set to `Always`
|
// default is not configured or is not set to `Always`
|
||||||
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
|
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
|
||||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||||
not exists(OnAppendCookieHttpOnlyTrackingConfig config | config.hasFlowTo(_)) and
|
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||||
iResponse.getAppendMethod() = mc.getTarget() and
|
iResponse.getAppendMethod() = mc.getTarget() and
|
||||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||||
(
|
(
|
||||||
@@ -79,8 +76,8 @@ where
|
|||||||
oc = c and
|
oc = c and
|
||||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||||
not isPropertySet(oc, "HttpOnly") and
|
not isPropertySet(oc, "HttpOnly") and
|
||||||
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
|
exists(DataFlow::Node creation |
|
||||||
cookieTracking.hasFlow(creation, _) and
|
CookieOptionsTracking::flow(creation, _) and
|
||||||
creation.asExpr() = oc
|
creation.asExpr() = oc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,15 +30,15 @@ where
|
|||||||
getAValueForCookiePolicyProp("Secure").getValue() = "1"
|
getAValueForCookiePolicyProp("Secure").getValue() = "1"
|
||||||
) and
|
) and
|
||||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||||
not exists(OnAppendCookieSecureTrackingConfig config | config.hasFlowTo(_)) and
|
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||||
(
|
(
|
||||||
// `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
// `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
||||||
exists(ObjectCreation oc |
|
exists(ObjectCreation oc |
|
||||||
oc = c and
|
oc = c and
|
||||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||||
not isPropertySet(oc, "Secure") and
|
not isPropertySet(oc, "Secure") and
|
||||||
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
|
exists(DataFlow::Node creation |
|
||||||
cookieTracking.hasFlow(creation, _) and
|
CookieOptionsTracking::flow(creation, _) and
|
||||||
creation.asExpr() = oc
|
creation.asExpr() = oc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -80,10 +80,10 @@ where
|
|||||||
or
|
or
|
||||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||||
not exists(OnAppendCookieSecureTrackingConfig config | config.hasFlowTo(_)) and
|
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||||
// the cookie option is passed to `Append`
|
// the cookie option is passed to `Append`
|
||||||
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
|
exists(DataFlow::Node creation |
|
||||||
cookieTracking.hasFlow(creation, _) and
|
CookieOptionsTracking::flow(creation, _) and
|
||||||
creation.asExpr() = oc
|
creation.asExpr() = oc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import semmle.code.csharp.dataflow.DataFlow2
|
import semmle.code.csharp.dataflow.DataFlow2
|
||||||
import semmle.code.csharp.dataflow.TaintTracking2
|
import semmle.code.csharp.dataflow.TaintTracking2
|
||||||
import DataFlow::PathGraph
|
import HashWithoutSalt::PathGraph
|
||||||
|
|
||||||
/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
|
/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
|
||||||
class HashAlgorithmProvider extends RefType {
|
class HashAlgorithmProvider extends RefType {
|
||||||
@@ -120,12 +120,10 @@ predicate hasHashAncestor(MethodCall mc) {
|
|||||||
* Taint configuration tracking flow from an expression whose name suggests it holds
|
* Taint configuration tracking flow from an expression whose name suggests it holds
|
||||||
* password data to a method call that generates a hash without a salt.
|
* password data to a method call that generates a hash without a salt.
|
||||||
*/
|
*/
|
||||||
class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
module HashWithoutSaltConfig implements DataFlow::ConfigSig {
|
||||||
HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
sink.asExpr() = mc.getArgument(0) and
|
sink.asExpr() = mc.getArgument(0) and
|
||||||
isHashCall(mc) and
|
isHashCall(mc) and
|
||||||
@@ -148,7 +146,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
mc.getTarget()
|
mc.getTarget()
|
||||||
.hasQualifiedName("Windows.Security.Cryptography", "CryptographicBuffer",
|
.hasQualifiedName("Windows.Security.Cryptography", "CryptographicBuffer",
|
||||||
@@ -166,7 +164,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
|||||||
* `byte[] saltedPassword = sha256.ComputeHash(rawSalted);`
|
* `byte[] saltedPassword = sha256.ComputeHash(rawSalted);`
|
||||||
* Or the password is concatenated with a salt as a string.
|
* Or the password is concatenated with a salt as a string.
|
||||||
*/
|
*/
|
||||||
override predicate isSanitizer(DataFlow::Node node) {
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
hasFurtherProcessing(mc) and
|
hasFurtherProcessing(mc) and
|
||||||
mc.getAnArgument() = node.asExpr()
|
mc.getAnArgument() = node.asExpr()
|
||||||
@@ -194,7 +192,9 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c
|
module HashWithoutSalt = TaintTracking::Global<HashWithoutSaltConfig>;
|
||||||
where c.hasFlowPath(source, sink)
|
|
||||||
|
from HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink
|
||||||
|
where HashWithoutSalt::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(),
|
select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(),
|
||||||
"The password"
|
"The password"
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ class TokenValidationParametersPropertySensitiveValidation extends Property {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation` instead.
|
||||||
|
*
|
||||||
* A dataflow from a `false` value to a write sensitive property for `TokenValidationParameters`.
|
* A dataflow from a `false` value to a write sensitive property for `TokenValidationParameters`.
|
||||||
*/
|
*/
|
||||||
class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
|
deprecated class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
|
||||||
{
|
{
|
||||||
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation() {
|
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation() {
|
||||||
this = "FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation"
|
this = "FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation"
|
||||||
@@ -37,6 +39,25 @@ class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dataflow configuration from a `false` value to a write sensitive property for `TokenValidationParameters`.
|
||||||
|
*/
|
||||||
|
private module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig
|
||||||
|
implements DataFlow::ConfigSig
|
||||||
|
{
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().getValue() = "false" and
|
||||||
|
source.asExpr().getType() instanceof BoolType
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
sink.asExpr() = any(TokenValidationParametersPropertySensitiveValidation p).getAnAssignedValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation =
|
||||||
|
DataFlow::Global<FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `assemblyName` is older than version `ver`
|
* Holds if `assemblyName` is older than version `ver`
|
||||||
*/
|
*/
|
||||||
@@ -81,21 +102,6 @@ private class TokenValidationResultIsValidCall extends PropertyRead {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dataflow from the output of `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken` call to access the `IsValid` or `Exception` property
|
|
||||||
*/
|
|
||||||
private class FlowsToTokenValidationResultIsValidCall extends DataFlow::Configuration {
|
|
||||||
FlowsToTokenValidationResultIsValidCall() { this = "FlowsToTokenValidationResultIsValidCall" }
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr() instanceof JsonWebTokenHandlerValidateTokenCall
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(TokenValidationResultIsValidCall call | sink.asExpr() = call.getQualifier())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A security-sensitive property for `Microsoft.IdentityModel.Tokens.TokenValidationParameters`
|
* A security-sensitive property for `Microsoft.IdentityModel.Tokens.TokenValidationParameters`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,11 +16,10 @@ import JsonWebTokenHandlerLib
|
|||||||
import semmle.code.csharp.commons.QualifiedName
|
import semmle.code.csharp.commons.QualifiedName
|
||||||
|
|
||||||
from
|
from
|
||||||
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation config,
|
|
||||||
DataFlow::Node source, DataFlow::Node sink,
|
DataFlow::Node source, DataFlow::Node sink,
|
||||||
TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name
|
TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name
|
||||||
where
|
where
|
||||||
config.hasFlow(source, sink) and
|
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation::flow(source, sink) and
|
||||||
sink.asExpr() = pw.getAnAssignedValue() and
|
sink.asExpr() = pw.getAnAssignedValue() and
|
||||||
pw.hasQualifiedName(qualifier, name)
|
pw.hasQualifiedName(qualifier, name)
|
||||||
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,
|
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,
|
||||||
|
|||||||
@@ -31,16 +31,16 @@ predicate unsafeDataContractTypeCreation(Expr e) {
|
|||||||
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
|
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
|
||||||
}
|
}
|
||||||
|
|
||||||
class Conf extends DataFlow::Configuration {
|
module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig {
|
||||||
Conf() { this = "FlowToDataSerializerConstructor" }
|
predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
|
predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from Conf conf, DataFlow::Node source, DataFlow::Node sink
|
module FlowToDataSerializerConstructor = DataFlow::Global<FlowToDataSerializerConstructorConfig>;
|
||||||
where conf.hasFlow(source, sink)
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink
|
||||||
|
where FlowToDataSerializerConstructor::flow(source, sink)
|
||||||
select sink,
|
select sink,
|
||||||
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
|
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
|
||||||
source, source.toString()
|
source, source.toString()
|
||||||
|
|||||||
@@ -11,23 +11,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import DataFlow::PathGraph
|
|
||||||
import experimental.code.csharp.Cryptography.NonCryptographicHashes
|
import experimental.code.csharp.Cryptography.NonCryptographicHashes
|
||||||
|
import DataFlowFromMethodToHash::PathGraph
|
||||||
|
|
||||||
class DataFlowFromMethodToHash extends TaintTracking::Configuration {
|
module DataFlowFromMethodToHashConfig implements DataFlow::ConfigSig {
|
||||||
DataFlowFromMethodToHash() { this = "DataFlowFromMethodNameToHashFunction" }
|
predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) }
|
||||||
|
|
||||||
/**
|
predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) }
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
override predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
override predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module DataFlowFromMethodToHash = TaintTracking::Global<DataFlowFromMethodToHashConfig>;
|
||||||
|
|
||||||
predicate isGetHash(Expr arg) {
|
predicate isGetHash(Expr arg) {
|
||||||
exists(MethodCall mc |
|
exists(MethodCall mc |
|
||||||
(
|
(
|
||||||
@@ -48,8 +42,8 @@ predicate isSuspiciousPropertyName(PropertyRead pr) {
|
|||||||
pr.getTarget().hasQualifiedName("System.Diagnostics", "Process", "ProcessName")
|
pr.getTarget().hasQualifiedName("System.Diagnostics", "Process", "ProcessName")
|
||||||
}
|
}
|
||||||
|
|
||||||
from DataFlow::PathNode src, DataFlow::PathNode sink, DataFlowFromMethodToHash conf
|
from DataFlowFromMethodToHash::PathNode src, DataFlowFromMethodToHash::PathNode sink
|
||||||
where conf.hasFlow(src.getNode(), sink.getNode())
|
where DataFlowFromMethodToHash::flow(src.getNode(), sink.getNode())
|
||||||
select src.getNode(), src, sink,
|
select src.getNode(), src, sink,
|
||||||
"The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent.",
|
"The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent.",
|
||||||
sink.getNode(), "this process name"
|
sink.getNode(), "this process name"
|
||||||
|
|||||||
@@ -9,18 +9,16 @@ import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
|||||||
* Holds if the expression is a variable with a sensitive name.
|
* Holds if the expression is a variable with a sensitive name.
|
||||||
*/
|
*/
|
||||||
predicate isCookieWithSensitiveName(Expr cookieExpr) {
|
predicate isCookieWithSensitiveName(Expr cookieExpr) {
|
||||||
exists(AuthCookieNameConfiguration dataflow, DataFlow::Node sink |
|
exists(DataFlow::Node sink |
|
||||||
dataflow.hasFlowTo(sink) and
|
AuthCookieName::flowTo(sink) and
|
||||||
sink.asExpr() = cookieExpr
|
sink.asExpr() = cookieExpr
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks if a variable with a sensitive name is used as an argument.
|
* Configuration for tracking if a variable with a sensitive name is used as an argument.
|
||||||
*/
|
*/
|
||||||
private class AuthCookieNameConfiguration extends DataFlow::Configuration {
|
private module AuthCookieNameConfig implements DataFlow::ConfigSig {
|
||||||
AuthCookieNameConfiguration() { this = "AuthCookieNameConfiguration" }
|
|
||||||
|
|
||||||
private predicate isAuthVariable(Expr expr) {
|
private predicate isAuthVariable(Expr expr) {
|
||||||
exists(string val |
|
exists(string val |
|
||||||
(
|
(
|
||||||
@@ -32,17 +30,22 @@ private class AuthCookieNameConfiguration extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) { exists(Call c | sink.asExpr() = c.getAnArgument()) }
|
||||||
exists(Call c | sink.asExpr() = c.getAnArgument())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Tracks if a variable with a sensitive name is used as an argument.
|
||||||
|
*/
|
||||||
|
private module AuthCookieName = DataFlow::Global<AuthCookieNameConfig>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `CookieOptionsTracking` instead.
|
||||||
|
*
|
||||||
* Tracks creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` call as a third parameter.
|
* Tracks creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` call as a third parameter.
|
||||||
*/
|
*/
|
||||||
class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
|
deprecated class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
|
||||||
CookieOptionsTrackingConfiguration() { this = "CookieOptionsTrackingConfiguration" }
|
CookieOptionsTrackingConfiguration() { this = "CookieOptionsTrackingConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
@@ -57,6 +60,29 @@ class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration module tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
|
||||||
|
* calls as a third parameter.
|
||||||
|
*/
|
||||||
|
private module CookieOptionsTrackingConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().(ObjectCreation).getType() instanceof MicrosoftAspNetCoreHttpCookieOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
|
||||||
|
iResponse.getAppendMethod() = mc.getTarget() and
|
||||||
|
mc.getArgument(2) = sink.asExpr()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
|
||||||
|
* calls as a third parameter.
|
||||||
|
*/
|
||||||
|
module CookieOptionsTracking = DataFlow::Global<CookieOptionsTrackingConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for property value of `CookiePolicyOptions` passed to `app.UseCookiePolicy` in `Startup.Configure`.
|
* Looks for property value of `CookiePolicyOptions` passed to `app.UseCookiePolicy` in `Startup.Configure`.
|
||||||
*/
|
*/
|
||||||
@@ -109,18 +135,22 @@ Expr getAValueForProp(ObjectCreation create, Assignment a, string prop) {
|
|||||||
predicate isPropertySet(ObjectCreation oc, string prop) { exists(getAValueForProp(oc, _, prop)) }
|
predicate isPropertySet(ObjectCreation oc, string prop) { exists(getAValueForProp(oc, _, prop)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `OnAppendCookieSecureTracking` instead.
|
||||||
|
*
|
||||||
* Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`.
|
* Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`.
|
||||||
*/
|
*/
|
||||||
class OnAppendCookieSecureTrackingConfig extends OnAppendCookieTrackingConfig {
|
deprecated class OnAppendCookieSecureTrackingConfig extends OnAppendCookieTrackingConfig {
|
||||||
OnAppendCookieSecureTrackingConfig() { this = "OnAppendCookieSecureTrackingConfig" }
|
OnAppendCookieSecureTrackingConfig() { this = "OnAppendCookieSecureTrackingConfig" }
|
||||||
|
|
||||||
override string propertyName() { result = "Secure" }
|
override string propertyName() { result = "Secure" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `OnAppendCookieHttpOnlyTracking` instead.
|
||||||
|
*
|
||||||
* Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
|
* Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
|
||||||
*/
|
*/
|
||||||
class OnAppendCookieHttpOnlyTrackingConfig extends OnAppendCookieTrackingConfig {
|
deprecated class OnAppendCookieHttpOnlyTrackingConfig extends OnAppendCookieTrackingConfig {
|
||||||
OnAppendCookieHttpOnlyTrackingConfig() { this = "OnAppendCookieHttpOnlyTrackingConfig" }
|
OnAppendCookieHttpOnlyTrackingConfig() { this = "OnAppendCookieHttpOnlyTrackingConfig" }
|
||||||
|
|
||||||
override string propertyName() { result = "HttpOnly" }
|
override string propertyName() { result = "HttpOnly" }
|
||||||
@@ -180,3 +210,83 @@ abstract private class OnAppendCookieTrackingConfig extends DataFlow::Configurat
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private signature string propertyName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for tracking if a callback used in `OnAppendCookie` sets a cookie property to `true`.
|
||||||
|
*/
|
||||||
|
private module OnAppendCookieTrackingConfig<propertyName/0 getPropertyName> implements
|
||||||
|
DataFlow::ConfigSig
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specifies the cookie property name to track.
|
||||||
|
*/
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
exists(PropertyWrite pw, Assignment delegateAssign, Callable c |
|
||||||
|
pw.getProperty().getName() = "OnAppendCookie" and
|
||||||
|
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and
|
||||||
|
delegateAssign.getLValue() = pw and
|
||||||
|
(
|
||||||
|
exists(LambdaExpr lambda |
|
||||||
|
delegateAssign.getRValue() = lambda and
|
||||||
|
lambda = c
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DelegateCreation delegate |
|
||||||
|
delegateAssign.getRValue() = delegate and
|
||||||
|
delegate.getArgument().(CallableAccess).getTarget() = c
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
c.getParameter(0) = source.asParameter()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(PropertyWrite pw, Assignment a |
|
||||||
|
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||||
|
pw.getProperty().getName() = getPropertyName() and
|
||||||
|
a.getLValue() = pw and
|
||||||
|
exists(Expr val |
|
||||||
|
DataFlow::localExprFlow(val, a.getRValue()) and
|
||||||
|
val.getValue() = "true"
|
||||||
|
) and
|
||||||
|
sink.asExpr() = pw.getQualifier()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
node2.asExpr() =
|
||||||
|
any(PropertyRead pr |
|
||||||
|
pr.getQualifier() = node1.asExpr() and
|
||||||
|
pr.getProperty().getDeclaringType() instanceof
|
||||||
|
MicrosoftAspNetCoreCookiePolicyAppendCookieContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getPropertyNameSecure() { result = "Secure" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration module for tracking if a callback used in `OnAppendCookie` sets `Secure` to `true`.
|
||||||
|
*/
|
||||||
|
private module OnAppendCookieSecureTrackingConfig =
|
||||||
|
OnAppendCookieTrackingConfig<getPropertyNameSecure/0>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`.
|
||||||
|
*/
|
||||||
|
module OnAppendCookieSecureTracking = DataFlow::Global<OnAppendCookieSecureTrackingConfig>;
|
||||||
|
|
||||||
|
private string getPropertyNameHttpOnly() { result = "HttpOnly" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration module for tracking if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
|
||||||
|
*/
|
||||||
|
private module OnAppendCookieHttpOnlyTrackingConfig =
|
||||||
|
OnAppendCookieTrackingConfig<getPropertyNameHttpOnly/0>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`.
|
||||||
|
*/
|
||||||
|
module OnAppendCookieHttpOnlyTracking = DataFlow::Global<OnAppendCookieHttpOnlyTrackingConfig>;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user