src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9325
8157eb19aba5
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
22 22
23 from Security.SecurityDefaults import SecurityDefaults 23 from Security.SecurityDefaults import SecurityDefaults
24 24
25 # This regex starts with a windows drive letter (eg C:) 25 # This regex starts with a windows drive letter (eg C:)
26 # or one of our path delimeter characters (/, \, .) 26 # or one of our path delimeter characters (/, \, .)
27 fullPathMatchRe = re.compile(r'^(?:[A-Za-z](?=\:)|[\\\/\.])') 27 fullPathMatchRe = re.compile(r"^(?:[A-Za-z](?=\:)|[\\\/\.])")
28 28
29 29
30 def getChecks(): 30 def getChecks():
31 """ 31 """
32 Public method to get a dictionary with checks handled by this module. 32 Public method to get a dictionary with checks handled by this module.
33 33
34 @return dictionary containing checker lists containing checker function and 34 @return dictionary containing checker lists containing checker function and
35 list of codes 35 list of codes
36 @rtype dict 36 @rtype dict
37 """ 37 """
38 return { 38 return {
48 48
49 49
50 def _evaluateShellCall(context): 50 def _evaluateShellCall(context):
51 """ 51 """
52 Function to determine the severity of a shell call. 52 Function to determine the severity of a shell call.
53 53
54 @param context context to be inspected 54 @param context context to be inspected
55 @type SecurityContext 55 @type SecurityContext
56 @return severity level (L, M or H) 56 @return severity level (L, M or H)
57 @rtype str 57 @rtype str
58 """ 58 """
65 65
66 66
67 def hasShell(context): 67 def hasShell(context):
68 """ 68 """
69 Function to check, if the node of the context contains the shell keyword. 69 Function to check, if the node of the context contains the shell keyword.
70 70
71 @param context context to be inspected 71 @param context context to be inspected
72 @type SecurityContext 72 @type SecurityContext
73 @return tuple containing a flag indicating the presence of the 'shell' 73 @return tuple containing a flag indicating the presence of the 'shell'
74 argument and flag indicating the value of the 'shell' argument 74 argument and flag indicating the value of the 'shell' argument
75 @rtype tuple of (bool, bool) 75 @rtype tuple of (bool, bool)
76 """ 76 """
77 keywords = context.node.keywords 77 keywords = context.node.keywords
78 result = False 78 result = False
79 shell = False 79 shell = False
80 if 'shell' in context.callKeywords: 80 if "shell" in context.callKeywords:
81 shell = True 81 shell = True
82 for key in keywords: 82 for key in keywords:
83 if key.arg == 'shell': 83 if key.arg == "shell":
84 val = key.value 84 val = key.value
85 if AstUtilities.isNumber(val): 85 if AstUtilities.isNumber(val):
86 result = bool(val.n) 86 result = bool(val.n)
87 elif isinstance(val, ast.List): 87 elif isinstance(val, ast.List):
88 result = bool(val.elts) 88 result = bool(val.elts)
89 elif isinstance(val, ast.Dict): 89 elif isinstance(val, ast.Dict):
90 result = bool(val.keys) 90 result = bool(val.keys)
91 elif isinstance(val, ast.Name) and val.id in ['False', 'None']: 91 elif isinstance(val, ast.Name) and val.id in ["False", "None"]:
92 result = False 92 result = False
93 elif AstUtilities.isNameConstant(val): 93 elif AstUtilities.isNameConstant(val):
94 result = val.value 94 result = val.value
95 else: 95 else:
96 result = True 96 result = True
97 97
98 return shell, result 98 return shell, result
99 99
100 100
101 def checkSubprocessPopenWithShell(reportError, context, config): 101 def checkSubprocessPopenWithShell(reportError, context, config):
102 """ 102 """
103 Function to check for use of popen with shell equals true. 103 Function to check for use of popen with shell equals true.
104 104
105 @param reportError function to be used to report errors 105 @param reportError function to be used to report errors
106 @type func 106 @type func
107 @param context security context object 107 @param context security context object
108 @type SecurityContext 108 @type SecurityContext
109 @param config dictionary with configuration data 109 @param config dictionary with configuration data
110 @type dict 110 @type dict
111 """ 111 """
112 functionNames = ( 112 functionNames = (
113 config["shell_injection_subprocess"] 113 config["shell_injection_subprocess"]
114 if config and "shell_injection_subprocess" in config else 114 if config and "shell_injection_subprocess" in config
115 SecurityDefaults["shell_injection_subprocess"] 115 else SecurityDefaults["shell_injection_subprocess"]
116 ) 116 )
117 117
118 if context.callFunctionNameQual in functionNames: 118 if context.callFunctionNameQual in functionNames:
119 shell, shellValue = hasShell(context) 119 shell, shellValue = hasShell(context)
120 if shell and shellValue and len(context.callArgs) > 0: 120 if shell and shellValue and len(context.callArgs) > 0:
121 sev = _evaluateShellCall(context) 121 sev = _evaluateShellCall(context)
122 if sev == "L": 122 if sev == "L":
123 reportError( 123 reportError(
124 context.getLinenoForCallArg('shell') - 1, 124 context.getLinenoForCallArg("shell") - 1,
125 context.getOffsetForCallArg('shell'), 125 context.getOffsetForCallArg("shell"),
126 "S602.L", 126 "S602.L",
127 sev, 127 sev,
128 "H", 128 "H",
129 ) 129 )
130 else: 130 else:
131 reportError( 131 reportError(
132 context.getLinenoForCallArg('shell') - 1, 132 context.getLinenoForCallArg("shell") - 1,
133 context.getOffsetForCallArg('shell'), 133 context.getOffsetForCallArg("shell"),
134 "S602.H", 134 "S602.H",
135 sev, 135 sev,
136 "H", 136 "H",
137 ) 137 )
138 138
139 139
140 def checkSubprocessPopenWithoutShell(reportError, context, config): 140 def checkSubprocessPopenWithoutShell(reportError, context, config):
141 """ 141 """
142 Function to check for use of popen without shell equals true. 142 Function to check for use of popen without shell equals true.
143 143
144 @param reportError function to be used to report errors 144 @param reportError function to be used to report errors
145 @type func 145 @type func
146 @param context security context object 146 @param context security context object
147 @type SecurityContext 147 @type SecurityContext
148 @param config dictionary with configuration data 148 @param config dictionary with configuration data
149 @type dict 149 @type dict
150 """ 150 """
151 functionNames = ( 151 functionNames = (
152 config["shell_injection_subprocess"] 152 config["shell_injection_subprocess"]
153 if config and "shell_injection_subprocess" in config else 153 if config and "shell_injection_subprocess" in config
154 SecurityDefaults["shell_injection_subprocess"] 154 else SecurityDefaults["shell_injection_subprocess"]
155 ) 155 )
156 156
157 if ( 157 if context.callFunctionNameQual in functionNames and not hasShell(context)[0]:
158 context.callFunctionNameQual in functionNames and
159 not hasShell(context)[0]
160 ):
161 reportError( 158 reportError(
162 context.node.lineno - 1, 159 context.node.lineno - 1,
163 context.node.col_offset, 160 context.node.col_offset,
164 "S603", 161 "S603",
165 "L", 162 "L",
168 165
169 166
170 def checkOtherFunctionWithShell(reportError, context, config): 167 def checkOtherFunctionWithShell(reportError, context, config):
171 """ 168 """
172 Function to check for any function with shell equals true. 169 Function to check for any function with shell equals true.
173 170
174 @param reportError function to be used to report errors 171 @param reportError function to be used to report errors
175 @type func 172 @type func
176 @param context security context object 173 @param context security context object
177 @type SecurityContext 174 @type SecurityContext
178 @param config dictionary with configuration data 175 @param config dictionary with configuration data
179 @type dict 176 @type dict
180 """ 177 """
181 functionNames = ( 178 functionNames = (
182 config["shell_injection_subprocess"] 179 config["shell_injection_subprocess"]
183 if config and "shell_injection_subprocess" in config else 180 if config and "shell_injection_subprocess" in config
184 SecurityDefaults["shell_injection_subprocess"] 181 else SecurityDefaults["shell_injection_subprocess"]
185 ) 182 )
186 183
187 if context.callFunctionNameQual not in functionNames: 184 if context.callFunctionNameQual not in functionNames:
188 shell, shellValue = hasShell(context) 185 shell, shellValue = hasShell(context)
189 if shell and shellValue: 186 if shell and shellValue:
190 reportError( 187 reportError(
191 context.getLinenoForCallArg('shell') - 1, 188 context.getLinenoForCallArg("shell") - 1,
192 context.getOffsetForCallArg('shell'), 189 context.getOffsetForCallArg("shell"),
193 "S604", 190 "S604",
194 "M", 191 "M",
195 "L", 192 "L",
196 ) 193 )
197 194
198 195
199 def checkStartProcessWithShell(reportError, context, config): 196 def checkStartProcessWithShell(reportError, context, config):
200 """ 197 """
201 Function to check for starting a process with a shell. 198 Function to check for starting a process with a shell.
202 199
203 @param reportError function to be used to report errors 200 @param reportError function to be used to report errors
204 @type func 201 @type func
205 @param context security context object 202 @param context security context object
206 @type SecurityContext 203 @type SecurityContext
207 @param config dictionary with configuration data 204 @param config dictionary with configuration data
208 @type dict 205 @type dict
209 """ 206 """
210 functionNames = ( 207 functionNames = (
211 config["shell_injection_shell"] 208 config["shell_injection_shell"]
212 if config and "shell_injection_shell" in config else 209 if config and "shell_injection_shell" in config
213 SecurityDefaults["shell_injection_shell"] 210 else SecurityDefaults["shell_injection_shell"]
214 ) 211 )
215 212
216 if ( 213 if context.callFunctionNameQual in functionNames and len(context.callArgs) > 0:
217 context.callFunctionNameQual in functionNames and
218 len(context.callArgs) > 0
219 ):
220 sev = _evaluateShellCall(context) 214 sev = _evaluateShellCall(context)
221 if sev == "L": 215 if sev == "L":
222 reportError( 216 reportError(
223 context.node.lineno - 1, 217 context.node.lineno - 1,
224 context.node.col_offset, 218 context.node.col_offset,
237 231
238 232
239 def checkStartProcessWithNoShell(reportError, context, config): 233 def checkStartProcessWithNoShell(reportError, context, config):
240 """ 234 """
241 Function to check for starting a process with no shell. 235 Function to check for starting a process with no shell.
242 236
243 @param reportError function to be used to report errors 237 @param reportError function to be used to report errors
244 @type func 238 @type func
245 @param context security context object 239 @param context security context object
246 @type SecurityContext 240 @type SecurityContext
247 @param config dictionary with configuration data 241 @param config dictionary with configuration data
248 @type dict 242 @type dict
249 """ 243 """
250 functionNames = ( 244 functionNames = (
251 config["shell_injection_noshell"] 245 config["shell_injection_noshell"]
252 if config and "shell_injection_noshell" in config else 246 if config and "shell_injection_noshell" in config
253 SecurityDefaults["shell_injection_noshell"] 247 else SecurityDefaults["shell_injection_noshell"]
254 ) 248 )
255 249
256 if context.callFunctionNameQual in functionNames: 250 if context.callFunctionNameQual in functionNames:
257 reportError( 251 reportError(
258 context.node.lineno - 1, 252 context.node.lineno - 1,
259 context.node.col_offset, 253 context.node.col_offset,
260 "S606", 254 "S606",
264 258
265 259
266 def checkStartProcessWithPartialPath(reportError, context, config): 260 def checkStartProcessWithPartialPath(reportError, context, config):
267 """ 261 """
268 Function to check for starting a process with no shell. 262 Function to check for starting a process with no shell.
269 263
270 @param reportError function to be used to report errors 264 @param reportError function to be used to report errors
271 @type func 265 @type func
272 @param context security context object 266 @param context security context object
273 @type SecurityContext 267 @type SecurityContext
274 @param config dictionary with configuration data 268 @param config dictionary with configuration data
275 @type dict 269 @type dict
276 """ 270 """
277 functionNames = ( 271 functionNames = (
278 config["shell_injection_subprocess"] 272 config["shell_injection_subprocess"]
279 if config and "shell_injection_subprocess" in config else 273 if config and "shell_injection_subprocess" in config
280 SecurityDefaults["shell_injection_subprocess"] 274 else SecurityDefaults["shell_injection_subprocess"]
281 ) 275 )
282 276
283 if config and "shell_injection_shell" in config: 277 if config and "shell_injection_shell" in config:
284 functionNames += config["shell_injection_shell"] 278 functionNames += config["shell_injection_shell"]
285 else: 279 else:
286 functionNames += SecurityDefaults["shell_injection_shell"] 280 functionNames += SecurityDefaults["shell_injection_shell"]
287 281
288 if config and "shell_injection_noshell" in config: 282 if config and "shell_injection_noshell" in config:
289 functionNames += config["shell_injection_noshell"] 283 functionNames += config["shell_injection_noshell"]
290 else: 284 else:
291 functionNames += SecurityDefaults["shell_injection_noshell"] 285 functionNames += SecurityDefaults["shell_injection_noshell"]
292 286
293 if ( 287 if len(context.callArgs) and context.callFunctionNameQual in functionNames:
294 len(context.callArgs) and
295 context.callFunctionNameQual in functionNames
296 ):
297 node = context.node.args[0] 288 node = context.node.args[0]
298 289
299 # some calls take an arg list, check the first part 290 # some calls take an arg list, check the first part
300 if isinstance(node, ast.List): 291 if isinstance(node, ast.List):
301 node = node.elts[0] 292 node = node.elts[0]
302 293
303 # make sure the param is a string literal and not a var name 294 # make sure the param is a string literal and not a var name
304 if ( 295 if AstUtilities.isString(node) and not fullPathMatchRe.match(node.s):
305 AstUtilities.isString(node) and
306 not fullPathMatchRe.match(node.s)
307 ):
308 reportError( 296 reportError(
309 context.node.lineno - 1, 297 context.node.lineno - 1,
310 context.node.col_offset, 298 context.node.col_offset,
311 "S607", 299 "S607",
312 "L", 300 "L",

eric ide

mercurial