11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 */
17
18 /* Does a search for Dan Rosenberg style info leaks */
19
20 /* fixme: struct includes a struct with a hole in it */
21 /* function is called that clears the struct */
22
23 #include "scope.h"
24 #include "smatch.h"
25 #include "smatch_function_hashtable.h"
26 #include "smatch_slist.h"
27 #include "smatch_extra.h"
28
29 static int my_whole_id;
30 static int my_member_id;
31
32 STATE(cleared);
33
34 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
35 {
36 struct symbol *type;
37
38 type = get_real_base_type(sym);
39 if (!type || type->type != SYM_STRUCT)
40 return;
41
42 set_state(my_member_id, name, sym, state);
43 }
44
45 static void print_holey_warning(struct expression *data, const char *member)
46 {
47 char *name;
48
49 name = expr_to_str(data);
50 if (member) {
107 struct symbol *type;
108 type = get_type(expr);
109 if (!type || type->type != SYM_STRUCT)
110 return 0;
111
112 return check_struct(expr, type);
113 }
114
115 static int has_global_scope(struct expression *expr)
116 {
117 struct symbol *sym;
118
119 if (expr->type != EXPR_SYMBOL)
120 return FALSE;
121 sym = expr->symbol;
122 if (!sym)
123 return FALSE;
124 return toplevel(sym->scope);
125 }
126
127 static int was_initialized(struct expression *expr)
128 {
129 struct symbol *sym;
130 char *name;
131
132 name = expr_to_var_sym(expr, &sym);
133 if (!name)
134 return 0;
135 if (sym->initializer)
136 return 1;
137 return 0;
138 }
139
140 static void match_clear(const char *fn, struct expression *expr, void *_arg_no)
141 {
142 struct expression *ptr;
143 int arg_no = PTR_INT(_arg_no);
144
145 ptr = get_argument_from_call_expr(expr->args, arg_no);
146 if (!ptr)
147 return;
148 ptr = strip_expr(ptr);
149 if (ptr->type != EXPR_PREOP || ptr->op != '&')
150 return;
151 ptr = strip_expr(ptr->unop);
152 set_state_expr(my_whole_id, ptr, &cleared);
153 }
154
155 static int was_memset(struct expression *expr)
156 {
157 if (get_state_expr(my_whole_id, expr) == &cleared)
158 return 1;
159 return 0;
241 goto out;
242 }
243 } END_FOR_EACH_PTR(tmp);
244 out:
245 free_string(name);
246 return printed;
247 }
248
249 static void check_was_initialized(struct expression *data)
250 {
251 data = strip_expr(data);
252 if (!data)
253 return;
254 if (data->type == EXPR_PREOP && data->op == '&')
255 data = strip_expr(data->unop);
256 if (data->type != EXPR_SYMBOL)
257 return;
258
259 if (has_global_scope(data))
260 return;
261 if (was_initialized(data))
262 return;
263 if (was_memset(data))
264 return;
265 if (warn_on_holey_struct(data))
266 return;
267 check_members_initialized(data);
268 }
269
270 static void match_copy_to_user(const char *fn, struct expression *expr, void *_arg)
271 {
272 int arg = PTR_INT(_arg);
273 struct expression *data;
274
275 data = get_argument_from_call_expr(expr->args, arg);
276 data = strip_expr(data);
277 if (!data)
278 return;
279 if (data->type != EXPR_PREOP || data->op != '&')
280 return;
281 check_was_initialized(data);
282 }
283
284 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
285 {
286 while (expr->type == EXPR_ASSIGNMENT)
287 expr = strip_expr(expr->right);
288 if (expr->type != EXPR_CALL)
289 return;
290
291 match_clear(NULL, expr, INT_PTR(param));
292 }
293
294 static void match_assign(struct expression *expr)
295 {
296 struct symbol *type;
297
298 type = get_type(expr->left);
299 if (!type || type->type != SYM_STRUCT)
300 return;
301 set_state_expr(my_whole_id, expr->left, &cleared);
302 }
303
304 static void register_clears_argument(void)
305 {
306 struct token *token;
307 const char *func;
308 int arg;
309
310 token = get_tokens_file("kernel.clears_argument");
311 if (!token)
312 return;
313 if (token_type(token) != TOKEN_STREAMBEGIN)
314 return;
315 token = token->next;
316 while (token_type(token) != TOKEN_STREAMEND) {
317 if (token_type(token) != TOKEN_IDENT)
318 return;
319 func = show_ident(token->ident);
320 token = token->next;
321 if (token_type(token) != TOKEN_NUMBER)
322 return;
323 arg = atoi(token->number);
352 token = token->next;
353 }
354 clear_token_alloc();
355 }
356
357 void check_rosenberg(int id)
358 {
359 if (option_project != PROJ_KERNEL)
360 return;
361 my_whole_id = id;
362
363 add_function_hook("memset", &match_clear, INT_PTR(0));
364 add_function_hook("memcpy", &match_clear, INT_PTR(0));
365 add_function_hook("memzero", &match_clear, INT_PTR(0));
366 add_function_hook("__memset", &match_clear, INT_PTR(0));
367 add_function_hook("__memcpy", &match_clear, INT_PTR(0));
368 add_function_hook("__memzero", &match_clear, INT_PTR(0));
369 add_function_hook("__builtin_memset", &match_clear, INT_PTR(0));
370 add_function_hook("__builtin_memcpy", &match_clear, INT_PTR(0));
371
372 add_hook(&match_assign, ASSIGNMENT_HOOK);
373 register_clears_argument();
374 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
375
376 register_copy_funcs_from_file();
377 }
378
379 void check_rosenberg2(int id)
380 {
381 if (option_project != PROJ_KERNEL)
382 return;
383
384 my_member_id = id;
385 set_dynamic_states(my_member_id);
386 add_extra_mod_hook(&extra_mod_hook);
387 }
388
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 */
17
18 /* Does a search for Dan Rosenberg style info leaks */
19
20 /* fixme: struct includes a struct with a hole in it */
21 /* function is called that clears the struct */
22
23 #include "scope.h"
24 #include "smatch.h"
25 #include "smatch_function_hashtable.h"
26 #include "smatch_slist.h"
27 #include "smatch_extra.h"
28
29 static int my_whole_id;
30 static int my_member_id;
31 static int skb_put_id;
32
33 STATE(cleared);
34
35 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
36 {
37 struct symbol *type;
38
39 type = get_real_base_type(sym);
40 if (!type || type->type != SYM_STRUCT)
41 return;
42
43 set_state(my_member_id, name, sym, state);
44 }
45
46 static void print_holey_warning(struct expression *data, const char *member)
47 {
48 char *name;
49
50 name = expr_to_str(data);
51 if (member) {
108 struct symbol *type;
109 type = get_type(expr);
110 if (!type || type->type != SYM_STRUCT)
111 return 0;
112
113 return check_struct(expr, type);
114 }
115
116 static int has_global_scope(struct expression *expr)
117 {
118 struct symbol *sym;
119
120 if (expr->type != EXPR_SYMBOL)
121 return FALSE;
122 sym = expr->symbol;
123 if (!sym)
124 return FALSE;
125 return toplevel(sym->scope);
126 }
127
128 static void match_clear(const char *fn, struct expression *expr, void *_arg_no)
129 {
130 struct expression *ptr;
131 int arg_no = PTR_INT(_arg_no);
132
133 ptr = get_argument_from_call_expr(expr->args, arg_no);
134 if (!ptr)
135 return;
136 ptr = strip_expr(ptr);
137 if (ptr->type != EXPR_PREOP || ptr->op != '&')
138 return;
139 ptr = strip_expr(ptr->unop);
140 set_state_expr(my_whole_id, ptr, &cleared);
141 }
142
143 static int was_memset(struct expression *expr)
144 {
145 if (get_state_expr(my_whole_id, expr) == &cleared)
146 return 1;
147 return 0;
229 goto out;
230 }
231 } END_FOR_EACH_PTR(tmp);
232 out:
233 free_string(name);
234 return printed;
235 }
236
237 static void check_was_initialized(struct expression *data)
238 {
239 data = strip_expr(data);
240 if (!data)
241 return;
242 if (data->type == EXPR_PREOP && data->op == '&')
243 data = strip_expr(data->unop);
244 if (data->type != EXPR_SYMBOL)
245 return;
246
247 if (has_global_scope(data))
248 return;
249 if (was_memset(data))
250 return;
251 if (warn_on_holey_struct(data))
252 return;
253 check_members_initialized(data);
254 }
255
256 static void check_skb_put(struct expression *data)
257 {
258 data = strip_expr(data);
259 if (!data)
260 return;
261 if (data->type == EXPR_PREOP && data->op == '&')
262 data = strip_expr(data->unop);
263
264 if (was_memset(data))
265 return;
266 if (warn_on_holey_struct(data))
267 return;
268 check_members_initialized(data);
269 }
270
271 static void match_copy_to_user(const char *fn, struct expression *expr, void *_arg)
272 {
273 int arg = PTR_INT(_arg);
274 struct expression *data;
275
276 data = get_argument_from_call_expr(expr->args, arg);
277 data = strip_expr(data);
278 if (!data)
279 return;
280 if (data->type != EXPR_PREOP || data->op != '&')
281 return;
282 check_was_initialized(data);
283 }
284
285 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
286 {
287 while (expr->type == EXPR_ASSIGNMENT)
288 expr = strip_expr(expr->right);
289 if (expr->type != EXPR_CALL)
290 return;
291
292 match_clear(NULL, expr, INT_PTR(param));
293 }
294
295 static struct smatch_state *alloc_expr_state(struct expression *expr)
296 {
297 struct smatch_state *state;
298 char *name;
299
300 name = expr_to_str(expr);
301 if (!name)
302 return NULL;
303
304 state = __alloc_smatch_state(0);
305 expr = strip_expr(expr);
306 state->name = alloc_sname(name);
307 free_string(name);
308 state->data = expr;
309 return state;
310 }
311
312 static void match_skb_put(const char *fn, struct expression *expr, void *unused)
313 {
314 struct symbol *type;
315 struct smatch_state *state;
316
317 type = get_type(expr->left);
318 type = get_real_base_type(type);
319 if (!type || type->type != SYM_STRUCT)
320 return;
321 state = alloc_expr_state(expr->left);
322 set_state_expr(skb_put_id, expr->left, state);
323 }
324
325 static void match_return_skb_put(struct expression *expr)
326 {
327 struct sm_state *sm;
328 struct stree *stree;
329
330 if (is_error_return(expr))
331 return;
332
333 stree = __get_cur_stree();
334
335 FOR_EACH_MY_SM(skb_put_id, stree, sm) {
336 check_skb_put(sm->state->data);
337 } END_FOR_EACH_SM(sm);
338 }
339
340 static void register_clears_argument(void)
341 {
342 struct token *token;
343 const char *func;
344 int arg;
345
346 token = get_tokens_file("kernel.clears_argument");
347 if (!token)
348 return;
349 if (token_type(token) != TOKEN_STREAMBEGIN)
350 return;
351 token = token->next;
352 while (token_type(token) != TOKEN_STREAMEND) {
353 if (token_type(token) != TOKEN_IDENT)
354 return;
355 func = show_ident(token->ident);
356 token = token->next;
357 if (token_type(token) != TOKEN_NUMBER)
358 return;
359 arg = atoi(token->number);
388 token = token->next;
389 }
390 clear_token_alloc();
391 }
392
393 void check_rosenberg(int id)
394 {
395 if (option_project != PROJ_KERNEL)
396 return;
397 my_whole_id = id;
398
399 add_function_hook("memset", &match_clear, INT_PTR(0));
400 add_function_hook("memcpy", &match_clear, INT_PTR(0));
401 add_function_hook("memzero", &match_clear, INT_PTR(0));
402 add_function_hook("__memset", &match_clear, INT_PTR(0));
403 add_function_hook("__memcpy", &match_clear, INT_PTR(0));
404 add_function_hook("__memzero", &match_clear, INT_PTR(0));
405 add_function_hook("__builtin_memset", &match_clear, INT_PTR(0));
406 add_function_hook("__builtin_memcpy", &match_clear, INT_PTR(0));
407
408 register_clears_argument();
409 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
410
411 register_copy_funcs_from_file();
412 }
413
414 void check_rosenberg2(int id)
415 {
416 if (option_project != PROJ_KERNEL)
417 return;
418
419 my_member_id = id;
420 set_dynamic_states(my_member_id);
421 add_extra_mod_hook(&extra_mod_hook);
422 }
423
424 void check_rosenberg3(int id)
425 {
426 if (option_project != PROJ_KERNEL)
427 return;
428
429 skb_put_id = id;
430 set_dynamic_states(skb_put_id);
431 add_function_assign_hook("skb_put", &match_skb_put, NULL);
432 add_hook(&match_return_skb_put, RETURN_HOOK);
433 }
434
|