db, fixup_kernel.sh: ignore (struct irq_router)->set()
[smatch.git] / check_user_data.c
blob844fd3102199a87bf089b7155b4ed0d336132430
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 #define NEW_USER_DATA 1
24 #define PASSED_IN_USER_DATA 2
26 static int my_id;
28 STATE(capped);
29 STATE(user_data);
31 static int is_user_macro(struct expression *expr)
33 return 0;
36 static int has_user_data_state(struct expression *expr, struct state_list *my_slist)
38 struct sm_state *sm;
39 struct symbol *sym;
40 char *name;
42 expr = strip_expr(expr);
43 if (expr->type == EXPR_PREOP && expr->op == '&')
44 expr = strip_expr(expr->unop);
46 name = expr_to_str_sym(expr, &sym);
47 free_string(name);
48 if (!sym)
49 return 1;
51 FOR_EACH_PTR(my_slist, sm) {
52 if (sm->sym == sym)
53 return 1;
54 } END_FOR_EACH_PTR(sm);
55 return 0;
58 static int passes_user_data(struct expression *expr)
60 struct state_list *slist;
61 struct expression *arg;
63 slist = get_all_states(my_id);
64 FOR_EACH_PTR(expr->args, arg) {
65 if (is_user_data(arg))
66 return 1;
67 if (has_user_data_state(arg, slist))
68 return 1;
69 } END_FOR_EACH_PTR(arg);
71 return 0;
74 static struct expression *db_expr;
75 static int db_user_data;
76 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
78 if (atoi(argv[0]) == PASSED_IN_USER_DATA && !passes_user_data(db_expr))
79 return 0;
80 db_user_data = 1;
81 return 0;
84 static int is_user_fn_db(struct expression *expr)
86 struct symbol *sym;
87 static char sql_filter[1024];
89 if (expr->fn->type != EXPR_SYMBOL)
90 return 0;
91 sym = expr->fn->symbol;
92 if (!sym)
93 return 0;
95 if (sym->ctype.modifiers & MOD_STATIC) {
96 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
97 get_filename(), sym->ident->name);
98 } else {
99 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
100 sym->ident->name);
103 db_expr = expr;
104 db_user_data = 0;
105 run_sql(db_user_data_callback,
106 "select value from return_states where type=%d and %s",
107 USER_DATA, sql_filter);
108 return db_user_data;
111 static int is_user_function(struct expression *expr)
113 if (expr->type != EXPR_CALL)
114 return 0;
115 if (sym_name_is("kmemdup_user", expr->fn))
116 return 1;
117 return is_user_fn_db(expr);
120 static int is_skb_data(struct expression *expr)
122 struct symbol *sym;
123 char *name;
124 int len;
125 int ret = 0;
127 name = expr_to_var_sym(expr, &sym);
128 if (!name || !sym)
129 goto free;
131 sym = get_base_type(sym);
132 if (!sym || sym->type != SYM_PTR)
133 goto free;
134 sym = get_base_type(sym);
135 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
136 goto free;
137 if (strcmp(sym->ident->name, "sk_buff") != 0)
138 goto free;
140 len = strlen(name);
141 if (len < 6)
142 goto free;
143 if (strcmp(name + len - 6, "->data") == 0)
144 ret = 1;
146 free:
147 free_string(name);
148 return ret;
151 static int in_container_of_macro(struct expression *expr)
153 char *macro;
155 macro = get_macro_name(expr->pos);
157 if (!macro)
158 return 0;
159 if (strcmp(macro, "container_of") == 0)
160 return 1;
161 return 0;
164 static int is_user_data_state(struct expression *expr)
166 struct state_list *slist = NULL;
167 struct sm_state *tmp;
168 struct symbol *sym;
169 char *name;
170 int user = 0;
172 tmp = get_sm_state_expr(my_id, expr);
173 if (tmp)
174 return slist_has_state(tmp->possible, &user_data);
176 name = expr_to_str_sym(expr, &sym);
177 if (!name || !sym)
178 goto free;
180 slist = get_all_states(my_id);
181 FOR_EACH_PTR(slist, tmp) {
182 if (tmp->sym != sym)
183 continue;
184 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
185 if (slist_has_state(tmp->possible, &user_data))
186 user = 1;
187 goto free;
189 } END_FOR_EACH_PTR(tmp);
191 free:
192 free_slist(&slist);
193 free_string(name);
194 return user;
197 int is_user_data(struct expression *expr)
199 if (!expr)
200 return 0;
202 if (is_capped(expr))
203 return 0;
204 if (in_container_of_macro(expr))
205 return 0;
207 if (is_user_macro(expr))
208 return 1;
209 if (is_user_function(expr))
210 return 1;
211 if (is_skb_data(expr))
212 return 1;
214 expr = strip_expr(expr); /* this has to come after is_user_macro() */
216 if (expr->type == EXPR_BINOP) {
217 if (is_user_data(expr->left))
218 return 1;
219 if (is_array(expr))
220 return 0;
221 if (is_user_data(expr->right))
222 return 1;
223 return 0;
225 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
226 expr = strip_expr(expr->unop);
228 return is_user_data_state(expr);
231 int is_capped_user_data(struct expression *expr)
233 struct sm_state *sm;
235 sm = get_sm_state_expr(my_id, expr);
236 if (!sm)
237 return 0;
238 if (slist_has_state(sm->possible, &capped))
239 return 1;
240 return 0;
243 void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
245 char fullname[256];
247 /* sanity check. this should always be true. */
248 if (strncmp(key, "$$", 2) != 0)
249 return;
250 snprintf(fullname, 256, "%s%s", name, key + 2);
251 set_state(my_id, fullname, sym, &user_data);
254 static void match_syscall_definition(struct symbol *sym)
256 struct symbol *arg;
257 char *macro;
259 macro = get_macro_name(sym->pos);
260 if (!macro)
261 return;
262 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
263 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
264 return;
266 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
267 set_state(my_id, arg->ident->name, arg, &user_data);
268 } END_FOR_EACH_PTR(arg);
271 static void match_condition(struct expression *expr)
273 switch (expr->op) {
274 case '<':
275 case SPECIAL_LTE:
276 case SPECIAL_UNSIGNED_LT:
277 case SPECIAL_UNSIGNED_LTE:
278 if (is_user_data(expr->left))
279 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
280 if (is_user_data(expr->right))
281 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
282 break;
283 case '>':
284 case SPECIAL_GTE:
285 case SPECIAL_UNSIGNED_GT:
286 case SPECIAL_UNSIGNED_GTE:
287 if (is_user_data(expr->right))
288 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
289 if (is_user_data(expr->left))
290 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
291 break;
292 case SPECIAL_EQUAL:
293 if (is_user_data(expr->left))
294 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
295 if (is_user_data(expr->right))
296 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
297 break;
298 case SPECIAL_NOTEQUAL:
299 if (is_user_data(expr->left))
300 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
301 if (is_user_data(expr->right))
302 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
303 break;
304 default:
305 return;
309 static void match_normal_assign(struct expression *expr)
311 if (is_user_data(expr->right))
312 set_state_expr(my_id, expr->left, &user_data);
313 if (expr->op != '=')
314 return;
315 if (is_user_data(expr->left))
316 set_state_expr(my_id, expr->left, &capped);
319 static void match_assign(struct expression *expr)
321 char *name;
323 name = get_macro_name(expr->pos);
324 if (!name || strcmp(name, "get_user") != 0) {
325 match_normal_assign(expr);
326 return;
328 name = expr_to_var(expr->right);
329 if (!name || strcmp(name, "__val_gu") != 0)
330 goto free;
331 set_state_expr(my_id, expr->left, &user_data);
332 free:
333 free_string(name);
336 static void tag_struct_members(struct symbol *type, struct expression *expr)
338 struct symbol *tmp;
339 struct expression *member;
340 int op = '*';
342 if (expr->type == EXPR_PREOP && expr->op == '&') {
343 expr = strip_expr(expr->unop);
344 op = '.';
347 FOR_EACH_PTR(type->symbol_list, tmp) {
348 if (!tmp->ident)
349 continue;
350 member = member_expression(expr, op, tmp->ident);
351 set_state_expr(my_id, member, &user_data);
352 } END_FOR_EACH_PTR(tmp);
355 static void tag_base_type(struct expression *expr)
357 if (expr->type == EXPR_PREOP && expr->op == '&')
358 expr = strip_expr(expr->unop);
359 else
360 expr = deref_expression(expr);
361 set_state_expr(my_id, expr, &user_data);
364 void tag_as_user_data(struct expression *expr)
366 struct symbol *type;
368 expr = strip_expr(expr);
370 type = get_type(expr);
371 if (!type || type->type != SYM_PTR)
372 return;
373 type = get_real_base_type(type);
374 if (!type)
375 return;
376 if (type == &void_ctype) {
377 set_state_expr(my_id, deref_expression(expr), &user_data);
378 return;
380 if (type->type == SYM_BASETYPE)
381 tag_base_type(expr);
382 if (type->type == SYM_STRUCT) {
383 if (expr->type != EXPR_PREOP || expr->op != '&')
384 expr = deref_expression(expr);
385 tag_struct_members(type, expr);
389 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
391 int param = PTR_INT(_param);
392 struct expression *dest;
394 dest = get_argument_from_call_expr(expr->args, param);
395 dest = strip_expr(dest);
396 if (!dest)
397 return;
398 tag_as_user_data(dest);
401 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
403 set_state_expr(my_id, expr->left, &user_data);
406 static void match_assign_userdata(struct expression *expr)
408 if (is_user_data(expr->right))
409 set_state_expr(my_id, expr->left, &user_data);
412 static void match_caller_info(struct expression *expr)
414 struct expression *tmp;
415 int i;
417 i = 0;
418 FOR_EACH_PTR(expr->args, tmp) {
419 if (is_user_data(tmp))
420 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
421 i++;
422 } END_FOR_EACH_PTR(tmp);
425 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
427 if (state == &capped)
428 return;
429 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
432 int was_passed_in_user_data(struct expression *expr)
434 int ret;
436 __set_fake_cur_slist_fast(get_start_states());
437 ret = is_user_data_state(expr);
438 __pop_fake_cur_slist_fast();
439 return ret;
442 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
444 struct state_list *my_slist;
445 struct sm_state *tmp;
446 int param;
447 const char *passed_or_new;
449 passed_or_new = was_passed_in_user_data(expr) ? "2" : "1";
450 if (is_user_data(expr)) {
451 sql_insert_return_states(return_id, return_ranges, USER_DATA,
452 -1, "", passed_or_new);
455 my_slist = get_all_states(my_id);
457 FOR_EACH_PTR(my_slist, tmp) {
458 const char *param_name;
460 param = get_param_num_from_sym(tmp->sym);
461 if (param < 0)
462 continue;
464 if (is_capped_var_sym(tmp->name, tmp->sym))
465 continue;
466 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
467 continue;
469 param_name = get_param_name(tmp);
470 if (!param_name)
471 return;
473 sql_insert_return_states(return_id, return_ranges, USER_DATA,
474 param, param_name, passed_or_new);
475 } END_FOR_EACH_PTR(tmp);
477 free_slist(&my_slist);
480 static void db_param_is_now_userdata(struct expression *expr, int param, char *key, char *value)
482 struct expression *arg;
483 char *name;
484 struct symbol *sym;
486 while (expr->type == EXPR_ASSIGNMENT)
487 expr = strip_expr(expr->right);
488 if (expr->type != EXPR_CALL)
489 return;
491 arg = get_argument_from_call_expr(expr->args, param);
492 if (!arg)
493 return;
495 if (strcmp(key, "$$") == 0 && arg->type == EXPR_PREOP && arg->op == '&') {
496 arg = strip_expr(arg->unop);
497 name = expr_to_var_sym(arg, &sym);
498 } else {
499 name = get_variable_from_key(arg, key, &sym);
501 if (!name || !sym)
502 goto free;
504 set_state(my_id, name, sym, &user_data);
505 free:
506 free_string(name);
509 void check_user_data(int id)
511 if (option_project != PROJ_KERNEL)
512 return;
513 my_id = id;
514 add_definition_db_callback(set_param_user_data, USER_DATA);
515 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
516 add_hook(&match_condition, CONDITION_HOOK);
517 add_hook(&match_assign, ASSIGNMENT_HOOK);
518 add_hook(&match_assign_userdata, ASSIGNMENT_HOOK);
519 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
520 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
521 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
522 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
524 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
525 add_member_info_callback(my_id, struct_member_callback);
526 add_returned_state_callback(print_returned_user_data);
527 add_db_return_states_callback(USER_DATA, &db_param_is_now_userdata);