Skip to content

Commit 32d52c0

Browse files
committed
Python: Allow any order for azure blob query
By only allowing the sink in the state where encryption v1 is used, we can handle the new case where the order of attribute assignment is flipped. However, we get a few too many paths because we can have multiple sources reaching the same sink... let's fix in next commit.
1 parent 480f171 commit 32d52c0

File tree

2 files changed

+79
-18
lines changed

2 files changed

+79
-18
lines changed

python/ql/src/experimental/Security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,20 @@ API::Node getBlobClient() {
8282

8383
API::Node anyClient() { result in [getBlobServiceClient(), getContainerClient(), getBlobClient()] }
8484

85-
module AzureBlobClientConfig implements DataFlow::ConfigSig {
86-
predicate isSource(DataFlow::Node node) {
87-
exists(DataFlow::AttrWrite attr |
88-
node = anyClient().getAValueReachableFromSource() and
89-
attr.accesses(node, ["key_encryption_key", "key_resolver_function"])
90-
)
85+
newtype TAzureFlowState =
86+
MkUsesV1Encryption() or
87+
MkUsesNoEncryption()
88+
89+
module AzureBlobClientConfig implements DataFlow::StateConfigSig {
90+
class FlowState = TAzureFlowState;
91+
92+
predicate isSource(DataFlow::Node node, FlowState state) {
93+
state = MkUsesNoEncryption() and
94+
node = anyClient().asSource()
9195
}
9296

93-
predicate isBarrier(DataFlow::Node node) {
97+
predicate isBarrier(DataFlow::Node node, FlowState state) {
98+
exists(state) and
9499
exists(DataFlow::AttrWrite attr |
95100
node = anyClient().getAValueReachableFromSource() and
96101
attr.accesses(node, "encryption_version") and
@@ -106,15 +111,28 @@ module AzureBlobClientConfig implements DataFlow::ConfigSig {
106111
)
107112
}
108113

109-
predicate isSink(DataFlow::Node node) {
114+
predicate isAdditionalFlowStep(
115+
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
116+
) {
117+
node1 = node2 and
118+
state1 = MkUsesNoEncryption() and
119+
state2 = MkUsesV1Encryption() and
120+
exists(DataFlow::AttrWrite attr |
121+
node1 = anyClient().getAValueReachableFromSource() and
122+
attr.accesses(node1, ["key_encryption_key", "key_resolver_function"])
123+
)
124+
}
125+
126+
predicate isSink(DataFlow::Node node, FlowState state) {
127+
state = MkUsesV1Encryption() and
110128
exists(DataFlow::MethodCallNode call |
111129
call = getBlobClient().getMember("upload_blob").getACall() and
112130
node = call.getObject()
113131
)
114132
}
115133
}
116134

117-
module AzureBlobClient = DataFlow::Global<AzureBlobClientConfig>;
135+
module AzureBlobClient = DataFlow::GlobalWithState<AzureBlobClientConfig>;
118136

119137
import AzureBlobClient::PathGraph
120138

Original file line numberDiff line numberDiff line change
@@ -1,32 +1,75 @@
11
edges
2+
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:7:19:7:21 | ControlFlowNode for BSC |
3+
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:35:19:35:21 | ControlFlowNode for BSC |
4+
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:66:19:66:21 | ControlFlowNode for BSC |
5+
| test.py:3:1:3:3 | GSSA Variable BSC | test.py:0:0:0:0 | ModuleVariableNode for test.BSC |
6+
| test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:3:1:3:3 | GSSA Variable BSC |
7+
| test.py:7:19:7:21 | ControlFlowNode for BSC | test.py:8:5:8:15 | ControlFlowNode for blob_client |
8+
| test.py:7:19:7:42 | ControlFlowNode for Attribute() | test.py:8:5:8:15 | ControlFlowNode for blob_client |
9+
| test.py:8:5:8:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client |
10+
| test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client |
211
| test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client |
12+
| test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:16:5:16:23 | ControlFlowNode for blob_service_client |
13+
| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client |
14+
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client |
315
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:21:9:21:19 | ControlFlowNode for blob_client |
16+
| test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:26:5:26:20 | ControlFlowNode for container_client |
17+
| test.py:26:5:26:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | ControlFlowNode for container_client |
18+
| test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | ControlFlowNode for container_client |
419
| test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:31:9:31:19 | ControlFlowNode for blob_client |
20+
| test.py:35:19:35:21 | ControlFlowNode for BSC | test.py:36:5:36:15 | ControlFlowNode for blob_client |
21+
| test.py:35:19:35:42 | ControlFlowNode for Attribute() | test.py:36:5:36:15 | ControlFlowNode for blob_client |
22+
| test.py:36:5:36:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client |
23+
| test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client |
524
| test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client |
6-
| test.py:60:5:60:15 | ControlFlowNode for blob_client | test.py:62:9:62:19 | ControlFlowNode for blob_client |
25+
| test.py:66:19:66:21 | ControlFlowNode for BSC | test.py:67:5:67:15 | ControlFlowNode for blob_client |
26+
| test.py:66:19:66:42 | ControlFlowNode for Attribute() | test.py:67:5:67:15 | ControlFlowNode for blob_client |
27+
| test.py:67:5:67:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | ControlFlowNode for blob_client |
28+
| test.py:68:5:68:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | ControlFlowNode for blob_client |
729
| test.py:68:5:68:15 | ControlFlowNode for blob_client | test.py:69:12:69:22 | ControlFlowNode for blob_client |
830
| test.py:69:12:69:22 | ControlFlowNode for blob_client | test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() |
931
| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | test.py:75:9:75:10 | ControlFlowNode for bc |
1032
nodes
33+
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | semmle.label | ModuleVariableNode for test.BSC |
34+
| test.py:3:1:3:3 | GSSA Variable BSC | semmle.label | GSSA Variable BSC |
35+
| test.py:3:7:3:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
36+
| test.py:7:19:7:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
37+
| test.py:7:19:7:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
38+
| test.py:8:5:8:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
39+
| test.py:9:5:9:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
1140
| test.py:9:5:9:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
1241
| test.py:11:9:11:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
42+
| test.py:15:27:15:71 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
43+
| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
44+
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
1345
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
1446
| test.py:21:9:21:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
47+
| test.py:25:24:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
48+
| test.py:26:5:26:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
49+
| test.py:27:5:27:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
1550
| test.py:27:5:27:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
1651
| test.py:31:9:31:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
52+
| test.py:35:19:35:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
53+
| test.py:35:19:35:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
54+
| test.py:36:5:36:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
55+
| test.py:37:5:37:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
1756
| test.py:37:5:37:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
1857
| test.py:43:9:43:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
19-
| test.py:60:5:60:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
20-
| test.py:62:9:62:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
58+
| test.py:66:19:66:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
59+
| test.py:66:19:66:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
60+
| test.py:67:5:67:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
61+
| test.py:68:5:68:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
2162
| test.py:68:5:68:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
2263
| test.py:69:12:69:22 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
2364
| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() |
2465
| test.py:75:9:75:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc |
2566
subpaths
2667
#select
27-
| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
28-
| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
29-
| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
30-
| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
31-
| test.py:62:9:62:19 | ControlFlowNode for blob_client | test.py:60:5:60:15 | ControlFlowNode for blob_client | test.py:62:9:62:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
32-
| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:68:5:68:15 | ControlFlowNode for blob_client | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |
68+
| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
69+
| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:7:19:7:42 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
70+
| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
71+
| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
72+
| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
73+
| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:35:19:35:42 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
74+
| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |
75+
| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:66:19:66:42 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |

0 commit comments

Comments
 (0)