math: improve how bitwise ANDs are handled
[smatch.git] / check_user_data.c
blob78447dbde1dc66df4dfdfbcb1bd41f1f7249c10b
1 /*
2 * smatch/check_user_data.c
4 * Copyright (C) 2011 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are a couple checks that try to see if a variable
12 * comes from the user. It would be better to unify them
13 * into one place. Also it we should follow the data down
14 * the call paths. Hence this file.
17 #include "smatch.h"
18 #include "smatch_slist.h"
19 #include "smatch_extra.h"
21 void tag_as_user_data(struct expression *expr);
23 static int my_id;
25 STATE(capped);
26 STATE(user_data_passed);
27 STATE(user_data_set);
29 enum {
30 SET_DATA = 1,
31 PASSED_DATA = 2,
34 int is_user_macro(struct expression *expr)
36 char *macro;
37 struct range_list *rl;
39 macro = get_macro_name(expr->pos);
41 if (!macro)
42 return 0;
43 if (get_implied_rl(expr, &rl) && !is_whole_rl(rl))
44 return 0;
45 if (strcmp(macro, "ntohl") == 0)
46 return SET_DATA;
47 if (strcmp(macro, "ntohs") == 0)
48 return SET_DATA;
49 return 0;
52 static int has_user_data_state(struct expression *expr, struct state_list *my_slist)
54 struct sm_state *sm;
55 struct symbol *sym;
56 char *name;
58 expr = strip_expr(expr);
59 if (expr->type == EXPR_PREOP && expr->op == '&')
60 expr = strip_expr(expr->unop);
62 name = expr_to_str_sym(expr, &sym);
63 free_string(name);
64 if (!sym)
65 return 1;
67 FOR_EACH_PTR(my_slist, sm) {
68 if (sm->sym == sym)
69 return 1;
70 } END_FOR_EACH_PTR(sm);
71 return 0;
74 static int passes_user_data(struct expression *expr)
76 struct state_list *slist;
77 struct expression *arg;
79 slist = get_all_states(my_id);
80 FOR_EACH_PTR(expr->args, arg) {
81 if (is_user_data(arg))
82 return 1;
83 if (has_user_data_state(arg, slist))
84 return 1;
85 } END_FOR_EACH_PTR(arg);
87 return 0;
90 static struct expression *db_expr;
91 static int db_user_data;
92 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
94 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
95 return 0;
96 db_user_data = 1;
97 return 0;
100 static int is_user_fn_db(struct expression *expr)
102 struct symbol *sym;
103 static char sql_filter[1024];
105 if (expr->fn->type != EXPR_SYMBOL)
106 return 0;
107 sym = expr->fn->symbol;
108 if (!sym)
109 return 0;
111 if (sym->ctype.modifiers & MOD_STATIC) {
112 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
113 get_filename(), sym->ident->name);
114 } else {
115 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
116 sym->ident->name);
119 db_expr = expr;
120 db_user_data = 0;
121 run_sql(db_user_data_callback,
122 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
123 USER_DATA, sql_filter);
124 return db_user_data;
127 static int is_user_function(struct expression *expr)
129 if (expr->type != EXPR_CALL)
130 return 0;
131 if (sym_name_is("kmemdup_user", expr->fn))
132 return SET_DATA;
133 return is_user_fn_db(expr);
136 static int is_skb_data(struct expression *expr)
138 struct symbol *sym;
139 char *name;
140 int len;
141 int ret = 0;
143 name = expr_to_var_sym(expr, &sym);
144 if (!name || !sym)
145 goto free;
147 sym = get_base_type(sym);
148 if (!sym || sym->type != SYM_PTR)
149 goto free;
150 sym = get_base_type(sym);
151 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
152 goto free;
153 if (strcmp(sym->ident->name, "sk_buff") != 0)
154 goto free;
156 len = strlen(name);
157 if (len < 6)
158 goto free;
159 if (strcmp(name + len - 6, "->data") == 0)
160 ret = SET_DATA;
162 free:
163 free_string(name);
164 return ret;
167 static int in_container_of_macro(struct expression *expr)
169 char *macro;
171 macro = get_macro_name(expr->pos);
173 if (!macro)
174 return 0;
175 if (strcmp(macro, "container_of") == 0)
176 return 1;
177 return 0;
180 static int is_user_data_state(struct expression *expr)
182 struct state_list *slist = NULL;
183 struct sm_state *tmp;
184 struct symbol *sym;
185 char *name;
186 int user = 0;
188 tmp = get_sm_state_expr(my_id, expr);
189 if (tmp) {
190 if (slist_has_state(tmp->possible, &user_data_set))
191 return SET_DATA;
192 if (slist_has_state(tmp->possible, &user_data_passed))
193 return PASSED_DATA;
194 return 0;
197 name = expr_to_str_sym(expr, &sym);
198 if (!name || !sym)
199 goto free;
201 slist = get_all_states(my_id);
202 FOR_EACH_PTR(slist, tmp) {
203 if (tmp->sym != sym)
204 continue;
205 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
206 if (slist_has_state(tmp->possible, &user_data_set))
207 user = SET_DATA;
208 else if (slist_has_state(tmp->possible, &user_data_passed))
209 user = PASSED_DATA;
210 goto free;
212 } END_FOR_EACH_PTR(tmp);
214 free:
215 free_slist(&slist);
216 free_string(name);
217 return user;
220 int is_user_data(struct expression *expr)
222 int user_data;
224 if (!expr)
225 return 0;
227 if (is_capped(expr))
228 return 0;
229 if (in_container_of_macro(expr))
230 return 0;
232 user_data = is_user_macro(expr);
233 if (user_data)
234 return user_data;
235 user_data = is_user_function(expr);
236 if (user_data)
237 return user_data;
238 user_data = is_skb_data(expr);
239 if (user_data)
240 return user_data;
242 expr = strip_expr(expr); /* this has to come after is_user_macro() */
244 if (expr->type == EXPR_BINOP) {
245 user_data = is_user_data(expr->left);
246 if (user_data)
247 return user_data;
248 if (is_array(expr))
249 return 0;
250 user_data = is_user_data(expr->right);
251 if (user_data)
252 return user_data;
253 return 0;
255 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
256 expr = strip_expr(expr->unop);
258 return is_user_data_state(expr);
261 int is_capped_user_data(struct expression *expr)
263 struct sm_state *sm;
265 sm = get_sm_state_expr(my_id, expr);
266 if (!sm)
267 return 0;
268 if (slist_has_state(sm->possible, &capped))
269 return 1;
270 return 0;
273 void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
275 char fullname[256];
277 /* sanity check. this should always be true. */
278 if (strncmp(key, "$$", 2) != 0)
279 return;
280 snprintf(fullname, 256, "%s%s", name, key + 2);
281 set_state(my_id, fullname, sym, &user_data_passed);
284 static void match_syscall_definition(struct symbol *sym)
286 struct symbol *arg;
287 char *macro;
289 macro = get_macro_name(sym->pos);
290 if (!macro)
291 return;
292 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
293 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
294 return;
296 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
297 set_state(my_id, arg->ident->name, arg, &user_data_set);
298 } END_FOR_EACH_PTR(arg);
301 static void match_condition(struct expression *expr)
303 switch (expr->op) {
304 case '<':
305 case SPECIAL_LTE:
306 case SPECIAL_UNSIGNED_LT:
307 case SPECIAL_UNSIGNED_LTE:
308 if (is_user_data(expr->left))
309 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
310 if (is_user_data(expr->right))
311 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
312 break;
313 case '>':
314 case SPECIAL_GTE:
315 case SPECIAL_UNSIGNED_GT:
316 case SPECIAL_UNSIGNED_GTE:
317 if (is_user_data(expr->right))
318 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
319 if (is_user_data(expr->left))
320 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
321 break;
322 case SPECIAL_EQUAL:
323 if (is_user_data(expr->left))
324 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
325 if (is_user_data(expr->right))
326 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
327 break;
328 case SPECIAL_NOTEQUAL:
329 if (is_user_data(expr->left))
330 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
331 if (is_user_data(expr->right))
332 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
333 break;
334 default:
335 return;
339 static void set_capped(struct sm_state *sm, struct expression *mod_expr)
341 set_state(my_id, sm->name, sm->sym, &capped);
344 static void match_normal_assign(struct expression *expr)
346 int user_data;
348 user_data = is_user_data(expr->right);
349 if (user_data == PASSED_DATA)
350 set_state_expr(my_id, expr->left, &user_data_passed);
351 if (user_data == SET_DATA)
352 set_state_expr(my_id, expr->left, &user_data_set);
355 static void match_assign(struct expression *expr)
357 char *name;
359 name = get_macro_name(expr->pos);
360 if (!name || strcmp(name, "get_user") != 0) {
361 match_normal_assign(expr);
362 return;
364 name = expr_to_var(expr->right);
365 if (!name || strcmp(name, "__val_gu") != 0)
366 goto free;
367 set_state_expr(my_id, expr->left, &user_data_set);
368 free:
369 free_string(name);
372 static void tag_struct_members(struct symbol *type, struct expression *expr)
374 struct symbol *tmp;
375 struct expression *member;
376 int op = '*';
378 if (expr->type == EXPR_PREOP && expr->op == '&') {
379 expr = strip_expr(expr->unop);
380 op = '.';
383 FOR_EACH_PTR(type->symbol_list, tmp) {
384 if (!tmp->ident)
385 continue;
386 member = member_expression(expr, op, tmp->ident);
387 set_state_expr(my_id, member, &user_data_set);
388 } END_FOR_EACH_PTR(tmp);
391 static void tag_base_type(struct expression *expr)
393 if (expr->type == EXPR_PREOP && expr->op == '&')
394 expr = strip_expr(expr->unop);
395 else
396 expr = deref_expression(expr);
397 set_state_expr(my_id, expr, &user_data_set);
400 void tag_as_user_data(struct expression *expr)
402 struct symbol *type;
404 expr = strip_expr(expr);
406 type = get_type(expr);
407 if (!type || type->type != SYM_PTR)
408 return;
409 type = get_real_base_type(type);
410 if (!type)
411 return;
412 if (type == &void_ctype) {
413 set_state_expr(my_id, deref_expression(expr), &user_data_set);
414 return;
416 if (type->type == SYM_BASETYPE)
417 tag_base_type(expr);
418 if (type->type == SYM_STRUCT) {
419 if (expr->type != EXPR_PREOP || expr->op != '&')
420 expr = deref_expression(expr);
421 tag_struct_members(type, expr);
425 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
427 int param = PTR_INT(_param);
428 struct expression *dest;
430 dest = get_argument_from_call_expr(expr->args, param);
431 dest = strip_expr(dest);
432 if (!dest)
433 return;
434 tag_as_user_data(dest);
437 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
439 set_state_expr(my_id, expr->left, &user_data_set);
442 static void match_macro_assign(const char *fn, struct expression *expr, void *_bits)
444 int bits;
446 bits = nr_bits(expr->left);
447 if (!bits)
448 return;
449 if (bits > nr_bits(expr->right))
450 return;
451 set_state_expr(my_id, expr->left, &user_data_set);
454 static void match_caller_info(struct expression *expr)
456 struct expression *tmp;
457 int i;
459 i = 0;
460 FOR_EACH_PTR(expr->args, tmp) {
461 if (is_user_data(tmp))
462 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
463 i++;
464 } END_FOR_EACH_PTR(tmp);
467 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
469 if (state == &capped)
470 return;
471 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
474 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
476 if (state == &capped)
477 return;
478 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
481 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
483 struct state_list *my_slist;
484 struct sm_state *tmp;
485 int param;
486 int user_data;
487 const char *passed_or_new;
489 user_data = is_user_data(expr);
490 if (user_data == PASSED_DATA) {
491 sql_insert_return_states(return_id, return_ranges, USER_DATA,
492 -1, "$$", "2");
494 if (user_data == SET_DATA) {
495 sql_insert_return_states(return_id, return_ranges, USER_DATA,
496 -1, "$$", "1");
499 my_slist = get_all_states(my_id);
501 FOR_EACH_PTR(my_slist, tmp) {
502 const char *param_name;
504 param = get_param_num_from_sym(tmp->sym);
505 if (param < 0)
506 continue;
508 if (is_capped_var_sym(tmp->name, tmp->sym))
509 continue;
510 /* ignore states that were already USER_DATA to begin with */
511 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
512 continue;
514 param_name = get_param_name(tmp);
515 if (!param_name)
516 return;
518 if (slist_has_state(tmp->possible, &user_data_set))
519 passed_or_new = "1";
520 if (slist_has_state(tmp->possible, &user_data_passed))
521 passed_or_new = "2";
523 sql_insert_return_states(return_id, return_ranges, USER_DATA,
524 param, param_name, passed_or_new);
525 } END_FOR_EACH_PTR(tmp);
527 free_slist(&my_slist);
530 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
532 char *name;
533 struct symbol *sym;
535 name = return_state_to_var_sym(expr, param, key, &sym);
536 if (!name || !sym)
537 goto free;
539 set_state(my_id, name, sym, &user_data_set);
540 free:
541 free_string(name);
544 void check_user_data(int id)
546 if (option_project != PROJ_KERNEL)
547 return;
548 my_id = id;
549 select_caller_info_hook(set_param_user_data, USER_DATA);
550 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
551 add_hook(&match_condition, CONDITION_HOOK);
552 add_hook(&match_assign, ASSIGNMENT_HOOK);
553 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
554 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
555 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
556 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
558 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
559 add_member_info_callback(my_id, struct_member_callback);
560 add_returned_member_callback(my_id, returned_member_callback);
561 add_returned_state_callback(print_returned_user_data);
562 select_return_states_hook(USER_DATA, &db_return_states_userdata);
564 add_modification_hook(my_id, &set_capped);
566 add_macro_assign_hook("ntohl", &match_macro_assign, NULL);
567 add_macro_assign_hook("ntohs", &match_macro_assign, NULL);