848fbbcb1f52d5331a7f0376bf23faf8b8911a15
[smatch.git] / check_user_data.c
blob848fbbcb1f52d5331a7f0376bf23faf8b8911a15
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 static int is_user_macro(struct expression *expr)
36 return 0;
39 static int has_user_data_state(struct expression *expr, struct state_list *my_slist)
41 struct sm_state *sm;
42 struct symbol *sym;
43 char *name;
45 expr = strip_expr(expr);
46 if (expr->type == EXPR_PREOP && expr->op == '&')
47 expr = strip_expr(expr->unop);
49 name = expr_to_str_sym(expr, &sym);
50 free_string(name);
51 if (!sym)
52 return 1;
54 FOR_EACH_PTR(my_slist, sm) {
55 if (sm->sym == sym)
56 return 1;
57 } END_FOR_EACH_PTR(sm);
58 return 0;
61 static int passes_user_data(struct expression *expr)
63 struct state_list *slist;
64 struct expression *arg;
66 slist = get_all_states(my_id);
67 FOR_EACH_PTR(expr->args, arg) {
68 if (is_user_data(arg))
69 return 1;
70 if (has_user_data_state(arg, slist))
71 return 1;
72 } END_FOR_EACH_PTR(arg);
74 return 0;
77 static struct expression *db_expr;
78 static int db_user_data;
79 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
81 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
82 return 0;
83 db_user_data = 1;
84 return 0;
87 static int is_user_fn_db(struct expression *expr)
89 struct symbol *sym;
90 static char sql_filter[1024];
92 if (expr->fn->type != EXPR_SYMBOL)
93 return 0;
94 sym = expr->fn->symbol;
95 if (!sym)
96 return 0;
98 if (sym->ctype.modifiers & MOD_STATIC) {
99 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
100 get_filename(), sym->ident->name);
101 } else {
102 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
103 sym->ident->name);
106 db_expr = expr;
107 db_user_data = 0;
108 run_sql(db_user_data_callback,
109 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
110 USER_DATA, sql_filter);
111 return db_user_data;
114 static int is_user_function(struct expression *expr)
116 if (expr->type != EXPR_CALL)
117 return 0;
118 if (sym_name_is("kmemdup_user", expr->fn))
119 return SET_DATA;
120 return is_user_fn_db(expr);
123 static int is_skb_data(struct expression *expr)
125 struct symbol *sym;
126 char *name;
127 int len;
128 int ret = 0;
130 name = expr_to_var_sym(expr, &sym);
131 if (!name || !sym)
132 goto free;
134 sym = get_base_type(sym);
135 if (!sym || sym->type != SYM_PTR)
136 goto free;
137 sym = get_base_type(sym);
138 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
139 goto free;
140 if (strcmp(sym->ident->name, "sk_buff") != 0)
141 goto free;
143 len = strlen(name);
144 if (len < 6)
145 goto free;
146 if (strcmp(name + len - 6, "->data") == 0)
147 ret = SET_DATA;
149 free:
150 free_string(name);
151 return ret;
154 static int in_container_of_macro(struct expression *expr)
156 char *macro;
158 macro = get_macro_name(expr->pos);
160 if (!macro)
161 return 0;
162 if (strcmp(macro, "container_of") == 0)
163 return 1;
164 return 0;
167 static int is_user_data_state(struct expression *expr)
169 struct state_list *slist = NULL;
170 struct sm_state *tmp;
171 struct symbol *sym;
172 char *name;
173 int user = 0;
175 tmp = get_sm_state_expr(my_id, expr);
176 if (tmp) {
177 if (slist_has_state(tmp->possible, &user_data_set))
178 return SET_DATA;
179 if (slist_has_state(tmp->possible, &user_data_passed))
180 return PASSED_DATA;
181 return 0;
184 name = expr_to_str_sym(expr, &sym);
185 if (!name || !sym)
186 goto free;
188 slist = get_all_states(my_id);
189 FOR_EACH_PTR(slist, tmp) {
190 if (tmp->sym != sym)
191 continue;
192 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
193 if (slist_has_state(tmp->possible, &user_data_set))
194 user = SET_DATA;
195 else if (slist_has_state(tmp->possible, &user_data_passed))
196 user = PASSED_DATA;
197 goto free;
199 } END_FOR_EACH_PTR(tmp);
201 free:
202 free_slist(&slist);
203 free_string(name);
204 return user;
207 int is_user_data(struct expression *expr)
209 int user_data;
211 if (!expr)
212 return 0;
214 if (is_capped(expr))
215 return 0;
216 if (in_container_of_macro(expr))
217 return 0;
219 user_data = is_user_macro(expr);
220 if (user_data)
221 return user_data;
222 user_data = is_user_function(expr);
223 if (user_data)
224 return user_data;
225 user_data = is_skb_data(expr);
226 if (user_data)
227 return user_data;
229 expr = strip_expr(expr); /* this has to come after is_user_macro() */
231 if (expr->type == EXPR_BINOP) {
232 user_data = is_user_data(expr->left);
233 if (user_data)
234 return user_data;
235 if (is_array(expr))
236 return 0;
237 user_data = is_user_data(expr->right);
238 if (user_data)
239 return user_data;
240 return 0;
242 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
243 expr = strip_expr(expr->unop);
245 return is_user_data_state(expr);
248 int is_capped_user_data(struct expression *expr)
250 struct sm_state *sm;
252 sm = get_sm_state_expr(my_id, expr);
253 if (!sm)
254 return 0;
255 if (slist_has_state(sm->possible, &capped))
256 return 1;
257 return 0;
260 void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
262 char fullname[256];
264 /* sanity check. this should always be true. */
265 if (strncmp(key, "$$", 2) != 0)
266 return;
267 snprintf(fullname, 256, "%s%s", name, key + 2);
268 set_state(my_id, fullname, sym, &user_data_passed);
271 static void match_syscall_definition(struct symbol *sym)
273 struct symbol *arg;
274 char *macro;
276 macro = get_macro_name(sym->pos);
277 if (!macro)
278 return;
279 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
280 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
281 return;
283 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
284 set_state(my_id, arg->ident->name, arg, &user_data_set);
285 } END_FOR_EACH_PTR(arg);
288 static void match_condition(struct expression *expr)
290 switch (expr->op) {
291 case '<':
292 case SPECIAL_LTE:
293 case SPECIAL_UNSIGNED_LT:
294 case SPECIAL_UNSIGNED_LTE:
295 if (is_user_data(expr->left))
296 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
297 if (is_user_data(expr->right))
298 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
299 break;
300 case '>':
301 case SPECIAL_GTE:
302 case SPECIAL_UNSIGNED_GT:
303 case SPECIAL_UNSIGNED_GTE:
304 if (is_user_data(expr->right))
305 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
306 if (is_user_data(expr->left))
307 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
308 break;
309 case SPECIAL_EQUAL:
310 if (is_user_data(expr->left))
311 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
312 if (is_user_data(expr->right))
313 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
314 break;
315 case SPECIAL_NOTEQUAL:
316 if (is_user_data(expr->left))
317 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
318 if (is_user_data(expr->right))
319 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
320 break;
321 default:
322 return;
326 static void set_capped(struct sm_state *sm, struct expression *mod_expr)
328 set_state(my_id, sm->name, sm->sym, &capped);
331 static void match_normal_assign(struct expression *expr)
333 int user_data;
335 user_data = is_user_data(expr->right);
336 if (user_data == PASSED_DATA)
337 set_state_expr(my_id, expr->left, &user_data_passed);
338 if (user_data == SET_DATA)
339 set_state_expr(my_id, expr->left, &user_data_set);
342 static void match_assign(struct expression *expr)
344 char *name;
346 name = get_macro_name(expr->pos);
347 if (!name || strcmp(name, "get_user") != 0) {
348 match_normal_assign(expr);
349 return;
351 name = expr_to_var(expr->right);
352 if (!name || strcmp(name, "__val_gu") != 0)
353 goto free;
354 set_state_expr(my_id, expr->left, &user_data_set);
355 free:
356 free_string(name);
359 static void tag_struct_members(struct symbol *type, struct expression *expr)
361 struct symbol *tmp;
362 struct expression *member;
363 int op = '*';
365 if (expr->type == EXPR_PREOP && expr->op == '&') {
366 expr = strip_expr(expr->unop);
367 op = '.';
370 FOR_EACH_PTR(type->symbol_list, tmp) {
371 if (!tmp->ident)
372 continue;
373 member = member_expression(expr, op, tmp->ident);
374 set_state_expr(my_id, member, &user_data_set);
375 } END_FOR_EACH_PTR(tmp);
378 static void tag_base_type(struct expression *expr)
380 if (expr->type == EXPR_PREOP && expr->op == '&')
381 expr = strip_expr(expr->unop);
382 else
383 expr = deref_expression(expr);
384 set_state_expr(my_id, expr, &user_data_set);
387 void tag_as_user_data(struct expression *expr)
389 struct symbol *type;
391 expr = strip_expr(expr);
393 type = get_type(expr);
394 if (!type || type->type != SYM_PTR)
395 return;
396 type = get_real_base_type(type);
397 if (!type)
398 return;
399 if (type == &void_ctype) {
400 set_state_expr(my_id, deref_expression(expr), &user_data_set);
401 return;
403 if (type->type == SYM_BASETYPE)
404 tag_base_type(expr);
405 if (type->type == SYM_STRUCT) {
406 if (expr->type != EXPR_PREOP || expr->op != '&')
407 expr = deref_expression(expr);
408 tag_struct_members(type, expr);
412 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
414 int param = PTR_INT(_param);
415 struct expression *dest;
417 dest = get_argument_from_call_expr(expr->args, param);
418 dest = strip_expr(dest);
419 if (!dest)
420 return;
421 tag_as_user_data(dest);
424 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
426 set_state_expr(my_id, expr->left, &user_data_set);
429 static void match_macro_assign(const char *fn, struct expression *expr, void *_bits)
431 int bits;
433 bits = nr_bits(expr->left);
434 if (!bits)
435 return;
436 if (bits > nr_bits(expr->right))
437 return;
438 set_state_expr(my_id, expr->left, &user_data_set);
441 static void match_caller_info(struct expression *expr)
443 struct expression *tmp;
444 int i;
446 i = 0;
447 FOR_EACH_PTR(expr->args, tmp) {
448 if (is_user_data(tmp))
449 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
450 i++;
451 } END_FOR_EACH_PTR(tmp);
454 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
456 if (state == &capped)
457 return;
458 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
461 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
463 if (state == &capped)
464 return;
465 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
468 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
470 struct state_list *my_slist;
471 struct sm_state *tmp;
472 int param;
473 int user_data;
474 const char *passed_or_new;
476 user_data = is_user_data(expr);
477 if (user_data == PASSED_DATA) {
478 sql_insert_return_states(return_id, return_ranges, USER_DATA,
479 -1, "$$", "2");
481 if (user_data == SET_DATA) {
482 sql_insert_return_states(return_id, return_ranges, USER_DATA,
483 -1, "$$", "1");
486 my_slist = get_all_states(my_id);
488 FOR_EACH_PTR(my_slist, tmp) {
489 const char *param_name;
491 param = get_param_num_from_sym(tmp->sym);
492 if (param < 0)
493 continue;
495 if (is_capped_var_sym(tmp->name, tmp->sym))
496 continue;
497 /* ignore states that were already USER_DATA to begin with */
498 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
499 continue;
501 param_name = get_param_name(tmp);
502 if (!param_name)
503 return;
505 if (slist_has_state(tmp->possible, &user_data_set))
506 passed_or_new = "1";
507 if (slist_has_state(tmp->possible, &user_data_passed))
508 passed_or_new = "2";
510 sql_insert_return_states(return_id, return_ranges, USER_DATA,
511 param, param_name, passed_or_new);
512 } END_FOR_EACH_PTR(tmp);
514 free_slist(&my_slist);
517 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
519 char *name;
520 struct symbol *sym;
522 name = return_state_to_var_sym(expr, param, key, &sym);
523 if (!name || !sym)
524 goto free;
526 set_state(my_id, name, sym, &user_data_set);
527 free:
528 free_string(name);
531 void check_user_data(int id)
533 if (option_project != PROJ_KERNEL)
534 return;
535 my_id = id;
536 select_caller_info_hook(set_param_user_data, USER_DATA);
537 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
538 add_hook(&match_condition, CONDITION_HOOK);
539 add_hook(&match_assign, ASSIGNMENT_HOOK);
540 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
541 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
542 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
543 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
545 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
546 add_member_info_callback(my_id, struct_member_callback);
547 add_returned_member_callback(my_id, returned_member_callback);
548 add_returned_state_callback(print_returned_user_data);
549 select_return_states_hook(USER_DATA, &db_return_states_userdata);
551 add_modification_hook(my_id, &set_capped);