mirror of
https://github.com/github/codeql.git
synced 2026-07-07 04:25:30 +02:00
Compare commits
683 Commits
codeql-cli
...
mbg/csharp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8ccfe40a5 | ||
|
|
653d68ea94 | ||
|
|
952488c2d8 | ||
|
|
7369d043ed | ||
|
|
2e80e09f52 | ||
|
|
ee7f0b0f2a | ||
|
|
ca251fb840 | ||
|
|
984091d4a4 | ||
|
|
e999ec1ecf | ||
|
|
87bd21e12c | ||
|
|
de415d68cf | ||
|
|
6cd5711313 | ||
|
|
8ca75602d8 | ||
|
|
232caa7185 | ||
|
|
537601290b | ||
|
|
05f9a90fd7 | ||
|
|
43e3f8406d | ||
|
|
3061d4a516 | ||
|
|
1f4e7d1f37 | ||
|
|
44239cbf2e | ||
|
|
27de43fed8 | ||
|
|
80be95dbf9 | ||
|
|
65a4dc31c1 | ||
|
|
1dbcaa0ece | ||
|
|
4bf63fedc9 | ||
|
|
5b6ce3e0d0 | ||
|
|
c4e53b842d | ||
|
|
d25045c936 | ||
|
|
ccfb32e989 | ||
|
|
515c65058e | ||
|
|
6fd9e19673 | ||
|
|
1ac6c3751b | ||
|
|
cf71a1525b | ||
|
|
80bd129621 | ||
|
|
e0e82ad7ad | ||
|
|
96564b7128 | ||
|
|
d6ab7d2aff | ||
|
|
f56b2c912a | ||
|
|
02752fa051 | ||
|
|
38e3913fa9 | ||
|
|
dde0281d25 | ||
|
|
4a0875f78d | ||
|
|
963f084d87 | ||
|
|
08de0b40ed | ||
|
|
80d466ffea | ||
|
|
3004639fca | ||
|
|
a19f1d0b8b | ||
|
|
c62b7d139f | ||
|
|
9c4030ed45 | ||
|
|
70a296be89 | ||
|
|
f2d457d083 | ||
|
|
ec0c0f1b35 | ||
|
|
2ada999728 | ||
|
|
f10ffa39e4 | ||
|
|
b7792d690c | ||
|
|
b54d8dc6bd | ||
|
|
10592bb1c4 | ||
|
|
ed6f873478 | ||
|
|
03fdceb0fd | ||
|
|
7e107a4520 | ||
|
|
c187a7ad34 | ||
|
|
c0676f4269 | ||
|
|
eefa066d44 | ||
|
|
b6f0ae0460 | ||
|
|
7092f13584 | ||
|
|
5285fc0698 | ||
|
|
66e4acf53e | ||
|
|
4371433eb6 | ||
|
|
31b9b3adaa | ||
|
|
b9be002e01 | ||
|
|
59ea563d2a | ||
|
|
7463c51026 | ||
|
|
33fe51da4e | ||
|
|
547e232d3b | ||
|
|
e30a429c3d | ||
|
|
5042753b29 | ||
|
|
c6e936f2c3 | ||
|
|
a1e2e920f4 | ||
|
|
1aa6056bd8 | ||
|
|
801f696bbb | ||
|
|
53503002a1 | ||
|
|
4bf7bbb696 | ||
|
|
bb015cf56d | ||
|
|
f4aa3603ad | ||
|
|
63c8769323 | ||
|
|
9885a1cad1 | ||
|
|
919405e586 | ||
|
|
14c4d949d6 | ||
|
|
8c99ad4fcb | ||
|
|
8a5fc97b06 | ||
|
|
f38602e9fe | ||
|
|
b12a1c078c | ||
|
|
e846855bca | ||
|
|
dbb260dfd2 | ||
|
|
a66de28d8e | ||
|
|
cca27e4c77 | ||
|
|
3d8493757e | ||
|
|
89d20fd086 | ||
|
|
c3ea883b11 | ||
|
|
1420f564a5 | ||
|
|
e89f37df1a | ||
|
|
99cbeb7eb6 | ||
|
|
67052bf9e5 | ||
|
|
ca40b60e62 | ||
|
|
8271ad60c1 | ||
|
|
da7bfb9297 | ||
|
|
4a2c02543c | ||
|
|
041df780c1 | ||
|
|
d22ef44f44 | ||
|
|
e6641e7630 | ||
|
|
70c60868a6 | ||
|
|
395bdd0cec | ||
|
|
6928f7d443 | ||
|
|
309202ef89 | ||
|
|
8a1136ddcb | ||
|
|
b50834aee8 | ||
|
|
277c9f4087 | ||
|
|
8ea973f838 | ||
|
|
c113503b41 | ||
|
|
353f1cafe6 | ||
|
|
c654a05998 | ||
|
|
371a11e6da | ||
|
|
0d9e578857 | ||
|
|
fbff4b6e21 | ||
|
|
acc260cc3c | ||
|
|
20f06abe6f | ||
|
|
f07f2b0f4a | ||
|
|
cac4514eae | ||
|
|
3346b64e96 | ||
|
|
2c0baff76a | ||
|
|
4675426241 | ||
|
|
06b1d8e448 | ||
|
|
9734cff15b | ||
|
|
ebe38bca23 | ||
|
|
952f41e17e | ||
|
|
cc4382c785 | ||
|
|
db18d1046b | ||
|
|
8287cdd7b3 | ||
|
|
b65a4e45ab | ||
|
|
4933e803cf | ||
|
|
b99e234cdc | ||
|
|
3c767b086b | ||
|
|
27d2f9e402 | ||
|
|
0bebfa6e45 | ||
|
|
e377a0e05a | ||
|
|
1e1674a08a | ||
|
|
6b7522fe77 | ||
|
|
52dc79eb7d | ||
|
|
3e5f4b7f89 | ||
|
|
fbeb6f3940 | ||
|
|
395901b8e0 | ||
|
|
86515b0140 | ||
|
|
61cb03ea3f | ||
|
|
8e2beb7410 | ||
|
|
e89cf303e7 | ||
|
|
4bd5cc458b | ||
|
|
c0e55a06e7 | ||
|
|
b57a37479b | ||
|
|
0865397e29 | ||
|
|
8375c49ce1 | ||
|
|
ed22f49cdd | ||
|
|
0a93a31565 | ||
|
|
e1c65aae90 | ||
|
|
43eba85589 | ||
|
|
1e656a49b0 | ||
|
|
b8fd20eb05 | ||
|
|
972cd2b21a | ||
|
|
08ef0dc1f2 | ||
|
|
f56e337a7f | ||
|
|
e9bd1e5b79 | ||
|
|
3420f1f43f | ||
|
|
5d13d3b434 | ||
|
|
7db9b7d758 | ||
|
|
70a8bc302c | ||
|
|
012ea4bbf1 | ||
|
|
2a7ce9a0ab | ||
|
|
7f9adbd371 | ||
|
|
2e9f8574a3 | ||
|
|
b0d3c11885 | ||
|
|
4f08fdd232 | ||
|
|
3e0e374783 | ||
|
|
10be890cab | ||
|
|
4d0c53d493 | ||
|
|
14c0bbf531 | ||
|
|
e7ffddd52c | ||
|
|
99bd75c429 | ||
|
|
5d3c9d050d | ||
|
|
824aab884a | ||
|
|
d02f7971a3 | ||
|
|
67745e6332 | ||
|
|
2a33539e01 | ||
|
|
6a8188f8eb | ||
|
|
31775e21b7 | ||
|
|
bb83641634 | ||
|
|
9486e8b734 | ||
|
|
f87024c620 | ||
|
|
7cd344caff | ||
|
|
fbf7e0584f | ||
|
|
6cb0866d0f | ||
|
|
7c1aa84459 | ||
|
|
f7aab2e3e7 | ||
|
|
488903280f | ||
|
|
90fa3ec4ed | ||
|
|
11dedbef1b | ||
|
|
b3896df15c | ||
|
|
a462ec91f5 | ||
|
|
c46f44da5f | ||
|
|
96c1086dfc | ||
|
|
e33f7aa1c7 | ||
|
|
029b567bb7 | ||
|
|
a5521b90fc | ||
|
|
5d79ed6a9e | ||
|
|
a763dd7267 | ||
|
|
9cf2420c3b | ||
|
|
986e1cb597 | ||
|
|
a09262b4c6 | ||
|
|
f7874c37c4 | ||
|
|
5b6a4e616c | ||
|
|
f63f80ab68 | ||
|
|
5020e36d0a | ||
|
|
647515bd84 | ||
|
|
e93ce7c7d5 | ||
|
|
7e0e5a3f4e | ||
|
|
4bcc4254c6 | ||
|
|
f8af648524 | ||
|
|
bd56a3564a | ||
|
|
9d4e737bc2 | ||
|
|
3171f38cdd | ||
|
|
06746e540f | ||
|
|
bcb7901758 | ||
|
|
49b569cc4b | ||
|
|
0f3469313f | ||
|
|
47487cca0e | ||
|
|
a6f20a6ac1 | ||
|
|
b8d60cbb13 | ||
|
|
ad7480591b | ||
|
|
5f41b6d3f2 | ||
|
|
13afd6310b | ||
|
|
8feca3d532 | ||
|
|
32bfaa8569 | ||
|
|
6d37efc0d8 | ||
|
|
f9d9f9ba62 | ||
|
|
088a3ef15c | ||
|
|
9f6a2e090e | ||
|
|
a7a77a5f23 | ||
|
|
5b50a8270d | ||
|
|
1d0338444a | ||
|
|
5bcc694f6a | ||
|
|
08648f912e | ||
|
|
1c06c4aae0 | ||
|
|
61a4b251c0 | ||
|
|
418ab4b22a | ||
|
|
7acbf1a984 | ||
|
|
072713f771 | ||
|
|
d2de9a2238 | ||
|
|
9ca0fe4cbf | ||
|
|
2810d64b22 | ||
|
|
a9817a0281 | ||
|
|
b05d290bf0 | ||
|
|
fd773603e6 | ||
|
|
9a1c1f4be3 | ||
|
|
50c917d2eb | ||
|
|
c1937ea549 | ||
|
|
1d2e08a3b6 | ||
|
|
62194f5337 | ||
|
|
e673348ed3 | ||
|
|
a2c46749c6 | ||
|
|
1ca57cfb9d | ||
|
|
c71778f1aa | ||
|
|
dbae553146 | ||
|
|
fe28657c7d | ||
|
|
98fd97799c | ||
|
|
1ae174849f | ||
|
|
76318035ff | ||
|
|
9c2366a660 | ||
|
|
875478c1c6 | ||
|
|
aa557cf950 | ||
|
|
a0df33c3ac | ||
|
|
155f1fca85 | ||
|
|
23b18aeca9 | ||
|
|
eca7a88615 | ||
|
|
7db6f7c721 | ||
|
|
faef9dd877 | ||
|
|
41fef0f2b3 | ||
|
|
18c7b18f82 | ||
|
|
89f3b6f8d3 | ||
|
|
38be0e4c0a | ||
|
|
41f21d429b | ||
|
|
5727fda07a | ||
|
|
e8ddb6b180 | ||
|
|
1b224c1ab2 | ||
|
|
1a0442c5a6 | ||
|
|
5790f5d5dc | ||
|
|
2bc89900fb | ||
|
|
5c2a6b8865 | ||
|
|
a8188598b0 | ||
|
|
4e7115538b | ||
|
|
d89678f49f | ||
|
|
5251dc2058 | ||
|
|
d86fea5ba5 | ||
|
|
27738eaacc | ||
|
|
c113a0b5a1 | ||
|
|
60c212bb10 | ||
|
|
ba560f2fe9 | ||
|
|
e96f15d9b4 | ||
|
|
df2e2e503a | ||
|
|
c580046f8c | ||
|
|
9ec9d79b4f | ||
|
|
46abb9083b | ||
|
|
5ef496dd1b | ||
|
|
7402276ec7 | ||
|
|
85778f7fea | ||
|
|
8f886c6603 | ||
|
|
2b0c7a209b | ||
|
|
a4b2ee1205 | ||
|
|
b820b324bd | ||
|
|
216d298780 | ||
|
|
89b2a6b726 | ||
|
|
0e94ee81ae | ||
|
|
2cba97e87d | ||
|
|
1bc1472b0b | ||
|
|
4990f16ba5 | ||
|
|
8dc0688b6f | ||
|
|
593896b40e | ||
|
|
553bc8c13d | ||
|
|
86c7a49264 | ||
|
|
556774edc7 | ||
|
|
92427ab0c1 | ||
|
|
8abd3c4707 | ||
|
|
d779ae5c3e | ||
|
|
24eb65692f | ||
|
|
141259c003 | ||
|
|
7ab5663fa6 | ||
|
|
8d59159691 | ||
|
|
d30f3e2822 | ||
|
|
e42c7452ef | ||
|
|
39b61598e9 | ||
|
|
f7cf5af720 | ||
|
|
36acfeb305 | ||
|
|
6d6f269e6c | ||
|
|
0c6b4cdb8f | ||
|
|
f65f11b404 | ||
|
|
6aa7c93af2 | ||
|
|
fc6c327ab7 | ||
|
|
047e9742a0 | ||
|
|
e1f70a0dec | ||
|
|
5279857d06 | ||
|
|
adbd4d35ed | ||
|
|
a6fc41ec4b | ||
|
|
38eb3e4952 | ||
|
|
2ff2d25784 | ||
|
|
408a38d9fb | ||
|
|
0d45f0efb2 | ||
|
|
2b1caa8a35 | ||
|
|
5a4b720322 | ||
|
|
6f32c4129d | ||
|
|
7f86f8cac7 | ||
|
|
bcc89ecb7c | ||
|
|
196634ecdb | ||
|
|
8c111382ad | ||
|
|
47eb407be9 | ||
|
|
9f09454db9 | ||
|
|
cb0ac61db6 | ||
|
|
d9b278de66 | ||
|
|
f508f8eb83 | ||
|
|
7a86257968 | ||
|
|
d73dcd6753 | ||
|
|
8a01161d4a | ||
|
|
8252e1da02 | ||
|
|
44b1ad52d9 | ||
|
|
8c6e08c94e | ||
|
|
96a796585f | ||
|
|
460df89f28 | ||
|
|
1090164b77 | ||
|
|
28c0e899b7 | ||
|
|
e6302cae53 | ||
|
|
e8981a505d | ||
|
|
77f5168590 | ||
|
|
be5bd1da0a | ||
|
|
82f2c6075f | ||
|
|
88fc7be0a2 | ||
|
|
9ead2dc03c | ||
|
|
93e7202a69 | ||
|
|
5e7cd46117 | ||
|
|
2fb670a27c | ||
|
|
511f791511 | ||
|
|
c3b4447586 | ||
|
|
74aa47a809 | ||
|
|
269ea75036 | ||
|
|
b47e9612eb | ||
|
|
261e0a1a53 | ||
|
|
8fd581dd7e | ||
|
|
d06b5833cf | ||
|
|
f92e8555a6 | ||
|
|
e9a13aec1d | ||
|
|
adafe3e5b0 | ||
|
|
05b6700607 | ||
|
|
c2b342f1a0 | ||
|
|
d5c8dfd88c | ||
|
|
25664d0e53 | ||
|
|
03ab74e07d | ||
|
|
0de6658660 | ||
|
|
e9dff4d68f | ||
|
|
0d02126f12 | ||
|
|
37935eea3b | ||
|
|
d6372aebc7 | ||
|
|
e38b63ebcd | ||
|
|
178da21fb8 | ||
|
|
e6161a5019 | ||
|
|
5eb91fd516 | ||
|
|
68a4ea3be0 | ||
|
|
bded7085f0 | ||
|
|
d38f0eec7b | ||
|
|
3d467b24f8 | ||
|
|
4b0b038513 | ||
|
|
f8d623e905 | ||
|
|
940a99db3b | ||
|
|
fb04e39935 | ||
|
|
7210786721 | ||
|
|
f0045692a7 | ||
|
|
addef2f171 | ||
|
|
c6eaed343d | ||
|
|
7f84cf6d72 | ||
|
|
7baaa2373f | ||
|
|
4c50c083fb | ||
|
|
f2f577f86c | ||
|
|
d8b58f21c7 | ||
|
|
b1b62f2362 | ||
|
|
b32e578580 | ||
|
|
4dab0390c9 | ||
|
|
f3cd61f043 | ||
|
|
fcf16848d2 | ||
|
|
3b4fdb3fc2 | ||
|
|
60155ce205 | ||
|
|
4fa8c6ae65 | ||
|
|
227f9c7c1b | ||
|
|
4d851440b6 | ||
|
|
e7c10c6325 | ||
|
|
86c25d0396 | ||
|
|
28d517da59 | ||
|
|
626b1cef17 | ||
|
|
2e90c80a6f | ||
|
|
143d7e2084 | ||
|
|
faabc9982e | ||
|
|
6e627f6543 | ||
|
|
cdfb085e99 | ||
|
|
d2021b9c65 | ||
|
|
75a3c931d1 | ||
|
|
fa7c6f8b5e | ||
|
|
169671ad93 | ||
|
|
fe2d0b631c | ||
|
|
194f967d74 | ||
|
|
ed67dae850 | ||
|
|
9a07b3c3d4 | ||
|
|
e49a5be62f | ||
|
|
ab9a2bdf9a | ||
|
|
44c94e02fe | ||
|
|
20eaaa5699 | ||
|
|
e81c3483db | ||
|
|
292b29b0e3 | ||
|
|
176e9a425f | ||
|
|
e64f139c98 | ||
|
|
374769873a | ||
|
|
be40085982 | ||
|
|
a85ad4ec29 | ||
|
|
ca424d1e61 | ||
|
|
3fa93e5ca9 | ||
|
|
30581d7c1d | ||
|
|
b6cdae20d8 | ||
|
|
d3dd94433b | ||
|
|
61e00861e5 | ||
|
|
258f72db46 | ||
|
|
37365c746c | ||
|
|
66cf736b4c | ||
|
|
583651ba40 | ||
|
|
248f1c4ebe | ||
|
|
7059fc3e31 | ||
|
|
01cddcc042 | ||
|
|
44126913cd | ||
|
|
f8fff4b18c | ||
|
|
40bb7ec6ef | ||
|
|
9b2590ec7a | ||
|
|
c0474c4e45 | ||
|
|
7c8ca7a4d3 | ||
|
|
a82d267223 | ||
|
|
4effe9e364 | ||
|
|
6776b31c0d | ||
|
|
b7c7a9ee7c | ||
|
|
ae6b7b0277 | ||
|
|
fffeac6a13 | ||
|
|
49e002843e | ||
|
|
bb70bfce43 | ||
|
|
636c047c41 | ||
|
|
0836c3d6a5 | ||
|
|
38fa3c10d6 | ||
|
|
d3e44028ea | ||
|
|
8050b8246b | ||
|
|
10f692b57c | ||
|
|
d3e8292db9 | ||
|
|
ac4121dd6c | ||
|
|
6f3e6edd0e | ||
|
|
7ee0a7b398 | ||
|
|
edb9b47111 | ||
|
|
65be8a8aed | ||
|
|
c80a45f2a3 | ||
|
|
c2b426df76 | ||
|
|
6a6154913b | ||
|
|
36d8a6d05f | ||
|
|
295626d53b | ||
|
|
d8b453fc0d | ||
|
|
5012332bb2 | ||
|
|
86a7c486f9 | ||
|
|
be7aca9780 | ||
|
|
e6887f982e | ||
|
|
ca18005e44 | ||
|
|
c8736e8a3d | ||
|
|
1c2fdc29a3 | ||
|
|
fab29361cb | ||
|
|
6dc599c200 | ||
|
|
932ced4ace | ||
|
|
8c74478ef4 | ||
|
|
82ca369dce | ||
|
|
d6ceb89324 | ||
|
|
f25c16245c | ||
|
|
d828941b7c | ||
|
|
6aa74123af | ||
|
|
43eda58f83 | ||
|
|
afc2d3e6d2 | ||
|
|
09f73d8d6f | ||
|
|
d609c1b7e6 | ||
|
|
fd45e11f4b | ||
|
|
b4af5a61d1 | ||
|
|
596cfcfb42 | ||
|
|
9aede5f433 | ||
|
|
69ad69c38a | ||
|
|
69df07ed12 | ||
|
|
64c45debdb | ||
|
|
9dbf7d1828 | ||
|
|
dcf3b31f62 | ||
|
|
d9a830e008 | ||
|
|
59df4de8af | ||
|
|
cdf43f7118 | ||
|
|
a957e00fe5 | ||
|
|
b4718792d1 | ||
|
|
58faa2d71e | ||
|
|
6344f83e4b | ||
|
|
3f56fc9e89 | ||
|
|
42e0d7ce10 | ||
|
|
5f9b8c05bd | ||
|
|
e5eed2302f | ||
|
|
93f6f042e1 | ||
|
|
aab0d5e9e4 | ||
|
|
52cd7f2c5c | ||
|
|
4d04c5af83 | ||
|
|
9b4b01a442 | ||
|
|
24adbb80c7 | ||
|
|
55121d866c | ||
|
|
6a3e34cc4c | ||
|
|
57973df795 | ||
|
|
745e52f659 | ||
|
|
9a8a27750e | ||
|
|
4fb028cbb2 | ||
|
|
d80aa6fa6a | ||
|
|
cf84c08abf | ||
|
|
4e777561f0 | ||
|
|
f21439a6e3 | ||
|
|
23485f185b | ||
|
|
a69daa0d20 | ||
|
|
ae1ed385f6 | ||
|
|
07847762e1 | ||
|
|
38a5f63437 | ||
|
|
5a18f1ff07 | ||
|
|
63ddd81059 | ||
|
|
26d590a616 | ||
|
|
3909df75dc | ||
|
|
a2c6278282 | ||
|
|
dd87b1a9de | ||
|
|
bf824cac0a | ||
|
|
e4f982c12c | ||
|
|
fce13aeb35 | ||
|
|
a398f707fe | ||
|
|
a709fc6a54 | ||
|
|
d4ec8f650a | ||
|
|
3b01efaf5d | ||
|
|
5bb765d834 | ||
|
|
0fc46f5855 | ||
|
|
2da1d6aaa8 | ||
|
|
54e7db2294 | ||
|
|
1c874d3221 | ||
|
|
e2530cf14f | ||
|
|
358098230c | ||
|
|
a4ccda5fe3 | ||
|
|
28ead4011a | ||
|
|
f1e95a8a1d | ||
|
|
6ed895064f | ||
|
|
758092b1d6 | ||
|
|
49eefccde1 | ||
|
|
307fdc0864 | ||
|
|
e57d8983f5 | ||
|
|
9fc0dc5690 | ||
|
|
874dc83f3f | ||
|
|
81907bc743 | ||
|
|
bc784268fd | ||
|
|
791313fbdf | ||
|
|
cc62db796c | ||
|
|
5a0cd2e7d6 | ||
|
|
8cbab0c66e | ||
|
|
d37c816bd9 | ||
|
|
25cd4d4585 | ||
|
|
a0729fc760 | ||
|
|
35cbc162b0 | ||
|
|
85c7e8c221 | ||
|
|
fbaad09179 | ||
|
|
b4c84be3be | ||
|
|
e4eef6791a | ||
|
|
4cca6cff59 | ||
|
|
2282a8184b | ||
|
|
1c305aa8f3 | ||
|
|
1ab50fc62c | ||
|
|
fb050e8b43 | ||
|
|
d9d3e74e8c | ||
|
|
1315a1e9ae | ||
|
|
924467bebe | ||
|
|
c7c6924fda | ||
|
|
6a7fb06086 | ||
|
|
2df565c84f | ||
|
|
28d0ad94d5 | ||
|
|
3673c7c813 | ||
|
|
4208f031e3 | ||
|
|
aea7c3fc81 | ||
|
|
c03d69af1e | ||
|
|
b64b837db3 | ||
|
|
1b0f8aa657 | ||
|
|
72a69cfa17 | ||
|
|
792231c949 | ||
|
|
84f3e6a0d3 | ||
|
|
1c7b5aebb5 | ||
|
|
4b83a451bd | ||
|
|
de05aee483 | ||
|
|
08bf6d7d30 | ||
|
|
88be4b88ab | ||
|
|
213ce225e0 | ||
|
|
8ae05d8be4 | ||
|
|
c02ad65fdc | ||
|
|
3786ad4277 | ||
|
|
a28fc8e772 | ||
|
|
7250099f6c | ||
|
|
fcb65534a8 | ||
|
|
ea90698fc1 | ||
|
|
15953bf569 | ||
|
|
20685918bd | ||
|
|
b581723a63 | ||
|
|
176acabd9d | ||
|
|
a31e983e9e | ||
|
|
c86bbbb063 | ||
|
|
37712d2e21 | ||
|
|
c2c6b77b11 | ||
|
|
82f09f1f8b | ||
|
|
ede72b2680 | ||
|
|
f827ad8157 | ||
|
|
04926df6ea | ||
|
|
0d1bd8a9cd | ||
|
|
7b265b2df3 | ||
|
|
7279cc42f8 | ||
|
|
459d16824e | ||
|
|
bf11e2cd0f | ||
|
|
9b43b4994e | ||
|
|
7e98d02d56 | ||
|
|
2757b0ba6e | ||
|
|
1e1bbe92a3 | ||
|
|
8b73d4af86 | ||
|
|
1079486032 | ||
|
|
cc6b09da48 | ||
|
|
a99dd69d87 | ||
|
|
de2f8a1577 | ||
|
|
e142818fe5 | ||
|
|
e8aac2be9a | ||
|
|
27ad882f54 | ||
|
|
2bfca21a2f | ||
|
|
9b92ff7e78 | ||
|
|
211cda390d | ||
|
|
cfa1ad65c8 | ||
|
|
49a4318ab1 |
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"rust-lang.rust-analyzer",
|
"rust-lang.rust-analyzer",
|
||||||
"bungcip.better-toml",
|
"bungcip.better-toml",
|
||||||
|
|||||||
9
.github/workflows/compile-queries.yml
vendored
9
.github/workflows/compile-queries.yml
vendored
@@ -7,6 +7,11 @@ on:
|
|||||||
- "rc/*"
|
- "rc/*"
|
||||||
- "codeql-cli-*"
|
- "codeql-cli-*"
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '**.ql'
|
||||||
|
- '**.qll'
|
||||||
|
- '**/qlpack.yml'
|
||||||
|
- '**.dbscheme'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -33,9 +38,9 @@ jobs:
|
|||||||
# run with --check-only if running in a PR (github.sha != main)
|
# run with --check-only if running in a PR (github.sha != main)
|
||||||
if : ${{ github.event_name == 'pull_request' }}
|
if : ${{ github.event_name == 'pull_request' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||||
- name: compile queries - full
|
- name: compile queries - full
|
||||||
# do full compile if running on main - this populates the cache
|
# do full compile if running on main - this populates the cache
|
||||||
if : ${{ github.event_name != 'pull_request' }}
|
if : ${{ github.event_name != 'pull_request' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||||
|
|||||||
4
.github/workflows/csharp-qltest.yml
vendored
4
.github/workflows/csharp-qltest.yml
vendored
@@ -5,8 +5,10 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "csharp/**"
|
- "csharp/**"
|
||||||
- "shared/**"
|
- "shared/**"
|
||||||
|
- "misc/bazel/**"
|
||||||
- .github/actions/fetch-codeql/action.yml
|
- .github/actions/fetch-codeql/action.yml
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
|
- "MODULE.bazel"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- "rc/*"
|
- "rc/*"
|
||||||
@@ -14,9 +16,11 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "csharp/**"
|
- "csharp/**"
|
||||||
- "shared/**"
|
- "shared/**"
|
||||||
|
- "misc/bazel/**"
|
||||||
- .github/workflows/csharp-qltest.yml
|
- .github/workflows/csharp-qltest.yml
|
||||||
- .github/actions/fetch-codeql/action.yml
|
- .github/actions/fetch-codeql/action.yml
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
|
- "MODULE.bazel"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- "rc/*"
|
- "rc/*"
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ repos:
|
|||||||
|
|
||||||
- id: rust-codegen
|
- id: rust-codegen
|
||||||
name: Run Rust checked in code generation
|
name: Run Rust checked in code generation
|
||||||
files: ^misc/codegen/|^rust/(schema.py$|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list)
|
files: ^misc/codegen/|^rust/(prefix\.dbscheme|schema/|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list)
|
||||||
language: system
|
language: system
|
||||||
entry: bazel run //rust/codegen -- --quiet
|
entry: bazel run //rust/codegen -- --quiet
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|||||||
87
.vscode/tasks.json
vendored
87
.vscode/tasks.json
vendored
@@ -38,6 +38,93 @@
|
|||||||
"command": "${config:python.pythonPath}",
|
"command": "${config:python.pythonPath}",
|
||||||
},
|
},
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Create query change note",
|
||||||
|
"type": "process",
|
||||||
|
"command": "python3",
|
||||||
|
"args": [
|
||||||
|
"misc/scripts/create-change-note.py",
|
||||||
|
"${input:language}",
|
||||||
|
"src",
|
||||||
|
"${input:name}",
|
||||||
|
"${input:categoryQuery}"
|
||||||
|
],
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never",
|
||||||
|
"close": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Create library change note",
|
||||||
|
"type": "process",
|
||||||
|
"command": "python3",
|
||||||
|
"args": [
|
||||||
|
"misc/scripts/create-change-note.py",
|
||||||
|
"${input:language}",
|
||||||
|
"lib",
|
||||||
|
"${input:name}",
|
||||||
|
"${input:categoryLibrary}"
|
||||||
|
],
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never",
|
||||||
|
"close": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"type": "pickString",
|
||||||
|
"id": "language",
|
||||||
|
"description": "Language",
|
||||||
|
"options":
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"java",
|
||||||
|
"javascript",
|
||||||
|
"cpp",
|
||||||
|
"csharp",
|
||||||
|
"python",
|
||||||
|
"ruby",
|
||||||
|
"rust",
|
||||||
|
"swift",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "promptString",
|
||||||
|
"id": "name",
|
||||||
|
"description": "Short name (kebab-case)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "pickString",
|
||||||
|
"id": "categoryQuery",
|
||||||
|
"description": "Category (query change)",
|
||||||
|
"options":
|
||||||
|
[
|
||||||
|
"breaking",
|
||||||
|
"deprecated",
|
||||||
|
"newQuery",
|
||||||
|
"queryMetadata",
|
||||||
|
"majorAnalysis",
|
||||||
|
"minorAnalysis",
|
||||||
|
"fix",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "pickString",
|
||||||
|
"id": "categoryLibrary",
|
||||||
|
"description": "Category (library change)",
|
||||||
|
"options":
|
||||||
|
[
|
||||||
|
"breaking",
|
||||||
|
"deprecated",
|
||||||
|
"feature",
|
||||||
|
"majorAnalysis",
|
||||||
|
"minorAnalysis",
|
||||||
|
"fix",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4
2024-11-25-ts57.md
Normal file
4
2024-11-25-ts57.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: majorAnalysis
|
||||||
|
---
|
||||||
|
* Added support for TypeScript 5.7.
|
||||||
@@ -42,3 +42,6 @@ MODULE.bazel @github/codeql-ci-reviewers
|
|||||||
# Misc
|
# Misc
|
||||||
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
||||||
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
|
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
|
||||||
|
|
||||||
|
# .devcontainer
|
||||||
|
/.devcontainer/ @github/codeql-ci-reviewers
|
||||||
|
|||||||
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -381,8 +381,10 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argfile",
|
"argfile",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"codeql-extractor",
|
"codeql-extractor",
|
||||||
|
"dunce",
|
||||||
"figment",
|
"figment",
|
||||||
"glob",
|
"glob",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
@@ -404,6 +406,7 @@ dependencies = [
|
|||||||
"ra_ap_vfs",
|
"ra_ap_vfs",
|
||||||
"rust-extractor-macros",
|
"rust-extractor-macros",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"stderrlog",
|
"stderrlog",
|
||||||
"triomphe",
|
"triomphe",
|
||||||
@@ -540,6 +543,12 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dunce"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
@@ -2034,9 +2043,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.132"
|
version = "1.0.133"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ use_repo(py_deps, "vendor__anyhow-1.0.44", "vendor__cc-1.0.70", "vendor__clap-2.
|
|||||||
# deps for ruby+rust
|
# deps for ruby+rust
|
||||||
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
|
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
|
||||||
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
|
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
|
||||||
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.132", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
|
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__dunce-1.0.5", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.133", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
|
||||||
|
|
||||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||||
dotnet.toolchain(dotnet_version = "9.0.100")
|
dotnet.toolchain(dotnet_version = "9.0.100")
|
||||||
|
|||||||
@@ -1,58 +1,4 @@
|
|||||||
{
|
{
|
||||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
|
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
|
||||||
],
|
|
||||||
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll",
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
|
||||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
|
||||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
|
||||||
],
|
|
||||||
"SsaReadPosition Java/C#": [
|
"SsaReadPosition Java/C#": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||||
|
|||||||
2339
cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme
Normal file
2339
cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
description: Implement compilation_build_mode/2
|
||||||
|
compatibility: full
|
||||||
|
compilation_build_mode.rel: delete
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API.
|
||||||
|
|
||||||
|
### Deprecated APIs
|
||||||
|
|
||||||
|
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
|
||||||
|
|
||||||
## 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
9
cpp/ql/lib/change-notes/released/3.0.0.md
Normal file
9
cpp/ql/lib/change-notes/released/3.0.0.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API.
|
||||||
|
|
||||||
|
### Deprecated APIs
|
||||||
|
|
||||||
|
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 2.1.1
|
lastReleaseVersion: 3.0.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 2.1.1
|
version: 3.0.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -112,4 +112,7 @@ class Compilation extends @compilation {
|
|||||||
* termination, but crashing due to something like a segfault is not.
|
* termination, but crashing due to something like a segfault is not.
|
||||||
*/
|
*/
|
||||||
predicate normalTermination() { compilation_finished(this, _, _) }
|
predicate normalTermination() { compilation_finished(this, _, _) }
|
||||||
|
|
||||||
|
/** Holds if this compilation was compiled using the "none" build mode. */
|
||||||
|
predicate buildModeNone() { compilation_build_mode(this, 0) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,5 @@ deprecated module DataFlow {
|
|||||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
||||||
private import codeql.dataflow.DataFlow
|
private import codeql.dataflow.DataFlow
|
||||||
import DataFlowMake<Location, CppOldDataFlow>
|
import DataFlowMake<Location, CppOldDataFlow>
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
import Public
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
deprecated module DataFlow2 {
|
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow3` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
deprecated module DataFlow3 {
|
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow4` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
deprecated module DataFlow4 {
|
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
|
||||||
}
|
|
||||||
@@ -793,28 +793,27 @@ private Element interpretElement0(
|
|||||||
) {
|
) {
|
||||||
(
|
(
|
||||||
// Non-member functions
|
// Non-member functions
|
||||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
funcHasQualifiedName(result, namespace, name) and
|
||||||
subtypes = false and
|
subtypes = false and
|
||||||
type = "" and
|
type = "" and
|
||||||
(
|
(
|
||||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||||
or
|
or
|
||||||
signature = "" and
|
signature = "" and
|
||||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
elementSpec(namespace, type, subtypes, name, signature, _)
|
||||||
funcHasQualifiedName(result, namespace, name)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Member functions
|
// Member functions
|
||||||
exists(Class namedClass, Class classWithMethod |
|
exists(Class namedClass, Class classWithMethod |
|
||||||
|
hasClassAndName(classWithMethod, result, name) and
|
||||||
|
classHasQualifiedName(namedClass, namespace, type)
|
||||||
|
|
|
||||||
(
|
(
|
||||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) and
|
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||||
hasClassAndName(classWithMethod, result, name)
|
|
||||||
or
|
or
|
||||||
signature = "" and
|
signature = "" and
|
||||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
elementSpec(namespace, type, subtypes, name, "", _)
|
||||||
hasClassAndName(classWithMethod, result, name)
|
|
||||||
) and
|
) and
|
||||||
classHasQualifiedName(namedClass, namespace, type) and
|
|
||||||
(
|
(
|
||||||
// member declared in the named type or a subtype of it
|
// member declared in the named type or a subtype of it
|
||||||
subtypes = true and
|
subtypes = true and
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in
|
|
||||||
* any supported tooling. There is no need for this module because it's
|
|
||||||
* impossible to accidentally depend on recursion through
|
|
||||||
* `DataFlow::Configuration` in current releases.
|
|
||||||
*
|
|
||||||
* When this module is imported, recursive use of `DataFlow::Configuration` is
|
|
||||||
* disallowed. Importing this module will guarantee the absence of such
|
|
||||||
* recursion, which is unsupported and will be unconditionally disallowed in a
|
|
||||||
* future release.
|
|
||||||
*
|
|
||||||
* Recursive use of `DataFlow{2..4}::Configuration` is always disallowed, so no
|
|
||||||
* import is needed for those.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
private import semmle.code.cpp.dataflow.DataFlow
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
* Four copies are available: `DataFlow` through `DataFlow4`.
|
|
||||||
*/
|
|
||||||
abstract private class ConfigurationRecursionPrevention extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
strictcount(DataFlow::Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(DataFlow::Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(DataFlow::Node n1, DataFlow::Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.dataflow.DataFlow
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
import semmle.code.cpp.dataflow.DataFlow2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead.
|
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead.
|
||||||
@@ -25,10 +24,9 @@ import semmle.code.cpp.dataflow.DataFlow2
|
|||||||
* global (inter-procedural) taint-tracking analyses.
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
*/
|
*/
|
||||||
deprecated module TaintTracking {
|
deprecated module TaintTracking {
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil
|
||||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
||||||
private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific
|
private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific
|
||||||
private import codeql.dataflow.TaintTracking
|
private import codeql.dataflow.TaintTracking
|
||||||
import TaintFlowMake<Location, CppOldDataFlow, CppOldTaintTracking>
|
import TaintFlowMake<Location, CppOldDataFlow, CppOldTaintTracking>
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
|
||||||
* module. Use this class when data-flow configurations or taint-tracking
|
|
||||||
* configurations must depend on each other. Two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
|
||||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
|
||||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.TaintTracking` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking2` instead.
|
|
||||||
*
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
|
||||||
*/
|
|
||||||
deprecated module TaintTracking2 {
|
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
|
||||||
}
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -729,41 +729,39 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
|||||||
|
|
||||||
private module FieldFlow {
|
private module FieldFlow {
|
||||||
private import DataFlowImplCommon
|
private import DataFlowImplCommon
|
||||||
private import DataFlowImplLocal
|
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
|
private import semmle.code.cpp.dataflow.DataFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration for finding local-only flow through fields. This uses the
|
* A configuration for finding local-only flow through fields.
|
||||||
* `Configuration` class in the dedicated `DataFlowImplLocal` copy of the
|
|
||||||
* shared library that's not user-exposed directly.
|
|
||||||
*
|
*
|
||||||
* To keep the flow local to a single function, we put barriers on parameters
|
* To keep the flow local to a single function, we put barriers on parameters
|
||||||
* and return statements. Sources and sinks are the values that go into and
|
* and return statements. Sources and sinks are the values that go into and
|
||||||
* out of fields, respectively.
|
* out of fields, respectively.
|
||||||
*/
|
*/
|
||||||
private class FieldConfiguration extends Configuration {
|
private module FieldConfig implements DataFlow::ConfigSig {
|
||||||
FieldConfiguration() { this = "FieldConfiguration" }
|
predicate isSource(Node source) {
|
||||||
|
|
||||||
override predicate isSource(Node source) {
|
|
||||||
storeStep(source, _, _)
|
storeStep(source, _, _)
|
||||||
or
|
or
|
||||||
// Also mark `foo(a.b);` as a source when `a.b` may be overwritten by `foo`.
|
// Also mark `foo(a.b);` as a source when `a.b` may be overwritten by `foo`.
|
||||||
readStep(_, _, any(Node node | node.asExpr() = source.asDefiningArgument()))
|
readStep(_, _, any(Node node | node.asExpr() = source.asDefiningArgument()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(Node sink) { readStep(_, _, sink) }
|
predicate isSink(Node sink) { readStep(_, _, sink) }
|
||||||
|
|
||||||
override predicate isBarrier(Node node) { node instanceof ParameterNode }
|
predicate isBarrier(Node node) { node instanceof ParameterNode }
|
||||||
|
|
||||||
override predicate isBarrierOut(Node node) {
|
predicate isBarrierOut(Node node) {
|
||||||
node.asExpr().getParent() instanceof ReturnStmt
|
node.asExpr().getParent() instanceof ReturnStmt
|
||||||
or
|
or
|
||||||
node.asExpr().getParent() instanceof ThrowExpr
|
node.asExpr().getParent() instanceof ThrowExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module Flow = DataFlow::Global<FieldConfig>;
|
||||||
|
|
||||||
predicate fieldFlow(Node node1, Node node2) {
|
predicate fieldFlow(Node node1, Node node2) {
|
||||||
exists(FieldConfiguration cfg | cfg.hasFlow(node1, node2)) and
|
Flow::flow(node1, node2) and
|
||||||
// This configuration should not be able to cross function boundaries, but
|
// This configuration should not be able to cross function boundaries, but
|
||||||
// we double-check here just to be sure.
|
// we double-check here just to be sure.
|
||||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2)
|
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2)
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides an implementation of global (interprocedural) taint tracking.
|
|
||||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
|
||||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
|
||||||
* exposed through the `Configuration` class. For some languages, this file
|
|
||||||
* exists in several identical copies, allowing queries to use multiple
|
|
||||||
* `Configuration` classes that depend on each other without introducing
|
|
||||||
* mutual recursion among those configurations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TaintTrackingParameter::Public
|
|
||||||
private import TaintTrackingParameter::Private
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural taint tracking analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the taint tracking library must define its own unique extension of
|
|
||||||
* this abstract class.
|
|
||||||
*
|
|
||||||
* A taint-tracking configuration is a special data flow configuration
|
|
||||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
|
||||||
* necessarily preserve values but are still relevant from a taint tracking
|
|
||||||
* perspective. (For example, string concatenation, where one of the operands
|
|
||||||
* is tainted.)
|
|
||||||
*
|
|
||||||
* To create a configuration, extend this class with a subclass whose
|
|
||||||
* characteristic predicate is a unique singleton string. For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isSanitizer`.
|
|
||||||
* // Optionally override `isSanitizerIn`.
|
|
||||||
* // Optionally override `isSanitizerOut`.
|
|
||||||
* // Optionally override `isSanitizerGuard`.
|
|
||||||
* // Optionally override `isAdditionalTaintStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
|
||||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
|
||||||
* overridden predicates that define sources, sinks, or additional steps.
|
|
||||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
|
||||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
|
||||||
this.isSanitizer(node) or
|
|
||||||
defaultTaintSanitizer(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizer(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
this.isAdditionalTaintStep(node1, node2) or
|
|
||||||
defaultAdditionalTaintStep(node1, node2, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
|
||||||
(
|
|
||||||
this.isSink(node) or
|
|
||||||
this.isSink(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _, _, _)
|
|
||||||
) and
|
|
||||||
defaultImplicitTaintRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
|
||||||
|
|
||||||
module Private {
|
|
||||||
import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow
|
|
||||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides an implementation of global (interprocedural) taint tracking.
|
|
||||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
|
||||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
|
||||||
* exposed through the `Configuration` class. For some languages, this file
|
|
||||||
* exists in several identical copies, allowing queries to use multiple
|
|
||||||
* `Configuration` classes that depend on each other without introducing
|
|
||||||
* mutual recursion among those configurations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TaintTrackingParameter::Public
|
|
||||||
private import TaintTrackingParameter::Private
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural taint tracking analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the taint tracking library must define its own unique extension of
|
|
||||||
* this abstract class.
|
|
||||||
*
|
|
||||||
* A taint-tracking configuration is a special data flow configuration
|
|
||||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
|
||||||
* necessarily preserve values but are still relevant from a taint tracking
|
|
||||||
* perspective. (For example, string concatenation, where one of the operands
|
|
||||||
* is tainted.)
|
|
||||||
*
|
|
||||||
* To create a configuration, extend this class with a subclass whose
|
|
||||||
* characteristic predicate is a unique singleton string. For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isSanitizer`.
|
|
||||||
* // Optionally override `isSanitizerIn`.
|
|
||||||
* // Optionally override `isSanitizerOut`.
|
|
||||||
* // Optionally override `isSanitizerGuard`.
|
|
||||||
* // Optionally override `isAdditionalTaintStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
|
||||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
|
||||||
* overridden predicates that define sources, sinks, or additional steps.
|
|
||||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
|
||||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
|
||||||
this.isSanitizer(node) or
|
|
||||||
defaultTaintSanitizer(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizer(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
this.isAdditionalTaintStep(node1, node2) or
|
|
||||||
defaultAdditionalTaintStep(node1, node2, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
|
||||||
(
|
|
||||||
this.isSink(node) or
|
|
||||||
this.isSink(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _, _, _)
|
|
||||||
) and
|
|
||||||
defaultImplicitTaintRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
|
||||||
|
|
||||||
module Private {
|
|
||||||
import semmle.code.cpp.dataflow.DataFlow2::DataFlow2 as DataFlow
|
|
||||||
}
|
|
||||||
@@ -29,5 +29,5 @@ module DataFlow {
|
|||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||||
private import codeql.dataflow.DataFlow
|
private import codeql.dataflow.DataFlow
|
||||||
import DataFlowMake<Location, CppDataFlow>
|
import DataFlowMake<Location, CppDataFlow>
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
import Public
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
module DataFlow2 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
module DataFlow3 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) data flow analyses.
|
|
||||||
*/
|
|
||||||
module DataFlow4 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4
|
|
||||||
}
|
|
||||||
@@ -16,18 +16,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.dataflow.new.DataFlow
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
import semmle.code.cpp.dataflow.new.DataFlow2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides classes for performing local (intra-procedural) and
|
* Provides classes for performing local (intra-procedural) and
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
*/
|
*/
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||||
private import codeql.dataflow.TaintTracking
|
private import codeql.dataflow.TaintTracking
|
||||||
private import semmle.code.cpp.Location
|
private import semmle.code.cpp.Location
|
||||||
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
|
||||||
* module. Use this class when data-flow configurations or taint-tracking
|
|
||||||
* configurations must depend on each other. Two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
|
||||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
|
||||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.new.TaintTracking` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
|
||||||
*/
|
|
||||||
module TaintTracking2 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
|
||||||
* module. Use this class when data-flow configurations or taint-tracking
|
|
||||||
* configurations must depend on each other. Two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
|
||||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
|
||||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.dataflow.new.TaintTracking` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides classes for performing local (intra-procedural) and
|
|
||||||
* global (inter-procedural) taint-tracking analyses.
|
|
||||||
*/
|
|
||||||
module TaintTracking3 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl
|
|
||||||
}
|
|
||||||
@@ -25,5 +25,5 @@ module DataFlow {
|
|||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||||
private import codeql.dataflow.DataFlow
|
private import codeql.dataflow.DataFlow
|
||||||
import DataFlowMake<Location, CppDataFlow>
|
import DataFlowMake<Location, CppDataFlow>
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
import Public
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
module DataFlow2 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
module DataFlow3 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
|
||||||
* this class when data-flow configurations must depend on each other. Two
|
|
||||||
* classes extending `DataFlow::Configuration` should never depend on each
|
|
||||||
* other, but one of them should instead depend on a
|
|
||||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
|
||||||
* `DataFlow4::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
module DataFlow4 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4
|
|
||||||
}
|
|
||||||
@@ -16,13 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
|
||||||
|
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||||
private import codeql.dataflow.TaintTracking
|
private import codeql.dataflow.TaintTracking
|
||||||
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
|
||||||
* module. Use this class when data-flow configurations or taint-tracking
|
|
||||||
* configurations must depend on each other. Two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
|
||||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
|
||||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
|
||||||
*/
|
|
||||||
module TaintTracking2 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
|
||||||
* module. Use this class when data-flow configurations or taint-tracking
|
|
||||||
* configurations must depend on each other. Two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
|
||||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
|
||||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
|
||||||
*
|
|
||||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
|
||||||
*/
|
|
||||||
module TaintTracking3 {
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl
|
|
||||||
}
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
|
||||||
* flow library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import DataFlowImplCommon
|
|
||||||
private import DataFlowImplSpecific::Private
|
|
||||||
import DataFlowImplSpecific::Public
|
|
||||||
private import DataFlowImpl
|
|
||||||
import DataFlowImplCommonPublic
|
|
||||||
deprecated import FlowStateString
|
|
||||||
private import codeql.util.Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural data flow analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the global data flow library must define its own unique extension
|
|
||||||
* of this abstract class. To create a configuration, extend this class with
|
|
||||||
* a subclass whose characteristic predicate is a unique singleton string.
|
|
||||||
* For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isBarrier`.
|
|
||||||
* // Optionally override `isAdditionalFlowStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
|
||||||
* the edges are those data-flow steps that preserve the value of the node
|
|
||||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
|
||||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
|
||||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
|
||||||
* and/or out-going edges from those nodes, respectively.
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but two classes extending
|
|
||||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
|
||||||
* should instead depend on a `DataFlow2::Configuration`, a
|
|
||||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends string {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant data flow source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSource(Node source, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
|
||||||
*/
|
|
||||||
predicate isSink(Node sink, FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited. This completely removes
|
|
||||||
* `node` from the data flow graph.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow through `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isBarrier(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow into `node` is prohibited. */
|
|
||||||
predicate isBarrierIn(Node node) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
|
||||||
predicate isBarrierOut(Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
|
||||||
* taken at `node`.
|
|
||||||
*/
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
|
||||||
* This can be overridden to a smaller value to improve performance (a
|
|
||||||
* value of 0 disables field flow), or a larger value to get more results.
|
|
||||||
*/
|
|
||||||
int fieldFlowBranchLimit() { result = 2 }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a data flow configuration feature to add restrictions to the set of
|
|
||||||
* valid flow paths.
|
|
||||||
*
|
|
||||||
* - `FeatureHasSourceCallContext`:
|
|
||||||
* Assume that sources have some existing call context to disallow
|
|
||||||
* conflicting return-flow directly following the source.
|
|
||||||
* - `FeatureHasSinkCallContext`:
|
|
||||||
* Assume that sinks have some existing call context to disallow
|
|
||||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
|
||||||
* - `FeatureEqualSourceSinkCallContext`:
|
|
||||||
* Implies both of the above and additionally ensures that the entire flow
|
|
||||||
* path preserves the call context.
|
|
||||||
*
|
|
||||||
* These features are generally not relevant for typical end-to-end data flow
|
|
||||||
* queries, but should only be used for constructing paths that need to
|
|
||||||
* somehow be pluggable in another path context.
|
|
||||||
*/
|
|
||||||
FlowFeature getAFeature() { none() }
|
|
||||||
|
|
||||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
|
||||||
|
|
||||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
|
||||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
|
||||||
*
|
|
||||||
* The corresponding paths are generated from the end-points and the graph
|
|
||||||
* included in the module `PathGraph`.
|
|
||||||
*/
|
|
||||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data may flow from some source to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if hidden nodes should be included in the data flow graph.
|
|
||||||
*
|
|
||||||
* This feature should only be used for debugging or when the data flow graph
|
|
||||||
* is not visualized (for example in a `path-problem` query).
|
|
||||||
*/
|
|
||||||
predicate includeHiddenNodes() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exists to prevent mutual recursion between the user-overridden
|
|
||||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
|
||||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
|
||||||
* it should be replaced by using more than one copy of the data flow library.
|
|
||||||
*/
|
|
||||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
ConfigurationRecursionPrevention() { any() }
|
|
||||||
|
|
||||||
override predicate hasFlow(Node source, Node sink) {
|
|
||||||
strictcount(Node n | this.isSource(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSource(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n | this.isSink(n, _)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
|
||||||
or
|
|
||||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
|
||||||
or
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private FlowState relevantState(Configuration config) {
|
|
||||||
config.isSource(_, result) or
|
|
||||||
config.isSink(_, result) or
|
|
||||||
config.isBarrier(_, result) or
|
|
||||||
config.isAdditionalFlowStep(_, result, _, _) or
|
|
||||||
config.isAdditionalFlowStep(_, _, _, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private newtype TConfigState =
|
|
||||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
|
||||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
|
||||||
|
|
||||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
|
||||||
|
|
||||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
|
||||||
|
|
||||||
deprecated private module Config implements FullStateConfigSig {
|
|
||||||
class FlowState = TConfigState;
|
|
||||||
|
|
||||||
predicate isSource(Node source, FlowState state) {
|
|
||||||
getConfig(state).isSource(source, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isSink(Node sink) { none() }
|
|
||||||
|
|
||||||
predicate isSink(Node sink, FlowState state) {
|
|
||||||
getConfig(state).isSink(sink, getState(state))
|
|
||||||
or
|
|
||||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrier(Node node) { none() }
|
|
||||||
|
|
||||||
predicate isBarrier(Node node, FlowState state) {
|
|
||||||
getConfig(state).isBarrier(node, getState(state)) or
|
|
||||||
getConfig(state).isBarrier(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
|
||||||
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
|
||||||
singleConfiguration() and
|
|
||||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
|
||||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
|
||||||
) {
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
|
||||||
getConfig(state2) = getConfig(state1) and
|
|
||||||
model = ""
|
|
||||||
or
|
|
||||||
not singleConfiguration() and
|
|
||||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
|
||||||
state2 = state1 and
|
|
||||||
model = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
|
||||||
any(Configuration config).allowImplicitRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate neverSkip(Node node) { none() }
|
|
||||||
|
|
||||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
|
||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
|
||||||
|
|
||||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
|
||||||
|
|
||||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
|
||||||
|
|
||||||
predicate observeDiffInformedIncrementalMode() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private import Impl<Config> as I
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
|
||||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
|
||||||
*/
|
|
||||||
deprecated class PathNode instanceof I::PathNode {
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
final string toString() { result = super.toString() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a textual representation of this element, including a textual
|
|
||||||
* representation of the call context.
|
|
||||||
*/
|
|
||||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element is at the specified location.
|
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
|
||||||
* For more information, see
|
|
||||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
||||||
*/
|
|
||||||
final predicate hasLocationInfo(
|
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
||||||
) {
|
|
||||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the underlying `Node`. */
|
|
||||||
final Node getNode() { result = super.getNode() }
|
|
||||||
|
|
||||||
/** Gets the `FlowState` of this node. */
|
|
||||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets the associated configuration. */
|
|
||||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
|
||||||
|
|
||||||
/** Gets a successor of this node, if any. */
|
|
||||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
|
||||||
|
|
||||||
/** Holds if this node is a source. */
|
|
||||||
final predicate isSource() { super.isSource() }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of source nodes. */
|
|
||||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
|
||||||
|
|
||||||
/** Holds if this node is a grouping of sink nodes. */
|
|
||||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated module PathGraph = I::PathGraph;
|
|
||||||
|
|
||||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
|
||||||
exists(PathNode source0, PathNode sink0 |
|
|
||||||
hasFlowPath(source0, sink0, config) and
|
|
||||||
source0.getNode() = source and
|
|
||||||
sink0.getNode() = sink
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
|
||||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
|
||||||
|
|
||||||
deprecated predicate flowsTo = hasFlow/3;
|
|
||||||
@@ -545,7 +545,7 @@ module ProductFlow {
|
|||||||
private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
||||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||||
exists(ReturnKindExt returnKind |
|
exists(ReturnKindExt returnKind |
|
||||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
succ1.getNode() = getAnOutNodeExt(call, returnKind) and
|
||||||
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
|
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -573,7 +573,7 @@ module ProductFlow {
|
|||||||
private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
||||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||||
exists(ReturnKindExt returnKind |
|
exists(ReturnKindExt returnKind |
|
||||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
succ2.getNode() = getAnOutNodeExt(call, returnKind) and
|
||||||
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
|
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides an implementation of global (interprocedural) taint tracking.
|
|
||||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
|
||||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
|
||||||
* exposed through the `Configuration` class. For some languages, this file
|
|
||||||
* exists in several identical copies, allowing queries to use multiple
|
|
||||||
* `Configuration` classes that depend on each other without introducing
|
|
||||||
* mutual recursion among those configurations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TaintTrackingParameter::Public
|
|
||||||
private import TaintTrackingParameter::Private
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural taint tracking analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the taint tracking library must define its own unique extension of
|
|
||||||
* this abstract class.
|
|
||||||
*
|
|
||||||
* A taint-tracking configuration is a special data flow configuration
|
|
||||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
|
||||||
* necessarily preserve values but are still relevant from a taint tracking
|
|
||||||
* perspective. (For example, string concatenation, where one of the operands
|
|
||||||
* is tainted.)
|
|
||||||
*
|
|
||||||
* To create a configuration, extend this class with a subclass whose
|
|
||||||
* characteristic predicate is a unique singleton string. For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isSanitizer`.
|
|
||||||
* // Optionally override `isSanitizerIn`.
|
|
||||||
* // Optionally override `isSanitizerOut`.
|
|
||||||
* // Optionally override `isSanitizerGuard`.
|
|
||||||
* // Optionally override `isAdditionalTaintStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
|
||||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
|
||||||
* overridden predicates that define sources, sinks, or additional steps.
|
|
||||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
|
||||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
|
||||||
this.isSanitizer(node) or
|
|
||||||
defaultTaintSanitizer(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizer(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
this.isAdditionalTaintStep(node1, node2) or
|
|
||||||
defaultAdditionalTaintStep(node1, node2, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
|
||||||
(
|
|
||||||
this.isSink(node) or
|
|
||||||
this.isSink(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _, _, _)
|
|
||||||
) and
|
|
||||||
defaultImplicitTaintRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
|
||||||
|
|
||||||
module Private {
|
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides an implementation of global (interprocedural) taint tracking.
|
|
||||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
|
||||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
|
||||||
* exposed through the `Configuration` class. For some languages, this file
|
|
||||||
* exists in several identical copies, allowing queries to use multiple
|
|
||||||
* `Configuration` classes that depend on each other without introducing
|
|
||||||
* mutual recursion among those configurations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TaintTrackingParameter::Public
|
|
||||||
private import TaintTrackingParameter::Private
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural taint tracking analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the taint tracking library must define its own unique extension of
|
|
||||||
* this abstract class.
|
|
||||||
*
|
|
||||||
* A taint-tracking configuration is a special data flow configuration
|
|
||||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
|
||||||
* necessarily preserve values but are still relevant from a taint tracking
|
|
||||||
* perspective. (For example, string concatenation, where one of the operands
|
|
||||||
* is tainted.)
|
|
||||||
*
|
|
||||||
* To create a configuration, extend this class with a subclass whose
|
|
||||||
* characteristic predicate is a unique singleton string. For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isSanitizer`.
|
|
||||||
* // Optionally override `isSanitizerIn`.
|
|
||||||
* // Optionally override `isSanitizerOut`.
|
|
||||||
* // Optionally override `isSanitizerGuard`.
|
|
||||||
* // Optionally override `isAdditionalTaintStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
|
||||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
|
||||||
* overridden predicates that define sources, sinks, or additional steps.
|
|
||||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
|
||||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
|
||||||
this.isSanitizer(node) or
|
|
||||||
defaultTaintSanitizer(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizer(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
this.isAdditionalTaintStep(node1, node2) or
|
|
||||||
defaultAdditionalTaintStep(node1, node2, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
|
||||||
(
|
|
||||||
this.isSink(node) or
|
|
||||||
this.isSink(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _, _, _)
|
|
||||||
) and
|
|
||||||
defaultImplicitTaintRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
|
||||||
|
|
||||||
module Private {
|
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow2::DataFlow2 as DataFlow
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* Provides an implementation of global (interprocedural) taint tracking.
|
|
||||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
|
||||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
|
||||||
* exposed through the `Configuration` class. For some languages, this file
|
|
||||||
* exists in several identical copies, allowing queries to use multiple
|
|
||||||
* `Configuration` classes that depend on each other without introducing
|
|
||||||
* mutual recursion among those configurations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TaintTrackingParameter::Public
|
|
||||||
private import TaintTrackingParameter::Private
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
|
||||||
*
|
|
||||||
* A configuration of interprocedural taint tracking analysis. This defines
|
|
||||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
|
||||||
* use of the taint tracking library must define its own unique extension of
|
|
||||||
* this abstract class.
|
|
||||||
*
|
|
||||||
* A taint-tracking configuration is a special data flow configuration
|
|
||||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
|
||||||
* necessarily preserve values but are still relevant from a taint tracking
|
|
||||||
* perspective. (For example, string concatenation, where one of the operands
|
|
||||||
* is tainted.)
|
|
||||||
*
|
|
||||||
* To create a configuration, extend this class with a subclass whose
|
|
||||||
* characteristic predicate is a unique singleton string. For example, write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Optionally override `isSanitizer`.
|
|
||||||
* // Optionally override `isSanitizerIn`.
|
|
||||||
* // Optionally override `isSanitizerOut`.
|
|
||||||
* // Optionally override `isSanitizerGuard`.
|
|
||||||
* // Optionally override `isAdditionalTaintStep`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some `source` and `sink`,
|
|
||||||
* write
|
|
||||||
*
|
|
||||||
* ```ql
|
|
||||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
|
||||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
|
||||||
* overridden predicates that define sources, sinks, or additional steps.
|
|
||||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
|
||||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
|
||||||
*/
|
|
||||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
|
||||||
bindingset[this]
|
|
||||||
Configuration() { any() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is a relevant taint source with the given initial
|
|
||||||
* `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
|
||||||
*
|
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
|
||||||
this.isSanitizer(node) or
|
|
||||||
defaultTaintSanitizer(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizer(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
this.isAdditionalTaintStep(node1, node2) or
|
|
||||||
defaultAdditionalTaintStep(node1, node2, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
|
||||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
|
||||||
*/
|
|
||||||
predicate isAdditionalTaintStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(
|
|
||||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
|
||||||
DataFlow::FlowState state2
|
|
||||||
) {
|
|
||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
|
||||||
(
|
|
||||||
this.isSink(node) or
|
|
||||||
this.isSink(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _) or
|
|
||||||
this.isAdditionalTaintStep(node, _, _, _)
|
|
||||||
) and
|
|
||||||
defaultImplicitTaintRead(node, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
|
||||||
*/
|
|
||||||
// overridden to provide taint-tracking specific qldoc
|
|
||||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
|
||||||
super.hasFlow(source, sink)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
|
||||||
|
|
||||||
module Private {
|
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow3::DataFlow3 as DataFlow
|
|
||||||
}
|
|
||||||
@@ -364,10 +364,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
|||||||
|
|
||||||
final override predicate mayThrowException() {
|
final override predicate mayThrowException() {
|
||||||
expr.getTarget().(ThrowingFunction).mayThrowException(_)
|
expr.getTarget().(ThrowingFunction).mayThrowException(_)
|
||||||
|
or
|
||||||
|
expr.getTarget() instanceof AlwaysSehThrowingFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate mustThrowException() {
|
final override predicate mustThrowException() {
|
||||||
expr.getTarget().(ThrowingFunction).mayThrowException(true)
|
expr.getTarget().(ThrowingFunction).mayThrowException(true)
|
||||||
|
or
|
||||||
|
expr.getTarget() instanceof AlwaysSehThrowingFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,3 +49,4 @@ private import implementations.PostgreSql
|
|||||||
private import implementations.System
|
private import implementations.System
|
||||||
private import implementations.StructuredExceptionHandling
|
private import implementations.StructuredExceptionHandling
|
||||||
private import implementations.ZMQ
|
private import implementations.ZMQ
|
||||||
|
private import implementations.Win32CommandExecution
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
|||||||
* `__builtin___memcpy_chk`.
|
* `__builtin___memcpy_chk`.
|
||||||
*/
|
*/
|
||||||
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
||||||
AliasFunction, NonThrowingFunction
|
AliasFunction, NonCppThrowingFunction
|
||||||
{
|
{
|
||||||
MemcpyFunction() {
|
MemcpyFunction() {
|
||||||
// memcpy(dest, src, num)
|
// memcpy(dest, src, num)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
|||||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||||
|
|
||||||
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||||
SideEffectFunction, NonThrowingFunction
|
SideEffectFunction, NonCppThrowingFunction
|
||||||
{
|
{
|
||||||
MemsetFunctionModel() {
|
MemsetFunctionModel() {
|
||||||
this.hasGlobalOrStdOrBslName("memset")
|
this.hasGlobalOrStdOrBslName("memset")
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
|||||||
*
|
*
|
||||||
* Note: The `throw` specifier was deprecated in C++11 and removed in C++17.
|
* Note: The `throw` specifier was deprecated in C++11 and removed in C++17.
|
||||||
*/
|
*/
|
||||||
class NoexceptFunction extends NonThrowingFunction {
|
class NoexceptFunction extends NonCppThrowingFunction {
|
||||||
NoexceptFunction() { this.isNoExcept() or this.isNoThrow() }
|
NoexceptFunction() { this.isNoExcept() or this.isNoThrow() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
|||||||
/**
|
/**
|
||||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||||
*/
|
*/
|
||||||
private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunction {
|
private class Printf extends FormattingFunction, AliasFunction, NonCppThrowingFunction {
|
||||||
Printf() {
|
Printf() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
(
|
(
|
||||||
@@ -37,7 +37,7 @@ private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunct
|
|||||||
/**
|
/**
|
||||||
* The standard functions `fprintf`, `fwprintf` and their glib variants.
|
* The standard functions `fprintf`, `fwprintf` and their glib variants.
|
||||||
*/
|
*/
|
||||||
private class Fprintf extends FormattingFunction, NonThrowingFunction {
|
private class Fprintf extends FormattingFunction, NonCppThrowingFunction {
|
||||||
Fprintf() {
|
Fprintf() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
(
|
(
|
||||||
@@ -55,7 +55,7 @@ private class Fprintf extends FormattingFunction, NonThrowingFunction {
|
|||||||
/**
|
/**
|
||||||
* The standard function `sprintf` and its Microsoft and glib variants.
|
* The standard function `sprintf` and its Microsoft and glib variants.
|
||||||
*/
|
*/
|
||||||
private class Sprintf extends FormattingFunction, NonThrowingFunction {
|
private class Sprintf extends FormattingFunction, NonCppThrowingFunction {
|
||||||
Sprintf() {
|
Sprintf() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
(
|
(
|
||||||
@@ -98,7 +98,9 @@ private class Sprintf extends FormattingFunction, NonThrowingFunction {
|
|||||||
/**
|
/**
|
||||||
* Implements `Snprintf`.
|
* Implements `Snprintf`.
|
||||||
*/
|
*/
|
||||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction, NonThrowingFunction {
|
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction,
|
||||||
|
NonCppThrowingFunction
|
||||||
|
{
|
||||||
SnprintfImpl() {
|
SnprintfImpl() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
(
|
(
|
||||||
@@ -205,7 +207,7 @@ private class StringCchPrintf extends FormattingFunction {
|
|||||||
/**
|
/**
|
||||||
* The standard function `syslog`.
|
* The standard function `syslog`.
|
||||||
*/
|
*/
|
||||||
private class Syslog extends FormattingFunction, NonThrowingFunction {
|
private class Syslog extends FormattingFunction, NonCppThrowingFunction {
|
||||||
Syslog() {
|
Syslog() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
this.hasGlobalName("syslog") and
|
this.hasGlobalName("syslog") and
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
|||||||
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||||
*/
|
*/
|
||||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction,
|
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction,
|
||||||
NonThrowingFunction
|
NonCppThrowingFunction
|
||||||
{
|
{
|
||||||
StrcatFunction() {
|
StrcatFunction() {
|
||||||
this.hasGlobalOrStdOrBslName([
|
this.hasGlobalOrStdOrBslName([
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
|||||||
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
|
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
|
||||||
*/
|
*/
|
||||||
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction,
|
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction,
|
||||||
NonThrowingFunction
|
NonCppThrowingFunction
|
||||||
{
|
{
|
||||||
StrcpyFunction() {
|
StrcpyFunction() {
|
||||||
this.hasGlobalOrStdOrBslName([
|
this.hasGlobalOrStdOrBslName([
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import semmle.code.cpp.models.interfaces.Throwing
|
import semmle.code.cpp.models.interfaces.Throwing
|
||||||
|
|
||||||
class WindowsDriverFunction extends ThrowingFunction {
|
class WindowsDriverExceptionAnnotation extends AlwaysSehThrowingFunction {
|
||||||
WindowsDriverFunction() {
|
WindowsDriverExceptionAnnotation() {
|
||||||
this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"])
|
this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"])
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate mayThrowException(boolean unconditional) { unconditional = true }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
private import semmle.code.cpp.models.interfaces.CommandExecution
|
||||||
|
|
||||||
|
/** The `ShellExecute` family of functions from Win32. */
|
||||||
|
class ShellExecute extends Function {
|
||||||
|
ShellExecute() { this.hasGlobalName("ShellExecute" + ["", "A", "W"]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ShellExecuteModel extends ShellExecute, CommandExecutionFunction {
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The `WinExec` function from Win32. */
|
||||||
|
class WinExec extends Function {
|
||||||
|
WinExec() { this.hasGlobalName("WinExec") }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WinExecModel extends WinExec, CommandExecutionFunction {
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The `CreateProcess` family of functions from Win32. */
|
||||||
|
class CreateProcess extends Function {
|
||||||
|
CreateProcess() { this.hasGlobalName("CreateProcess" + ["", "A", "W"]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CreateProcessModel extends CreateProcess, CommandExecutionFunction {
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The `CreateProcessAsUser` family of functions from Win32. */
|
||||||
|
class CreateProcessAsUser extends Function {
|
||||||
|
CreateProcessAsUser() { this.hasGlobalName("CreateProcessAsUser" + ["", "A", "W"]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CreateProcessAsUserModel extends CreateProcessAsUser, CommandExecutionFunction {
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The `CreateProcessWithLogonW` function from Win32. */
|
||||||
|
class CreateProcessWithLogonW extends Function {
|
||||||
|
CreateProcessWithLogonW() { this.hasGlobalName("CreateProcessWithLogonW") }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CreateProcessWithLogonModel extends CreateProcessWithLogonW, CommandExecutionFunction {
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(4) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The `CreateProcessWithTokenW` function from Win32. */
|
||||||
|
class CreateProcessWithTokenW extends Function {
|
||||||
|
CreateProcessWithTokenW() { this.hasGlobalName("CreateProcessWithTokenW") }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CreateProcessWithTokenWModel extends CreateProcessWithTokenW, CommandExecutionFunction
|
||||||
|
{
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) }
|
||||||
|
}
|
||||||
@@ -6,6 +6,15 @@ import semmle.code.cpp.Function
|
|||||||
import semmle.code.cpp.models.Models
|
import semmle.code.cpp.models.Models
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that is guaranteed to never throw.
|
* A function that is guaranteed to never throw a C++ exception
|
||||||
|
*
|
||||||
|
* The function may still raise a structured exception handling (SEH) exception.
|
||||||
*/
|
*/
|
||||||
abstract class NonThrowingFunction extends Function { }
|
abstract class NonCppThrowingFunction extends Function { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that is guaranteed to never throw.
|
||||||
|
*
|
||||||
|
* DEPRECATED: use `NonCppThrowingFunction` instead.
|
||||||
|
*/
|
||||||
|
deprecated class NonThrowingFunction = NonCppThrowingFunction;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import semmle.code.cpp.models.Models
|
|||||||
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that models the exceptional behavior of a function.
|
* A function that is known to raise an exception.
|
||||||
*/
|
*/
|
||||||
abstract class ThrowingFunction extends Function {
|
abstract class ThrowingFunction extends Function {
|
||||||
/**
|
/**
|
||||||
@@ -20,3 +20,8 @@ abstract class ThrowingFunction extends Function {
|
|||||||
*/
|
*/
|
||||||
abstract predicate mayThrowException(boolean unconditional);
|
abstract predicate mayThrowException(boolean unconditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that unconditionally raises a structured exception handling (SEH) exception.
|
||||||
|
*/
|
||||||
|
abstract class AlwaysSehThrowingFunction extends Function { }
|
||||||
|
|||||||
@@ -46,6 +46,22 @@ compilation_args(
|
|||||||
string arg : string ref
|
string arg : string ref
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally, record the build mode for each compilation.
|
||||||
|
*/
|
||||||
|
compilation_build_mode(
|
||||||
|
unique int id : @compilation ref,
|
||||||
|
int mode : int ref
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
case @compilation_build_mode.mode of
|
||||||
|
0 = @build_mode_none
|
||||||
|
| 1 = @build_mode_manual
|
||||||
|
| 2 = @build_mode_auto
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The source files that are compiled by a compiler invocation.
|
* The source files that are compiled by a compiler invocation.
|
||||||
* If `id` is for the compiler invocation
|
* If `id` is for the compiler invocation
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Implement compilation_build_mode/2
|
||||||
|
compatibility: backwards
|
||||||
@@ -1,18 +1,28 @@
|
|||||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
<qhelp>
|
<qhelp>
|
||||||
|
|
||||||
<overview>
|
<overview>
|
||||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check the argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||||
</overview>
|
</overview>
|
||||||
|
|
||||||
<recommendation>
|
<recommendation>
|
||||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the condition preceding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||||
</recommendation>
|
</recommendation>
|
||||||
|
|
||||||
<example>
|
<example>
|
||||||
<sample src = "GuardedFree.cpp" />
|
<sample src = "GuardedFree.cpp" />
|
||||||
|
|
||||||
|
<p>In this example, the condition checking the value of <code>foo</code> can be deleted.</p>
|
||||||
|
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
<references>
|
<references>
|
||||||
<li>
|
<li>
|
||||||
The Open Group Base Specifications Issue 7, 2018 Edition:
|
The Open Group Base Specifications Issue 7, 2018 Edition:
|
||||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
|
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>.
|
||||||
</li>
|
</li>
|
||||||
</references>
|
</references>
|
||||||
|
|
||||||
</qhelp>
|
</qhelp>
|
||||||
63
cpp/ql/src/Best Practices/GuardedFree.ql
Normal file
63
cpp/ql/src/Best Practices/GuardedFree.ql
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @name Guarded Free
|
||||||
|
* @description NULL-condition guards before function calls to the memory-deallocation
|
||||||
|
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
||||||
|
* @kind problem
|
||||||
|
* @problem.severity recommendation
|
||||||
|
* @precision very-high
|
||||||
|
* @id cpp/guarded-free
|
||||||
|
* @tags maintainability
|
||||||
|
* readability
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.controlflow.Guards
|
||||||
|
|
||||||
|
class FreeCall extends FunctionCall {
|
||||||
|
FreeCall() { this.getTarget().hasGlobalName("free") }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate blockContainsPreprocessorBranches(BasicBlock bb) {
|
||||||
|
exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc |
|
||||||
|
bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation()
|
||||||
|
|
|
||||||
|
bbLoc.getFile() = ppb.getFile() and
|
||||||
|
bbLoc.getStartLine() < ppbLoc.getStartLine() and
|
||||||
|
ppbLoc.getEndLine() < bbLoc.getEndLine()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `gc` ensures that `v` is non-zero when reaching `bb`, and `bb`
|
||||||
|
* contains a single statement which is `fc`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate interesting(GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb) {
|
||||||
|
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
||||||
|
fc.getArgument(0) = v.getAnAccess() and
|
||||||
|
bb = fc.getBasicBlock() and
|
||||||
|
(
|
||||||
|
// No block statement: if (x) free(x);
|
||||||
|
bb = fc.getEnclosingStmt()
|
||||||
|
or
|
||||||
|
// Block statement with a single nested statement: if (x) { free(x); }
|
||||||
|
strictcount(bb.(BlockStmt).getAStmt()) = 1
|
||||||
|
) and
|
||||||
|
not fc.isInMacroExpansion() and
|
||||||
|
not blockContainsPreprocessorBranches(bb) and
|
||||||
|
not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and
|
||||||
|
not exists(CommaExpr c | c.getAChild*() = fc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `gc` only guards a single block. */
|
||||||
|
bindingset[gc]
|
||||||
|
pragma[inline_late]
|
||||||
|
private predicate guardConditionGuardsUniqueBlock(GuardCondition gc) {
|
||||||
|
strictcount(BasicBlock bb | gc.ensuresEq(_, 0, bb, _)) = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
||||||
|
where
|
||||||
|
interesting(gc, fc, v, bb) and
|
||||||
|
guardConditionGuardsUniqueBlock(gc)
|
||||||
|
select gc, "unnecessary NULL check before call to $@", fc, "free"
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
## 1.3.0
|
||||||
|
|
||||||
|
### New Queries
|
||||||
|
|
||||||
|
* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331).
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared.
|
||||||
|
|
||||||
## 1.2.7
|
## 1.2.7
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<p>
|
<p>
|
||||||
This rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer).
|
This rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer).
|
||||||
Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything
|
Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything
|
||||||
from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave
|
from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manager to behave
|
||||||
erratically, to a possible security vulnerability.
|
erratically, to a possible security vulnerability.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -51,5 +51,7 @@ predicate tooFewArguments(FunctionCall fc, Function f) {
|
|||||||
hasDefiniteNumberOfParameters(fde)
|
hasDefiniteNumberOfParameters(fde)
|
||||||
|
|
|
|
||||||
fde.getNumberOfParameters() > fc.getNumberOfArguments()
|
fde.getNumberOfParameters() > fc.getNumberOfArguments()
|
||||||
)
|
) and
|
||||||
|
// Don't report on implicit function declarations, as these are likely extraction errors.
|
||||||
|
not f.getADeclarationEntry().isImplicit()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import semmle.code.cpp.security.Security
|
|||||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
|
||||||
import semmle.code.cpp.security.FlowSources
|
import semmle.code.cpp.security.FlowSources
|
||||||
import semmle.code.cpp.models.implementations.Strcat
|
import semmle.code.cpp.models.implementations.Strcat
|
||||||
import ExecTaint::PathGraph
|
import ExecTaint::PathGraph
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
|||||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||||
*/
|
*/
|
||||||
predicate functionMayThrow(Function f) {
|
predicate functionMayThrow(Function f) {
|
||||||
not f instanceof NonThrowingFunction and
|
not f instanceof NonCppThrowingFunction and
|
||||||
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock()))
|
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
cpp/ql/src/change-notes/released/1.3.0.md
Normal file
9
cpp/ql/src/change-notes/released/1.3.0.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## 1.3.0
|
||||||
|
|
||||||
|
### New Queries
|
||||||
|
|
||||||
|
* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331).
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 1.2.7
|
lastReleaseVersion: 1.3.0
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Guarded Free
|
|
||||||
* @description NULL-condition guards before function calls to the memory-deallocation
|
|
||||||
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
|
||||||
* @kind problem
|
|
||||||
* @problem.severity recommendation
|
|
||||||
* @precision very-high
|
|
||||||
* @id cpp/guarded-free
|
|
||||||
* @tags maintainability
|
|
||||||
* readability
|
|
||||||
* experimental
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
import semmle.code.cpp.controlflow.Guards
|
|
||||||
|
|
||||||
class FreeCall extends FunctionCall {
|
|
||||||
FreeCall() { this.getTarget().hasGlobalName("free") }
|
|
||||||
}
|
|
||||||
|
|
||||||
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
|
||||||
where
|
|
||||||
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
|
||||||
fc.getArgument(0) = v.getAnAccess() and
|
|
||||||
bb = fc.getEnclosingStmt()
|
|
||||||
select gc, "unnecessary NULL check before call to $@", fc, "free"
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 1.2.7
|
version: 1.3.1-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
| test.cpp:5:7:5:7 | x | unnecessary NULL check before call to $@ | test.cpp:6:5:6:8 | call to free | free |
|
|
||||||
| test.cpp:23:7:23:7 | x | unnecessary NULL check before call to $@ | test.cpp:26:5:26:8 | call to free | free |
|
|
||||||
| test.cpp:31:7:31:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
|
|
||||||
| test.cpp:31:7:31:24 | ... \|\| ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
|
|
||||||
| test.cpp:31:8:31:8 | x | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
|
|
||||||
| test.cpp:94:12:94:12 | x | unnecessary NULL check before call to $@ | test.cpp:94:3:94:13 | call to free | free |
|
|
||||||
| test.cpp:98:7:98:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free |
|
|
||||||
| test.cpp:98:8:98:8 | x | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free |
|
|
||||||
| test.cpp:106:7:106:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:107:5:107:8 | call to free | free |
|
|
||||||
| test.cpp:113:7:113:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:114:17:114:20 | call to free | free |
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
experimental/Best Practices/GuardedFree.ql
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
WARNING: module 'DataFlow' has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||||
failures
|
|
||||||
testFailures
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
testFailures
|
|
||||||
failures
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
failures
|
|
||||||
testFailures
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user