comparison: handle preops like "if (++a == b)"
[smatch.git] / check_user_data.c
blob714cd1404b9e3b870c3a14fdbd61cfc8cf331850
1 /*
2 * Copyright (C) 2011 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
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
19 * There are a couple checks that try to see if a variable
20 * comes from the user. It would be better to unify them
21 * into one place. Also it we should follow the data down
22 * the call paths. Hence this file.
25 #include "smatch.h"
26 #include "smatch_slist.h"
27 #include "smatch_extra.h"
29 static int my_id;
31 STATE(called);
33 STATE(capped);
34 STATE(user_data_passed);
35 STATE(user_data_set);
37 enum {
38 SET_DATA = 1,
39 PASSED_DATA = 2,
42 int is_user_macro(struct expression *expr)
44 char *macro;
45 struct range_list *rl;
47 macro = get_macro_name(expr->pos);
49 if (!macro)
50 return 0;
51 if (get_implied_rl(expr, &rl) && !is_whole_rl(rl))
52 return 0;
53 if (strcmp(macro, "ntohl") == 0)
54 return SET_DATA;
55 if (strcmp(macro, "ntohs") == 0)
56 return SET_DATA;
57 return 0;
60 static int has_user_data_state(struct expression *expr)
62 struct stree *stree;
63 struct sm_state *sm;
64 struct symbol *sym;
65 char *name;
67 expr = strip_expr(expr);
68 if (expr->type == EXPR_PREOP && expr->op == '&')
69 expr = strip_expr(expr->unop);
71 name = expr_to_str_sym(expr, &sym);
72 free_string(name);
73 if (!sym)
74 return 1;
76 stree = __get_cur_stree();
77 FOR_EACH_MY_SM(my_id, stree, sm) {
78 if (sm->sym == sym)
79 return 1;
80 } END_FOR_EACH_SM(sm);
81 return 0;
84 static int passes_user_data(struct expression *expr)
86 struct expression *arg;
88 FOR_EACH_PTR(expr->args, arg) {
89 if (is_user_data(arg))
90 return 1;
91 if (has_user_data_state(arg))
92 return 1;
93 } END_FOR_EACH_PTR(arg);
95 return 0;
98 static struct expression *db_expr;
99 static int db_user_data;
100 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
102 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
103 return 0;
104 db_user_data = 1;
105 return 0;
108 static int is_user_fn_db(struct expression *expr)
110 struct symbol *sym;
111 static char sql_filter[1024];
113 if (is_fake_call(expr))
114 return 0;
115 if (expr->fn->type != EXPR_SYMBOL)
116 return 0;
117 sym = expr->fn->symbol;
118 if (!sym)
119 return 0;
121 if (sym->ctype.modifiers & MOD_STATIC) {
122 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
123 get_filename(), sym->ident->name);
124 } else {
125 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
126 sym->ident->name);
129 db_expr = expr;
130 db_user_data = 0;
131 run_sql(db_user_data_callback, NULL,
132 "select value from return_states where type=%d and parameter = -1 and key = '$' and %s",
133 USER_DATA, sql_filter);
134 return db_user_data;
137 static int is_user_function(struct expression *expr)
139 if (expr->type != EXPR_CALL)
140 return 0;
141 return is_user_fn_db(expr);
144 static int is_skb_data(struct expression *expr)
146 struct symbol *sym;
147 char *name;
148 int len;
149 int ret = 0;
151 name = expr_to_var_sym(expr, &sym);
152 if (!name || !sym)
153 goto free;
155 sym = get_base_type(sym);
156 if (!sym || sym->type != SYM_PTR)
157 goto free;
158 sym = get_base_type(sym);
159 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
160 goto free;
161 if (strcmp(sym->ident->name, "sk_buff") != 0)
162 goto free;
164 len = strlen(name);
165 if (len < 6)
166 goto free;
167 if (strcmp(name + len - 6, "->data") == 0)
168 ret = SET_DATA;
170 free:
171 free_string(name);
172 return ret;
175 static int in_container_of_macro(struct expression *expr)
177 char *macro;
179 macro = get_macro_name(expr->pos);
181 if (!macro)
182 return 0;
183 if (strcmp(macro, "container_of") == 0)
184 return 1;
185 return 0;
188 static int is_user_data_state(struct expression *expr)
190 struct stree *stree = NULL;
191 struct sm_state *tmp;
192 struct symbol *sym;
193 char *name;
194 int user = 0;
196 tmp = get_sm_state_expr(my_id, expr);
197 if (tmp) {
198 if (slist_has_state(tmp->possible, &user_data_set))
199 return SET_DATA;
200 if (slist_has_state(tmp->possible, &user_data_passed))
201 return PASSED_DATA;
202 return 0;
205 name = expr_to_str_sym(expr, &sym);
206 if (!name || !sym)
207 goto free;
209 stree = __get_cur_stree();
210 FOR_EACH_MY_SM(my_id, stree, tmp) {
211 if (tmp->sym != sym)
212 continue;
213 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
214 if (slist_has_state(tmp->possible, &user_data_set))
215 user = SET_DATA;
216 else if (slist_has_state(tmp->possible, &user_data_passed))
217 user = PASSED_DATA;
218 goto free;
220 } END_FOR_EACH_SM(tmp);
222 free:
223 free_string(name);
224 return user;
227 int is_user_data(struct expression *expr)
229 int user_data;
231 if (!expr)
232 return 0;
234 if (is_capped(expr))
235 return 0;
236 if (in_container_of_macro(expr))
237 return 0;
239 user_data = is_user_macro(expr);
240 if (user_data)
241 return user_data;
242 user_data = is_user_function(expr);
243 if (user_data)
244 return user_data;
245 user_data = is_skb_data(expr);
246 if (user_data)
247 return user_data;
249 expr = strip_expr(expr); /* this has to come after is_user_macro() */
251 if (expr->type == EXPR_BINOP) {
252 user_data = is_user_data(expr->left);
253 if (user_data)
254 return user_data;
255 if (is_array(expr))
256 return 0;
257 user_data = is_user_data(expr->right);
258 if (user_data)
259 return user_data;
260 return 0;
262 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
263 expr = strip_expr(expr->unop);
265 return is_user_data_state(expr);
268 int implied_user_data(struct expression *expr, struct range_list **rl)
270 if (!is_user_data(expr))
271 return 0;
272 get_absolute_rl(expr, rl);
273 return 1;
276 int is_capped_user_data(struct expression *expr)
278 struct sm_state *sm;
280 sm = get_sm_state_expr(my_id, expr);
281 if (!sm)
282 return 0;
283 if (slist_has_state(sm->possible, &capped))
284 return 1;
285 return 0;
288 static void set_called(const char *name, struct symbol *sym, char *key, char *value)
290 set_state(my_id, "this_function", NULL, &called);
293 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
295 char fullname[256];
297 /* sanity check. this should always be true. */
298 if (strncmp(key, "$", 1) != 0)
299 return;
300 snprintf(fullname, 256, "%s%s", name, key + 1);
301 set_state(my_id, fullname, sym, &user_data_passed);
304 static void match_syscall_definition(struct symbol *sym)
306 struct symbol *arg;
307 char *macro;
308 char *name;
309 int is_syscall = 0;
311 macro = get_macro_name(sym->pos);
312 if (macro &&
313 (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
314 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
315 is_syscall = 1;
317 name = get_function();
318 if (!option_no_db && get_state(my_id, "this_function", NULL) != &called) {
319 if (name && strncmp(name, "sys_", 4) == 0)
320 is_syscall = 1;
323 if (name && strncmp(name, "compat_sys_", 11) == 0)
324 is_syscall = 1;
326 if (!is_syscall)
327 return;
329 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
330 set_state(my_id, arg->ident->name, arg, &user_data_set);
331 } END_FOR_EACH_PTR(arg);
334 static void match_condition(struct expression *expr)
336 switch (expr->op) {
337 case '<':
338 case SPECIAL_LTE:
339 case SPECIAL_UNSIGNED_LT:
340 case SPECIAL_UNSIGNED_LTE:
341 if (is_user_data(expr->left))
342 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
343 if (is_user_data(expr->right))
344 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
345 break;
346 case '>':
347 case SPECIAL_GTE:
348 case SPECIAL_UNSIGNED_GT:
349 case SPECIAL_UNSIGNED_GTE:
350 if (is_user_data(expr->right))
351 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
352 if (is_user_data(expr->left))
353 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
354 break;
355 case SPECIAL_EQUAL:
356 if (is_user_data(expr->left))
357 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
358 if (is_user_data(expr->right))
359 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
360 break;
361 case SPECIAL_NOTEQUAL:
362 if (is_user_data(expr->left))
363 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
364 if (is_user_data(expr->right))
365 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
366 break;
367 default:
368 return;
372 static int handle_get_user(struct expression *expr)
374 char *name;
375 int ret = 0;
377 name = get_macro_name(expr->pos);
378 if (!name || strcmp(name, "get_user") != 0)
379 return 0;
381 name = expr_to_var(expr->right);
382 if (!name || strcmp(name, "__val_gu") != 0)
383 goto free;
384 set_state_expr(my_id, expr->left, &user_data_set);
385 ret = 1;
386 free:
387 free_string(name);
388 return ret;
391 static void match_assign(struct expression *expr)
393 int user_data;
395 if (handle_get_user(expr))
396 return;
398 user_data = is_user_data(expr->right);
399 if (user_data == PASSED_DATA)
400 set_state_expr(my_id, expr->left, &user_data_passed);
401 else if (user_data == SET_DATA)
402 set_state_expr(my_id, expr->left, &user_data_set);
403 else if (get_state_expr(my_id, expr->left))
404 set_state_expr(my_id, expr->left, &capped);
407 static void tag_struct_members(struct symbol *type, struct expression *expr)
409 struct symbol *tmp;
410 struct expression *member;
411 int op = '*';
413 if (expr->type == EXPR_PREOP && expr->op == '&') {
414 expr = strip_expr(expr->unop);
415 op = '.';
418 FOR_EACH_PTR(type->symbol_list, tmp) {
419 if (!tmp->ident)
420 continue;
421 member = member_expression(expr, op, tmp->ident);
422 set_state_expr(my_id, member, &user_data_set);
423 } END_FOR_EACH_PTR(tmp);
426 static void tag_base_type(struct expression *expr)
428 if (expr->type == EXPR_PREOP && expr->op == '&')
429 expr = strip_expr(expr->unop);
430 else
431 expr = deref_expression(expr);
432 set_state_expr(my_id, expr, &user_data_set);
435 static void tag_as_user_data(struct expression *expr)
437 struct symbol *type;
439 expr = strip_expr(expr);
441 type = get_type(expr);
442 if (!type || type->type != SYM_PTR)
443 return;
444 type = get_real_base_type(type);
445 if (!type)
446 return;
447 if (type == &void_ctype) {
448 set_state_expr(my_id, deref_expression(expr), &user_data_set);
449 return;
451 if (type->type == SYM_BASETYPE)
452 tag_base_type(expr);
453 if (type->type == SYM_STRUCT) {
454 if (expr->type != EXPR_PREOP || expr->op != '&')
455 expr = deref_expression(expr);
456 tag_struct_members(type, expr);
460 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
462 int param = PTR_INT(_param);
463 struct expression *dest;
465 dest = get_argument_from_call_expr(expr->args, param);
466 dest = strip_expr(dest);
467 if (!dest)
468 return;
469 tag_as_user_data(dest);
472 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
474 set_state_expr(my_id, expr->left, &user_data_set);
477 static void match_caller_info(struct expression *expr)
479 struct expression *tmp;
480 int i;
482 i = 0;
483 FOR_EACH_PTR(expr->args, tmp) {
484 if (is_user_data(tmp))
485 sql_insert_caller_info(expr, USER_DATA, i, "$", "");
486 i++;
487 } END_FOR_EACH_PTR(tmp);
490 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
492 if (sm->state == &capped)
493 return;
494 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
497 static void returned_member_callback(int return_id, char *return_ranges, struct expression *expr, char *printed_name, struct smatch_state *state)
499 if (state == &capped)
500 return;
501 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
504 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
506 struct stree *stree;
507 struct sm_state *tmp;
508 int param;
509 int user_data;
510 const char *passed_or_new;
512 user_data = is_user_data(expr);
513 if (user_data == PASSED_DATA) {
514 sql_insert_return_states(return_id, return_ranges, USER_DATA,
515 -1, "$", "2");
517 if (user_data == SET_DATA) {
518 sql_insert_return_states(return_id, return_ranges, USER_DATA,
519 -1, "$", "1");
522 stree = __get_cur_stree();
524 FOR_EACH_MY_SM(my_id, stree, tmp) {
525 const char *param_name;
527 param = get_param_num_from_sym(tmp->sym);
528 if (param < 0)
529 continue;
531 if (is_capped_var_sym(tmp->name, tmp->sym))
532 continue;
533 /* ignore states that were already USER_DATA to begin with */
534 if (get_state_stree(get_start_states(), my_id, tmp->name, tmp->sym))
535 continue;
537 param_name = get_param_name(tmp);
538 if (!param_name || strcmp(param_name, "$") == 0)
539 continue;
541 if (slist_has_state(tmp->possible, &user_data_set))
542 passed_or_new = "1";
543 else if (slist_has_state(tmp->possible, &user_data_passed))
544 passed_or_new = "2";
545 else
546 continue;
548 sql_insert_return_states(return_id, return_ranges, USER_DATA,
549 param, param_name, passed_or_new);
550 } END_FOR_EACH_SM(tmp);
553 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
555 char *name;
556 struct symbol *sym;
558 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$") == 0) {
559 tag_as_user_data(expr->left);
560 return;
563 name = return_state_to_var_sym(expr, param, key, &sym);
564 if (!name || !sym)
565 goto free;
567 set_state(my_id, name, sym, &user_data_set);
568 free:
569 free_string(name);
572 void check_user_data(int id)
574 if (option_project != PROJ_KERNEL)
575 return;
576 my_id = id;
577 select_caller_info_hook(set_called, INTERNAL);
578 select_caller_info_hook(set_param_user_data, USER_DATA);
579 add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
580 add_hook(&match_condition, CONDITION_HOOK);
581 add_hook(&match_assign, ASSIGNMENT_HOOK);
582 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
583 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
584 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
585 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
586 add_function_hook("_kstrtoull", &match_user_copy, INT_PTR(2));
588 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
589 add_member_info_callback(my_id, struct_member_callback);
590 add_returned_member_callback(my_id, returned_member_callback);
591 add_split_return_callback(print_returned_user_data);
592 select_return_states_hook(USER_DATA, &db_return_states_userdata);