db: improve database debugging
[smatch.git] / check_user_data.c
blobb627ab4ea8345493de10945a18dd0e64f821e7c3
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 static int my_id;
23 STATE(capped);
24 STATE(user_data_passed);
25 STATE(user_data_set);
27 enum {
28 SET_DATA = 1,
29 PASSED_DATA = 2,
32 int is_user_macro(struct expression *expr)
34 char *macro;
35 struct range_list *rl;
37 macro = get_macro_name(expr->pos);
39 if (!macro)
40 return 0;
41 if (get_implied_rl(expr, &rl) && !is_whole_rl(rl))
42 return 0;
43 if (strcmp(macro, "ntohl") == 0)
44 return SET_DATA;
45 if (strcmp(macro, "ntohs") == 0)
46 return SET_DATA;
47 return 0;
50 static int has_user_data_state(struct expression *expr, struct state_list *my_slist)
52 struct sm_state *sm;
53 struct symbol *sym;
54 char *name;
56 expr = strip_expr(expr);
57 if (expr->type == EXPR_PREOP && expr->op == '&')
58 expr = strip_expr(expr->unop);
60 name = expr_to_str_sym(expr, &sym);
61 free_string(name);
62 if (!sym)
63 return 1;
65 FOR_EACH_PTR(my_slist, sm) {
66 if (sm->sym == sym)
67 return 1;
68 } END_FOR_EACH_PTR(sm);
69 return 0;
72 static int passes_user_data(struct expression *expr)
74 struct state_list *slist;
75 struct expression *arg;
77 slist = get_all_states(my_id);
78 FOR_EACH_PTR(expr->args, arg) {
79 if (is_user_data(arg))
80 return 1;
81 if (has_user_data_state(arg, slist))
82 return 1;
83 } END_FOR_EACH_PTR(arg);
85 return 0;
88 static struct expression *db_expr;
89 static int db_user_data;
90 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
92 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
93 return 0;
94 db_user_data = 1;
95 return 0;
98 static int is_user_fn_db(struct expression *expr)
100 struct symbol *sym;
101 static char sql_filter[1024];
103 if (expr->fn->type != EXPR_SYMBOL)
104 return 0;
105 sym = expr->fn->symbol;
106 if (!sym)
107 return 0;
109 if (sym->ctype.modifiers & MOD_STATIC) {
110 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
111 get_filename(), sym->ident->name);
112 } else {
113 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
114 sym->ident->name);
117 db_expr = expr;
118 db_user_data = 0;
119 run_sql(db_user_data_callback,
120 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
121 USER_DATA, sql_filter);
122 return db_user_data;
125 static int is_user_function(struct expression *expr)
127 if (expr->type != EXPR_CALL)
128 return 0;
129 return is_user_fn_db(expr);
132 static int is_skb_data(struct expression *expr)
134 struct symbol *sym;
135 char *name;
136 int len;
137 int ret = 0;
139 name = expr_to_var_sym(expr, &sym);
140 if (!name || !sym)
141 goto free;
143 sym = get_base_type(sym);
144 if (!sym || sym->type != SYM_PTR)
145 goto free;
146 sym = get_base_type(sym);
147 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
148 goto free;
149 if (strcmp(sym->ident->name, "sk_buff") != 0)
150 goto free;
152 len = strlen(name);
153 if (len < 6)
154 goto free;
155 if (strcmp(name + len - 6, "->data") == 0)
156 ret = SET_DATA;
158 free:
159 free_string(name);
160 return ret;
163 static int in_container_of_macro(struct expression *expr)
165 char *macro;
167 macro = get_macro_name(expr->pos);
169 if (!macro)
170 return 0;
171 if (strcmp(macro, "container_of") == 0)
172 return 1;
173 return 0;
176 static int is_user_data_state(struct expression *expr)
178 struct state_list *slist = NULL;
179 struct sm_state *tmp;
180 struct symbol *sym;
181 char *name;
182 int user = 0;
184 tmp = get_sm_state_expr(my_id, expr);
185 if (tmp) {
186 if (slist_has_state(tmp->possible, &user_data_set))
187 return SET_DATA;
188 if (slist_has_state(tmp->possible, &user_data_passed))
189 return PASSED_DATA;
190 return 0;
193 name = expr_to_str_sym(expr, &sym);
194 if (!name || !sym)
195 goto free;
197 slist = get_all_states(my_id);
198 FOR_EACH_PTR(slist, tmp) {
199 if (tmp->sym != sym)
200 continue;
201 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
202 if (slist_has_state(tmp->possible, &user_data_set))
203 user = SET_DATA;
204 else if (slist_has_state(tmp->possible, &user_data_passed))
205 user = PASSED_DATA;
206 goto free;
208 } END_FOR_EACH_PTR(tmp);
210 free:
211 free_slist(&slist);
212 free_string(name);
213 return user;
216 int is_user_data(struct expression *expr)
218 int user_data;
220 if (!expr)
221 return 0;
223 if (is_capped(expr))
224 return 0;
225 if (in_container_of_macro(expr))
226 return 0;
228 user_data = is_user_macro(expr);
229 if (user_data)
230 return user_data;
231 user_data = is_user_function(expr);
232 if (user_data)
233 return user_data;
234 user_data = is_skb_data(expr);
235 if (user_data)
236 return user_data;
238 expr = strip_expr(expr); /* this has to come after is_user_macro() */
240 if (expr->type == EXPR_BINOP) {
241 user_data = is_user_data(expr->left);
242 if (user_data)
243 return user_data;
244 if (is_array(expr))
245 return 0;
246 user_data = is_user_data(expr->right);
247 if (user_data)
248 return user_data;
249 return 0;
251 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
252 expr = strip_expr(expr->unop);
254 return is_user_data_state(expr);
257 int is_capped_user_data(struct expression *expr)
259 struct sm_state *sm;
261 sm = get_sm_state_expr(my_id, expr);
262 if (!sm)
263 return 0;
264 if (slist_has_state(sm->possible, &capped))
265 return 1;
266 return 0;
269 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
271 char fullname[256];
273 /* sanity check. this should always be true. */
274 if (strncmp(key, "$$", 2) != 0)
275 return;
276 snprintf(fullname, 256, "%s%s", name, key + 2);
277 set_state(my_id, fullname, sym, &user_data_passed);
280 static void match_syscall_definition(struct symbol *sym)
282 struct symbol *arg;
283 char *macro;
285 macro = get_macro_name(sym->pos);
286 if (!macro)
287 return;
288 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
289 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
290 return;
292 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
293 set_state(my_id, arg->ident->name, arg, &user_data_set);
294 } END_FOR_EACH_PTR(arg);
297 static void match_condition(struct expression *expr)
299 switch (expr->op) {
300 case '<':
301 case SPECIAL_LTE:
302 case SPECIAL_UNSIGNED_LT:
303 case SPECIAL_UNSIGNED_LTE:
304 if (is_user_data(expr->left))
305 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
306 if (is_user_data(expr->right))
307 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
308 break;
309 case '>':
310 case SPECIAL_GTE:
311 case SPECIAL_UNSIGNED_GT:
312 case SPECIAL_UNSIGNED_GTE:
313 if (is_user_data(expr->right))
314 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
315 if (is_user_data(expr->left))
316 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
317 break;
318 case SPECIAL_EQUAL:
319 if (is_user_data(expr->left))
320 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
321 if (is_user_data(expr->right))
322 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
323 break;
324 case SPECIAL_NOTEQUAL:
325 if (is_user_data(expr->left))
326 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
327 if (is_user_data(expr->right))
328 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
329 break;
330 default:
331 return;
335 static void set_capped(struct sm_state *sm, struct expression *mod_expr)
337 set_state(my_id, sm->name, sm->sym, &capped);
340 static void match_normal_assign(struct expression *expr)
342 int user_data;
344 user_data = is_user_data(expr->right);
345 if (user_data == PASSED_DATA)
346 set_state_expr(my_id, expr->left, &user_data_passed);
347 if (user_data == SET_DATA)
348 set_state_expr(my_id, expr->left, &user_data_set);
351 static void match_assign(struct expression *expr)
353 char *name;
355 name = get_macro_name(expr->pos);
356 if (!name || strcmp(name, "get_user") != 0) {
357 match_normal_assign(expr);
358 return;
360 name = expr_to_var(expr->right);
361 if (!name || strcmp(name, "__val_gu") != 0)
362 goto free;
363 set_state_expr(my_id, expr->left, &user_data_set);
364 free:
365 free_string(name);
368 static void tag_struct_members(struct symbol *type, struct expression *expr)
370 struct symbol *tmp;
371 struct expression *member;
372 int op = '*';
374 if (expr->type == EXPR_PREOP && expr->op == '&') {
375 expr = strip_expr(expr->unop);
376 op = '.';
379 FOR_EACH_PTR(type->symbol_list, tmp) {
380 if (!tmp->ident)
381 continue;
382 member = member_expression(expr, op, tmp->ident);
383 set_state_expr(my_id, member, &user_data_set);
384 } END_FOR_EACH_PTR(tmp);
387 static void tag_base_type(struct expression *expr)
389 if (expr->type == EXPR_PREOP && expr->op == '&')
390 expr = strip_expr(expr->unop);
391 else
392 expr = deref_expression(expr);
393 set_state_expr(my_id, expr, &user_data_set);
396 static void tag_as_user_data(struct expression *expr)
398 struct symbol *type;
400 expr = strip_expr(expr);
402 type = get_type(expr);
403 if (!type || type->type != SYM_PTR)
404 return;
405 type = get_real_base_type(type);
406 if (!type)
407 return;
408 if (type == &void_ctype) {
409 set_state_expr(my_id, deref_expression(expr), &user_data_set);
410 return;
412 if (type->type == SYM_BASETYPE)
413 tag_base_type(expr);
414 if (type->type == SYM_STRUCT) {
415 if (expr->type != EXPR_PREOP || expr->op != '&')
416 expr = deref_expression(expr);
417 tag_struct_members(type, expr);
421 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
423 int param = PTR_INT(_param);
424 struct expression *dest;
426 dest = get_argument_from_call_expr(expr->args, param);
427 dest = strip_expr(dest);
428 if (!dest)
429 return;
430 tag_as_user_data(dest);
433 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
435 set_state_expr(my_id, expr->left, &user_data_set);
438 static void match_macro_assign(const char *fn, struct expression *expr, void *_bits)
440 int bits;
442 bits = nr_bits(expr->left);
443 if (!bits)
444 return;
445 if (bits > nr_bits(expr->right))
446 return;
447 set_state_expr(my_id, expr->left, &user_data_set);
450 static void match_caller_info(struct expression *expr)
452 struct expression *tmp;
453 int i;
455 i = 0;
456 FOR_EACH_PTR(expr->args, tmp) {
457 if (is_user_data(tmp))
458 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
459 i++;
460 } END_FOR_EACH_PTR(tmp);
463 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
465 if (state == &capped)
466 return;
467 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
470 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
472 if (state == &capped)
473 return;
474 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
477 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
479 struct state_list *my_slist;
480 struct sm_state *tmp;
481 int param;
482 int user_data;
483 const char *passed_or_new;
485 user_data = is_user_data(expr);
486 if (user_data == PASSED_DATA) {
487 sql_insert_return_states(return_id, return_ranges, USER_DATA,
488 -1, "$$", "2");
490 if (user_data == SET_DATA) {
491 sql_insert_return_states(return_id, return_ranges, USER_DATA,
492 -1, "$$", "1");
495 my_slist = get_all_states(my_id);
497 FOR_EACH_PTR(my_slist, tmp) {
498 const char *param_name;
500 param = get_param_num_from_sym(tmp->sym);
501 if (param < 0)
502 continue;
504 if (is_capped_var_sym(tmp->name, tmp->sym))
505 continue;
506 /* ignore states that were already USER_DATA to begin with */
507 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
508 continue;
510 param_name = get_param_name(tmp);
511 if (!param_name)
512 return;
514 if (slist_has_state(tmp->possible, &user_data_set))
515 passed_or_new = "1";
516 else if (slist_has_state(tmp->possible, &user_data_passed))
517 passed_or_new = "2";
518 else
519 continue;
521 sql_insert_return_states(return_id, return_ranges, USER_DATA,
522 param, param_name, passed_or_new);
523 } END_FOR_EACH_PTR(tmp);
525 free_slist(&my_slist);
528 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
530 char *name;
531 struct symbol *sym;
533 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$$") == 0) {
534 tag_as_user_data(expr->left);
535 return;
538 name = return_state_to_var_sym(expr, param, key, &sym);
539 if (!name || !sym)
540 goto free;
542 set_state(my_id, name, sym, &user_data_set);
543 free:
544 free_string(name);
547 void check_user_data(int id)
549 if (option_project != PROJ_KERNEL)
550 return;
551 my_id = id;
552 select_caller_info_hook(set_param_user_data, USER_DATA);
553 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
554 add_hook(&match_condition, CONDITION_HOOK);
555 add_hook(&match_assign, ASSIGNMENT_HOOK);
556 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
557 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
558 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
559 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
561 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
562 add_member_info_callback(my_id, struct_member_callback);
563 add_returned_member_callback(my_id, returned_member_callback);
564 add_split_return_callback(print_returned_user_data);
565 select_return_states_hook(USER_DATA, &db_return_states_userdata);
567 add_modification_hook(my_id, &set_capped);
569 add_macro_assign_hook("ntohl", &match_macro_assign, NULL);
570 add_macro_assign_hook("ntohs", &match_macro_assign, NULL);