implied: remove some unused code
[smatch.git] / check_user_data.c
blob001840b92f4d6bef0d0e4f9419732cf18314b6fa
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 parameter = -1 and key = '$$' 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 set_capped(struct sm_state *sm, struct expression *mod_expr)
311 set_state(my_id, sm->name, sm->sym, &capped);
314 static void match_normal_assign(struct expression *expr)
316 if (is_user_data(expr->right))
317 set_state_expr(my_id, expr->left, &user_data);
320 static void match_assign(struct expression *expr)
322 char *name;
324 name = get_macro_name(expr->pos);
325 if (!name || strcmp(name, "get_user") != 0) {
326 match_normal_assign(expr);
327 return;
329 name = expr_to_var(expr->right);
330 if (!name || strcmp(name, "__val_gu") != 0)
331 goto free;
332 set_state_expr(my_id, expr->left, &user_data);
333 free:
334 free_string(name);
337 static void tag_struct_members(struct symbol *type, struct expression *expr)
339 struct symbol *tmp;
340 struct expression *member;
341 int op = '*';
343 if (expr->type == EXPR_PREOP && expr->op == '&') {
344 expr = strip_expr(expr->unop);
345 op = '.';
348 FOR_EACH_PTR(type->symbol_list, tmp) {
349 if (!tmp->ident)
350 continue;
351 member = member_expression(expr, op, tmp->ident);
352 set_state_expr(my_id, member, &user_data);
353 } END_FOR_EACH_PTR(tmp);
356 static void tag_base_type(struct expression *expr)
358 if (expr->type == EXPR_PREOP && expr->op == '&')
359 expr = strip_expr(expr->unop);
360 else
361 expr = deref_expression(expr);
362 set_state_expr(my_id, expr, &user_data);
365 void tag_as_user_data(struct expression *expr)
367 struct symbol *type;
369 expr = strip_expr(expr);
371 type = get_type(expr);
372 if (!type || type->type != SYM_PTR)
373 return;
374 type = get_real_base_type(type);
375 if (!type)
376 return;
377 if (type == &void_ctype) {
378 set_state_expr(my_id, deref_expression(expr), &user_data);
379 return;
381 if (type->type == SYM_BASETYPE)
382 tag_base_type(expr);
383 if (type->type == SYM_STRUCT) {
384 if (expr->type != EXPR_PREOP || expr->op != '&')
385 expr = deref_expression(expr);
386 tag_struct_members(type, expr);
390 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
392 int param = PTR_INT(_param);
393 struct expression *dest;
395 dest = get_argument_from_call_expr(expr->args, param);
396 dest = strip_expr(dest);
397 if (!dest)
398 return;
399 tag_as_user_data(dest);
402 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
404 set_state_expr(my_id, expr->left, &user_data);
407 static void match_assign_userdata(struct expression *expr)
409 if (is_user_data(expr->right))
410 set_state_expr(my_id, expr->left, &user_data);
413 static void match_caller_info(struct expression *expr)
415 struct expression *tmp;
416 int i;
418 i = 0;
419 FOR_EACH_PTR(expr->args, tmp) {
420 if (is_user_data(tmp))
421 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
422 i++;
423 } END_FOR_EACH_PTR(tmp);
426 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
428 if (state == &capped)
429 return;
430 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
433 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
435 if (state == &capped)
436 return;
437 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
440 int was_passed_in_user_data(struct expression *expr)
442 int ret;
444 __set_fake_cur_slist_fast(get_start_states());
445 ret = is_user_data_state(expr);
446 __pop_fake_cur_slist_fast();
447 return ret;
450 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
452 struct state_list *my_slist;
453 struct sm_state *tmp;
454 int param;
455 const char *passed_or_new;
457 passed_or_new = was_passed_in_user_data(expr) ? "2" : "1";
458 if (is_user_data(expr)) {
459 sql_insert_return_states(return_id, return_ranges, USER_DATA,
460 -1, "$$", passed_or_new);
463 my_slist = get_all_states(my_id);
465 FOR_EACH_PTR(my_slist, tmp) {
466 const char *param_name;
468 param = get_param_num_from_sym(tmp->sym);
469 if (param < 0)
470 continue;
472 if (is_capped_var_sym(tmp->name, tmp->sym))
473 continue;
474 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
475 continue;
477 param_name = get_param_name(tmp);
478 if (!param_name)
479 return;
481 sql_insert_return_states(return_id, return_ranges, USER_DATA,
482 param, param_name, passed_or_new);
483 } END_FOR_EACH_PTR(tmp);
485 free_slist(&my_slist);
488 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
490 char *name;
491 struct symbol *sym;
493 name = return_state_to_var_sym(expr, param, key, &sym);
494 if (!name || !sym)
495 goto free;
497 set_state(my_id, name, sym, &user_data);
498 free:
499 free_string(name);
502 void check_user_data(int id)
504 if (option_project != PROJ_KERNEL)
505 return;
506 my_id = id;
507 select_caller_info_hook(set_param_user_data, USER_DATA);
508 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
509 add_hook(&match_condition, CONDITION_HOOK);
510 add_hook(&match_assign, ASSIGNMENT_HOOK);
511 add_hook(&match_assign_userdata, ASSIGNMENT_HOOK);
512 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
513 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
514 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
515 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
517 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
518 add_member_info_callback(my_id, struct_member_callback);
519 add_returned_member_callback(my_id, returned_member_callback);
520 add_returned_state_callback(print_returned_user_data);
521 select_return_states_hook(USER_DATA, &db_return_states_userdata);
523 add_modification_hook(my_id, &set_capped);