db: rename "callbacks" "select_caller_info_callbacks"
[smatch.git] / check_user_data.c
blob13d380e85072675569590034fbd97c02435e35bd
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 static const char * kstr_funcs[] = {
38 "kstrtoull", "kstrtoll", "kstrtoul", "kstrtol", "kstrtouint",
39 "kstrtoint", "kstrtou64", "kstrtos64", "kstrtou32", "kstrtos32",
40 "kstrtou16", "kstrtos16", "kstrtou8", "kstrtos8", "kstrtoull_from_user"
41 "kstrtoll_from_user", "kstrtoul_from_user", "kstrtol_from_user",
42 "kstrtouint_from_user", "kstrtoint_from_user", "kstrtou16_from_user",
43 "kstrtos16_from_user", "kstrtou8_from_user", "kstrtos8_from_user",
44 "kstrtou64_from_user", "kstrtos64_from_user", "kstrtou32_from_user",
45 "kstrtos32_from_user",
48 enum {
49 SET_DATA = 1,
50 PASSED_DATA = 2,
53 int is_user_macro(struct expression *expr)
55 char *macro;
56 struct range_list *rl;
58 macro = get_macro_name(expr->pos);
60 if (!macro)
61 return 0;
62 if (get_implied_rl(expr, &rl) && !is_whole_rl(rl))
63 return 0;
64 if (strcmp(macro, "ntohl") == 0)
65 return SET_DATA;
66 if (strcmp(macro, "ntohs") == 0)
67 return SET_DATA;
68 return 0;
71 static int has_user_data_state(struct expression *expr)
73 struct stree *stree;
74 struct sm_state *sm;
75 struct symbol *sym;
76 char *name;
78 expr = strip_expr(expr);
79 if (expr->type == EXPR_PREOP && expr->op == '&')
80 expr = strip_expr(expr->unop);
82 name = expr_to_str_sym(expr, &sym);
83 free_string(name);
84 if (!sym)
85 return 1;
87 stree = __get_cur_stree();
88 FOR_EACH_MY_SM(my_id, stree, sm) {
89 if (sm->sym == sym)
90 return 1;
91 } END_FOR_EACH_SM(sm);
92 return 0;
95 static int passes_user_data(struct expression *expr)
97 struct expression *arg;
99 FOR_EACH_PTR(expr->args, arg) {
100 if (is_user_data(arg))
101 return 1;
102 if (has_user_data_state(arg))
103 return 1;
104 } END_FOR_EACH_PTR(arg);
106 return 0;
109 static struct expression *db_expr;
110 static int db_user_data;
111 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
113 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
114 return 0;
115 db_user_data = 1;
116 return 0;
119 static int is_user_fn_db(struct expression *expr)
121 struct symbol *sym;
122 static char sql_filter[1024];
124 if (is_fake_call(expr))
125 return 0;
126 if (expr->fn->type != EXPR_SYMBOL)
127 return 0;
128 sym = expr->fn->symbol;
129 if (!sym)
130 return 0;
132 if (sym->ctype.modifiers & MOD_STATIC) {
133 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
134 get_filename(), sym->ident->name);
135 } else {
136 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
137 sym->ident->name);
140 db_expr = expr;
141 db_user_data = 0;
142 run_sql(db_user_data_callback, NULL,
143 "select value from return_states where type=%d and parameter = -1 and key = '$' and %s",
144 USER_DATA, sql_filter);
145 return db_user_data;
148 static int is_user_function(struct expression *expr)
150 if (expr->type != EXPR_CALL)
151 return 0;
152 return is_user_fn_db(expr);
155 static int is_skb_data(struct expression *expr)
157 struct symbol *sym;
158 char *name;
159 int len;
160 int ret = 0;
162 name = expr_to_var_sym(expr, &sym);
163 if (!name || !sym)
164 goto free;
166 sym = get_base_type(sym);
167 if (!sym || sym->type != SYM_PTR)
168 goto free;
169 sym = get_base_type(sym);
170 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
171 goto free;
172 if (strcmp(sym->ident->name, "sk_buff") != 0)
173 goto free;
175 len = strlen(name);
176 if (len < 6)
177 goto free;
178 if (strcmp(name + len - 6, "->data") == 0)
179 ret = SET_DATA;
181 free:
182 free_string(name);
183 return ret;
186 static int in_container_of_macro(struct expression *expr)
188 char *macro;
190 macro = get_macro_name(expr->pos);
192 if (!macro)
193 return 0;
194 if (strcmp(macro, "container_of") == 0)
195 return 1;
196 return 0;
199 static int is_user_data_state(struct expression *expr)
201 struct stree *stree = NULL;
202 struct sm_state *tmp;
203 struct symbol *sym;
204 char *name;
205 int user = 0;
207 tmp = get_sm_state_expr(my_id, expr);
208 if (tmp) {
209 if (slist_has_state(tmp->possible, &user_data_set))
210 return SET_DATA;
211 if (slist_has_state(tmp->possible, &user_data_passed))
212 return PASSED_DATA;
213 return 0;
216 name = expr_to_str_sym(expr, &sym);
217 if (!name || !sym)
218 goto free;
220 stree = __get_cur_stree();
221 FOR_EACH_MY_SM(my_id, stree, tmp) {
222 if (tmp->sym != sym)
223 continue;
224 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
225 if (slist_has_state(tmp->possible, &user_data_set))
226 user = SET_DATA;
227 else if (slist_has_state(tmp->possible, &user_data_passed))
228 user = PASSED_DATA;
229 goto free;
231 } END_FOR_EACH_SM(tmp);
233 free:
234 free_string(name);
235 return user;
238 int is_user_data(struct expression *expr)
240 struct range_list *rl;
241 int user_data;
243 if (is_capped(expr))
244 return 0;
245 return get_user_rl(expr, &rl);
247 if (!expr)
248 return 0;
250 if (is_capped(expr))
251 return 0;
252 if (in_container_of_macro(expr))
253 return 0;
255 user_data = is_user_macro(expr);
256 if (user_data)
257 return user_data;
258 user_data = is_user_function(expr);
259 if (user_data)
260 return user_data;
261 user_data = is_skb_data(expr);
262 if (user_data)
263 return user_data;
265 expr = strip_expr(expr); /* this has to come after is_user_macro() */
267 if (expr->type == EXPR_BINOP) {
268 user_data = is_user_data(expr->left);
269 if (user_data)
270 return user_data;
271 if (is_array(expr))
272 return 0;
273 user_data = is_user_data(expr->right);
274 if (user_data)
275 return user_data;
276 return 0;
278 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
279 expr = strip_expr(expr->unop);
281 return is_user_data_state(expr);
284 int implied_user_data(struct expression *expr, struct range_list **rl)
286 if (!is_user_data(expr))
287 return 0;
288 get_absolute_rl(expr, rl);
289 return 1;
292 int is_capped_user_data(struct expression *expr)
294 struct sm_state *sm;
296 sm = get_sm_state_expr(my_id, expr);
297 if (!sm)
298 return 0;
299 if (slist_has_state(sm->possible, &capped))
300 return 1;
301 return 0;
304 static void set_called(const char *name, struct symbol *sym, char *key, char *value)
306 set_state(my_id, "this_function", NULL, &called);
309 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
311 char fullname[256];
313 /* sanity check. this should always be true. */
314 if (strncmp(key, "$", 1) != 0)
315 return;
316 snprintf(fullname, 256, "%s%s", name, key + 1);
317 set_state(my_id, fullname, sym, &user_data_passed);
320 static void match_syscall_definition(struct symbol *sym)
322 struct symbol *arg;
323 char *macro;
324 char *name;
325 int is_syscall = 0;
327 macro = get_macro_name(sym->pos);
328 if (macro &&
329 (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
330 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
331 is_syscall = 1;
333 name = get_function();
334 if (!option_no_db && get_state(my_id, "this_function", NULL) != &called) {
335 if (name && strncmp(name, "sys_", 4) == 0)
336 is_syscall = 1;
339 if (name && strncmp(name, "compat_sys_", 11) == 0)
340 is_syscall = 1;
342 if (!is_syscall)
343 return;
345 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
346 set_state(my_id, arg->ident->name, arg, &user_data_set);
347 } END_FOR_EACH_PTR(arg);
350 static void match_condition(struct expression *expr)
352 switch (expr->op) {
353 case '<':
354 case SPECIAL_LTE:
355 case SPECIAL_UNSIGNED_LT:
356 case SPECIAL_UNSIGNED_LTE:
357 if (is_user_data(expr->left))
358 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
359 if (is_user_data(expr->right))
360 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
361 break;
362 case '>':
363 case SPECIAL_GTE:
364 case SPECIAL_UNSIGNED_GT:
365 case SPECIAL_UNSIGNED_GTE:
366 if (is_user_data(expr->right))
367 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
368 if (is_user_data(expr->left))
369 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
370 break;
371 case SPECIAL_EQUAL:
372 if (is_user_data(expr->left))
373 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
374 if (is_user_data(expr->right))
375 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
376 break;
377 case SPECIAL_NOTEQUAL:
378 if (is_user_data(expr->left))
379 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
380 if (is_user_data(expr->right))
381 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
382 break;
383 default:
384 return;
388 static int handle_get_user(struct expression *expr)
390 char *name;
391 int ret = 0;
393 name = get_macro_name(expr->pos);
394 if (!name || strcmp(name, "get_user") != 0)
395 return 0;
397 name = expr_to_var(expr->right);
398 if (!name || strcmp(name, "__val_gu") != 0)
399 goto free;
400 set_state_expr(my_id, expr->left, &user_data_set);
401 ret = 1;
402 free:
403 free_string(name);
404 return ret;
407 static void match_assign(struct expression *expr)
409 int user_data;
411 if (handle_get_user(expr))
412 return;
414 user_data = is_user_data(expr->right);
415 if (user_data == PASSED_DATA)
416 set_state_expr(my_id, expr->left, &user_data_passed);
417 else if (user_data == SET_DATA)
418 set_state_expr(my_id, expr->left, &user_data_set);
419 else if (get_state_expr(my_id, expr->left))
420 set_state_expr(my_id, expr->left, &capped);
423 static void tag_struct_members(struct symbol *type, struct expression *expr)
425 struct symbol *tmp;
426 struct expression *member;
427 int op = '*';
429 if (expr->type == EXPR_PREOP && expr->op == '&') {
430 expr = strip_expr(expr->unop);
431 op = '.';
434 FOR_EACH_PTR(type->symbol_list, tmp) {
435 if (!tmp->ident)
436 continue;
437 member = member_expression(expr, op, tmp->ident);
438 set_state_expr(my_id, member, &user_data_set);
439 } END_FOR_EACH_PTR(tmp);
442 static void tag_base_type(struct expression *expr)
444 if (expr->type == EXPR_PREOP && expr->op == '&')
445 expr = strip_expr(expr->unop);
446 else
447 expr = deref_expression(expr);
448 set_state_expr(my_id, expr, &user_data_set);
451 static void tag_as_user_data(struct expression *expr)
453 struct symbol *type;
455 expr = strip_expr(expr);
457 type = get_type(expr);
458 if (!type || type->type != SYM_PTR)
459 return;
460 type = get_real_base_type(type);
461 if (!type)
462 return;
463 if (type == &void_ctype) {
464 set_state_expr(my_id, deref_expression(expr), &user_data_set);
465 return;
467 if (type->type == SYM_BASETYPE)
468 tag_base_type(expr);
469 if (type->type == SYM_STRUCT) {
470 if (expr->type != EXPR_PREOP || expr->op != '&')
471 expr = deref_expression(expr);
472 tag_struct_members(type, expr);
476 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
478 int param = PTR_INT(_param);
479 struct expression *dest;
481 dest = get_argument_from_call_expr(expr->args, param);
482 dest = strip_expr(dest);
483 if (!dest)
484 return;
485 tag_as_user_data(dest);
488 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
490 set_state_expr(my_id, expr->left, &user_data_set);
493 static void match_caller_info(struct expression *expr)
495 struct expression *tmp;
496 int i;
498 i = 0;
499 FOR_EACH_PTR(expr->args, tmp) {
500 if (is_user_data(tmp))
501 sql_insert_caller_info(expr, USER_DATA, i, "$", "");
502 i++;
503 } END_FOR_EACH_PTR(tmp);
506 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
508 if (sm->state == &capped)
509 return;
510 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
513 static void returned_member_callback(int return_id, char *return_ranges, struct expression *expr, char *printed_name, struct smatch_state *state)
515 if (state == &capped)
516 return;
517 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
520 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
522 struct stree *stree;
523 struct sm_state *tmp;
524 int param;
525 int user_data;
526 const char *passed_or_new;
528 user_data = is_user_data(expr);
529 if (user_data == PASSED_DATA) {
530 sql_insert_return_states(return_id, return_ranges, USER_DATA,
531 -1, "$", "2");
533 if (user_data == SET_DATA) {
534 sql_insert_return_states(return_id, return_ranges, USER_DATA,
535 -1, "$", "1");
538 stree = __get_cur_stree();
540 FOR_EACH_MY_SM(my_id, stree, tmp) {
541 const char *param_name;
543 param = get_param_num_from_sym(tmp->sym);
544 if (param < 0)
545 continue;
547 if (is_capped_var_sym(tmp->name, tmp->sym))
548 continue;
549 /* ignore states that were already USER_DATA to begin with */
550 if (get_state_stree(get_start_states(), my_id, tmp->name, tmp->sym))
551 continue;
553 param_name = get_param_name(tmp);
554 if (!param_name || strcmp(param_name, "$") == 0)
555 continue;
557 if (slist_has_state(tmp->possible, &user_data_set))
558 passed_or_new = "1";
559 else if (slist_has_state(tmp->possible, &user_data_passed))
560 passed_or_new = "2";
561 else
562 continue;
564 sql_insert_return_states(return_id, return_ranges, USER_DATA,
565 param, param_name, passed_or_new);
566 } END_FOR_EACH_SM(tmp);
569 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
571 char *name;
572 struct symbol *sym;
574 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$") == 0) {
575 tag_as_user_data(expr->left);
576 return;
579 name = return_state_to_var_sym(expr, param, key, &sym);
580 if (!name || !sym)
581 goto free;
583 set_state(my_id, name, sym, &user_data_set);
584 free:
585 free_string(name);
588 void check_user_data(int id)
590 int i;
592 if (option_project != PROJ_KERNEL)
593 return;
594 my_id = id;
595 select_caller_info_hook(set_called, INTERNAL);
596 select_caller_info_hook(set_param_user_data, USER_DATA);
597 add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
598 add_hook(&match_condition, CONDITION_HOOK);
599 add_hook(&match_assign, ASSIGNMENT_HOOK);
600 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
601 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
602 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
603 add_function_assign_hook("memdup_user", &match_user_assign_function, NULL);
604 add_function_assign_hook("kmap_atomic", &match_user_assign_function, NULL);
605 for (i = 0; i < ARRAY_SIZE(kstr_funcs); i++)
606 add_function_hook(kstr_funcs[i], &match_user_copy, INT_PTR(2));
608 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
609 add_member_info_callback(my_id, struct_member_callback);
610 add_returned_member_callback(my_id, returned_member_callback);
611 add_split_return_callback(print_returned_user_data);
612 select_return_states_hook(USER_DATA, &db_return_states_userdata);