@@ -1060,7 +1060,11 @@ private module StdlibPrivate {
1060
1060
private class OsSystemCall extends SystemCommandExecution:: Range , DataFlow:: CallCfgNode {
1061
1061
OsSystemCall ( ) { this = os ( ) .getMember ( "system" ) .getACall ( ) }
1062
1062
1063
- override DataFlow:: Node getCommand ( ) { result = this .getArg ( 0 ) }
1063
+ override DataFlow:: Node getCommand ( ) {
1064
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "command" ) ]
1065
+ }
1066
+
1067
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) { arg = this .getCommand ( ) }
1064
1068
}
1065
1069
1066
1070
/**
@@ -1071,7 +1075,7 @@ private module StdlibPrivate {
1071
1075
* Although deprecated since version 2.6, they still work in 2.7.
1072
1076
* See https://docs.python.org/2.7/library/os.html#os.popen2
1073
1077
*/
1074
- private class OsPopenCall extends SystemCommandExecution:: Range , DataFlow :: CallCfgNode {
1078
+ private class OsPopenCall extends SystemCommandExecution:: Range , API :: CallNode {
1075
1079
string name ;
1076
1080
1077
1081
OsPopenCall ( ) {
@@ -1085,6 +1089,8 @@ private module StdlibPrivate {
1085
1089
not name = "popen" and
1086
1090
result = this .getArgByName ( "cmd" )
1087
1091
}
1092
+
1093
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) { arg = this .getCommand ( ) }
1088
1094
}
1089
1095
1090
1096
/**
@@ -1104,6 +1110,10 @@ private module StdlibPrivate {
1104
1110
override DataFlow:: Node getCommand ( ) { result = this .getArg ( 0 ) }
1105
1111
1106
1112
override DataFlow:: Node getAPathArgument ( ) { result = this .getCommand ( ) }
1113
+
1114
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) {
1115
+ none ( ) // this is a safe API.
1116
+ }
1107
1117
}
1108
1118
1109
1119
/**
@@ -1131,6 +1141,10 @@ private module StdlibPrivate {
1131
1141
}
1132
1142
1133
1143
override DataFlow:: Node getAPathArgument ( ) { result = this .getCommand ( ) }
1144
+
1145
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) {
1146
+ none ( ) // this is a safe API.
1147
+ }
1134
1148
}
1135
1149
1136
1150
/**
@@ -1145,6 +1159,10 @@ private module StdlibPrivate {
1145
1159
override DataFlow:: Node getCommand ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "path" ) ] }
1146
1160
1147
1161
override DataFlow:: Node getAPathArgument ( ) { result = this .getCommand ( ) }
1162
+
1163
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) {
1164
+ none ( ) // this is a safe API.
1165
+ }
1148
1166
}
1149
1167
1150
1168
/** An additional taint step for calls to `os.path.join` */
@@ -1170,7 +1188,7 @@ private module StdlibPrivate {
1170
1188
* See https://docs.python.org/3.8/library/subprocess.html#subprocess.Popen
1171
1189
* ref: https://docs.python.org/3/library/subprocess.html#legacy-shell-invocation-functions
1172
1190
*/
1173
- private class SubprocessPopenCall extends SystemCommandExecution:: Range , DataFlow :: CallCfgNode {
1191
+ private class SubprocessPopenCall extends SystemCommandExecution:: Range , API :: CallNode {
1174
1192
SubprocessPopenCall ( ) {
1175
1193
exists ( string name |
1176
1194
name in [
@@ -1180,43 +1198,33 @@ private module StdlibPrivate {
1180
1198
)
1181
1199
}
1182
1200
1183
- /** Gets the ControlFlowNode for the `args` argument, if any. */
1184
- private DataFlow :: Node get_args_arg ( ) { result in [ this .getArg ( 0 ) , this . getArgByName ( "args" ) ] }
1201
+ /** Gets the API-node for the `args` argument, if any. */
1202
+ private API :: Node get_args_arg ( ) { result = this .getParameter ( 0 , "args" ) }
1185
1203
1186
- /** Gets the ControlFlowNode for the `shell` argument, if any. */
1187
- private DataFlow:: Node get_shell_arg ( ) {
1188
- result in [ this .getArg ( 8 ) , this .getArgByName ( "shell" ) ]
1189
- }
1204
+ /** Gets the API-node for the `shell` argument, if any. */
1205
+ private API:: Node get_shell_arg ( ) { result = this .getParameter ( 8 , "shell" ) }
1190
1206
1191
1207
private boolean get_shell_arg_value ( ) {
1192
1208
not exists ( this .get_shell_arg ( ) ) and
1193
1209
result = false
1194
1210
or
1195
- exists ( DataFlow:: Node shell_arg | shell_arg = this .get_shell_arg ( ) |
1196
- result = shell_arg .asCfgNode ( ) .getNode ( ) .( ImmutableLiteral ) .booleanValue ( )
1197
- or
1198
- // TODO: Track the "shell" argument to determine possible values
1199
- not shell_arg .asCfgNode ( ) .getNode ( ) instanceof ImmutableLiteral and
1200
- (
1201
- result = true
1202
- or
1203
- result = false
1204
- )
1205
- )
1211
+ result =
1212
+ this .get_shell_arg ( ) .getAValueReachingSink ( ) .asExpr ( ) .( ImmutableLiteral ) .booleanValue ( )
1213
+ or
1214
+ not this .get_shell_arg ( ) .getAValueReachingSink ( ) .asExpr ( ) instanceof ImmutableLiteral and
1215
+ result = false // defaults to `False`
1206
1216
}
1207
1217
1208
- /** Gets the ControlFlowNode for the `executable` argument, if any. */
1209
- private DataFlow:: Node get_executable_arg ( ) {
1210
- result in [ this .getArg ( 2 ) , this .getArgByName ( "executable" ) ]
1211
- }
1218
+ /** Gets the API-node for the `executable` argument, if any. */
1219
+ private API:: Node get_executable_arg ( ) { result = this .getParameter ( 2 , "executable" ) }
1212
1220
1213
1221
override DataFlow:: Node getCommand ( ) {
1214
1222
// TODO: Track arguments ("args" and "shell")
1215
1223
// TODO: Handle using `args=["sh", "-c", <user-input>]`
1216
- result = this .get_executable_arg ( )
1224
+ result = this .get_executable_arg ( ) . asSink ( )
1217
1225
or
1218
1226
exists ( DataFlow:: Node arg_args , boolean shell |
1219
- arg_args = this .get_args_arg ( ) and
1227
+ arg_args = this .get_args_arg ( ) . asSink ( ) and
1220
1228
shell = this .get_shell_arg_value ( )
1221
1229
|
1222
1230
// When "executable" argument is set, and "shell" argument is `False`, the
@@ -1242,6 +1250,11 @@ private module StdlibPrivate {
1242
1250
)
1243
1251
)
1244
1252
}
1253
+
1254
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) {
1255
+ arg = [ this .get_executable_arg ( ) , this .get_args_arg ( ) ] .asSink ( ) and
1256
+ this .get_shell_arg_value ( ) = true
1257
+ }
1245
1258
}
1246
1259
1247
1260
// ---------------------------------------------------------------------------
@@ -1389,6 +1402,8 @@ private module StdlibPrivate {
1389
1402
}
1390
1403
1391
1404
override DataFlow:: Node getCommand ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "cmd" ) ] }
1405
+
1406
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) { arg = this .getCommand ( ) }
1392
1407
}
1393
1408
1394
1409
// ---------------------------------------------------------------------------
@@ -1405,6 +1420,8 @@ private module StdlibPrivate {
1405
1420
PlatformPopenCall ( ) { this = platform ( ) .getMember ( "popen" ) .getACall ( ) }
1406
1421
1407
1422
override DataFlow:: Node getCommand ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "cmd" ) ] }
1423
+
1424
+ override predicate isShellInterpreted ( DataFlow:: Node arg ) { arg = this .getCommand ( ) }
1408
1425
}
1409
1426
1410
1427
// ---------------------------------------------------------------------------
0 commit comments