double_checking: fix compile problem
[smatch.git] / check_user_data.c
blob0cfef5acdedeaaa3861d946a52bcbf1c77398606
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 (is_fake_call(expr))
104 return 0;
105 if (expr->fn->type != EXPR_SYMBOL)
106 return 0;
107 sym = expr->fn->symbol;
108 if (!sym)
109 return 0;
111 if (sym->ctype.modifiers & MOD_STATIC) {
112 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
113 get_filename(), sym->ident->name);
114 } else {
115 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
116 sym->ident->name);
119 db_expr = expr;
120 db_user_data = 0;
121 run_sql(db_user_data_callback,
122 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
123 USER_DATA, sql_filter);
124 return db_user_data;
127 static int is_user_function(struct expression *expr)
129 if (expr->type != EXPR_CALL)
130 return 0;
131 return is_user_fn_db(expr);
134 static int is_skb_data(struct expression *expr)
136 struct symbol *sym;
137 char *name;
138 int len;
139 int ret = 0;
141 name = expr_to_var_sym(expr, &sym);
142 if (!name || !sym)
143 goto free;
145 sym = get_base_type(sym);
146 if (!sym || sym->type != SYM_PTR)
147 goto free;
148 sym = get_base_type(sym);
149 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
150 goto free;
151 if (strcmp(sym->ident->name, "sk_buff") != 0)
152 goto free;
154 len = strlen(name);
155 if (len < 6)
156 goto free;
157 if (strcmp(name + len - 6, "->data") == 0)
158 ret = SET_DATA;
160 free:
161 free_string(name);
162 return ret;
165 static int in_container_of_macro(struct expression *expr)
167 char *macro;
169 macro = get_macro_name(expr->pos);
171 if (!macro)
172 return 0;
173 if (strcmp(macro, "container_of") == 0)
174 return 1;
175 return 0;
178 static int is_user_data_state(struct expression *expr)
180 struct state_list *slist = NULL;
181 struct sm_state *tmp;
182 struct symbol *sym;
183 char *name;
184 int user = 0;
186 tmp = get_sm_state_expr(my_id, expr);
187 if (tmp) {
188 if (slist_has_state(tmp->possible, &user_data_set))
189 return SET_DATA;
190 if (slist_has_state(tmp->possible, &user_data_passed))
191 return PASSED_DATA;
192 return 0;
195 name = expr_to_str_sym(expr, &sym);
196 if (!name || !sym)
197 goto free;
199 slist = get_all_states(my_id);
200 FOR_EACH_PTR(slist, tmp) {
201 if (tmp->sym != sym)
202 continue;
203 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
204 if (slist_has_state(tmp->possible, &user_data_set))
205 user = SET_DATA;
206 else if (slist_has_state(tmp->possible, &user_data_passed))
207 user = PASSED_DATA;
208 goto free;
210 } END_FOR_EACH_PTR(tmp);
212 free:
213 free_slist(&slist);
214 free_string(name);
215 return user;
218 int is_user_data(struct expression *expr)
220 int user_data;
222 if (!expr)
223 return 0;
225 if (is_capped(expr))
226 return 0;
227 if (in_container_of_macro(expr))
228 return 0;
230 user_data = is_user_macro(expr);
231 if (user_data)
232 return user_data;
233 user_data = is_user_function(expr);
234 if (user_data)
235 return user_data;
236 user_data = is_skb_data(expr);
237 if (user_data)
238 return user_data;
240 expr = strip_expr(expr); /* this has to come after is_user_macro() */
242 if (expr->type == EXPR_BINOP) {
243 user_data = is_user_data(expr->left);
244 if (user_data)
245 return user_data;
246 if (is_array(expr))
247 return 0;
248 user_data = is_user_data(expr->right);
249 if (user_data)
250 return user_data;
251 return 0;
253 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
254 expr = strip_expr(expr->unop);
256 return is_user_data_state(expr);
259 int is_capped_user_data(struct expression *expr)
261 struct sm_state *sm;
263 sm = get_sm_state_expr(my_id, expr);
264 if (!sm)
265 return 0;
266 if (slist_has_state(sm->possible, &capped))
267 return 1;
268 return 0;
271 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
273 char fullname[256];
275 /* sanity check. this should always be true. */
276 if (strncmp(key, "$$", 2) != 0)
277 return;
278 snprintf(fullname, 256, "%s%s", name, key + 2);
279 set_state(my_id, fullname, sym, &user_data_passed);
282 static void match_syscall_definition(struct symbol *sym)
284 struct symbol *arg;
285 char *macro;
287 macro = get_macro_name(sym->pos);
288 if (!macro)
289 return;
290 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
291 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
292 return;
294 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
295 set_state(my_id, arg->ident->name, arg, &user_data_set);
296 } END_FOR_EACH_PTR(arg);
299 static void match_condition(struct expression *expr)
301 switch (expr->op) {
302 case '<':
303 case SPECIAL_LTE:
304 case SPECIAL_UNSIGNED_LT:
305 case SPECIAL_UNSIGNED_LTE:
306 if (is_user_data(expr->left))
307 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
308 if (is_user_data(expr->right))
309 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
310 break;
311 case '>':
312 case SPECIAL_GTE:
313 case SPECIAL_UNSIGNED_GT:
314 case SPECIAL_UNSIGNED_GTE:
315 if (is_user_data(expr->right))
316 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
317 if (is_user_data(expr->left))
318 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
319 break;
320 case SPECIAL_EQUAL:
321 if (is_user_data(expr->left))
322 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
323 if (is_user_data(expr->right))
324 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
325 break;
326 case SPECIAL_NOTEQUAL:
327 if (is_user_data(expr->left))
328 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
329 if (is_user_data(expr->right))
330 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
331 break;
332 default:
333 return;
337 static int handle_get_user(struct expression *expr)
339 char *name;
340 int ret = 0;
342 name = get_macro_name(expr->pos);
343 if (!name || strcmp(name, "get_user") != 0)
344 return 0;
346 name = expr_to_var(expr->right);
347 if (!name || strcmp(name, "__val_gu") != 0)
348 goto free;
349 set_state_expr(my_id, expr->left, &user_data_set);
350 ret = 1;
351 free:
352 free_string(name);
353 return ret;
356 static void match_assign(struct expression *expr)
358 int user_data;
360 if (handle_get_user(expr))
361 return;
363 user_data = is_user_data(expr->right);
364 if (user_data == PASSED_DATA)
365 set_state_expr(my_id, expr->left, &user_data_passed);
366 else if (user_data == SET_DATA)
367 set_state_expr(my_id, expr->left, &user_data_set);
368 else if (get_state_expr(my_id, expr->left))
369 set_state_expr(my_id, expr->left, &capped);
372 static void tag_struct_members(struct symbol *type, struct expression *expr)
374 struct symbol *tmp;
375 struct expression *member;
376 int op = '*';
378 if (expr->type == EXPR_PREOP && expr->op == '&') {
379 expr = strip_expr(expr->unop);
380 op = '.';
383 FOR_EACH_PTR(type->symbol_list, tmp) {
384 if (!tmp->ident)
385 continue;
386 member = member_expression(expr, op, tmp->ident);
387 set_state_expr(my_id, member, &user_data_set);
388 } END_FOR_EACH_PTR(tmp);
391 static void tag_base_type(struct expression *expr)
393 if (expr->type == EXPR_PREOP && expr->op == '&')
394 expr = strip_expr(expr->unop);
395 else
396 expr = deref_expression(expr);
397 set_state_expr(my_id, expr, &user_data_set);
400 static void tag_as_user_data(struct expression *expr)
402 struct symbol *type;
404 expr = strip_expr(expr);
406 type = get_type(expr);
407 if (!type || type->type != SYM_PTR)
408 return;
409 type = get_real_base_type(type);
410 if (!type)
411 return;
412 if (type == &void_ctype) {
413 set_state_expr(my_id, deref_expression(expr), &user_data_set);
414 return;
416 if (type->type == SYM_BASETYPE)
417 tag_base_type(expr);
418 if (type->type == SYM_STRUCT) {
419 if (expr->type != EXPR_PREOP || expr->op != '&')
420 expr = deref_expression(expr);
421 tag_struct_members(type, expr);
425 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
427 int param = PTR_INT(_param);
428 struct expression *dest;
430 dest = get_argument_from_call_expr(expr->args, param);
431 dest = strip_expr(dest);
432 if (!dest)
433 return;
434 tag_as_user_data(dest);
437 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
439 set_state_expr(my_id, expr->left, &user_data_set);
442 static void match_caller_info(struct expression *expr)
444 struct expression *tmp;
445 int i;
447 i = 0;
448 FOR_EACH_PTR(expr->args, tmp) {
449 if (is_user_data(tmp))
450 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
451 i++;
452 } END_FOR_EACH_PTR(tmp);
455 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
457 if (state == &capped)
458 return;
459 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
462 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
464 if (state == &capped)
465 return;
466 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
469 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
471 struct state_list *my_slist;
472 struct sm_state *tmp;
473 int param;
474 int user_data;
475 const char *passed_or_new;
477 user_data = is_user_data(expr);
478 if (user_data == PASSED_DATA) {
479 sql_insert_return_states(return_id, return_ranges, USER_DATA,
480 -1, "$$", "2");
482 if (user_data == SET_DATA) {
483 sql_insert_return_states(return_id, return_ranges, USER_DATA,
484 -1, "$$", "1");
487 my_slist = get_all_states(my_id);
489 FOR_EACH_PTR(my_slist, tmp) {
490 const char *param_name;
492 param = get_param_num_from_sym(tmp->sym);
493 if (param < 0)
494 continue;
496 if (is_capped_var_sym(tmp->name, tmp->sym))
497 continue;
498 /* ignore states that were already USER_DATA to begin with */
499 if (get_state_slist(get_start_states(), my_id, tmp->name, tmp->sym))
500 continue;
502 param_name = get_param_name(tmp);
503 if (!param_name || strcmp(param_name, "$$") == 0)
504 continue;
506 if (slist_has_state(tmp->possible, &user_data_set))
507 passed_or_new = "1";
508 else if (slist_has_state(tmp->possible, &user_data_passed))
509 passed_or_new = "2";
510 else
511 continue;
513 sql_insert_return_states(return_id, return_ranges, USER_DATA,
514 param, param_name, passed_or_new);
515 } END_FOR_EACH_PTR(tmp);
517 free_slist(&my_slist);
520 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
522 char *name;
523 struct symbol *sym;
525 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$$") == 0) {
526 tag_as_user_data(expr->left);
527 return;
530 name = return_state_to_var_sym(expr, param, key, &sym);
531 if (!name || !sym)
532 goto free;
534 set_state(my_id, name, sym, &user_data_set);
535 free:
536 free_string(name);
539 void check_user_data(int id)
541 if (option_project != PROJ_KERNEL)
542 return;
543 my_id = id;
544 select_caller_info_hook(set_param_user_data, USER_DATA);
545 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
546 add_hook(&match_condition, CONDITION_HOOK);
547 add_hook(&match_assign, ASSIGNMENT_HOOK);
548 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
549 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
550 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
551 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
553 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
554 add_member_info_callback(my_id, struct_member_callback);
555 add_returned_member_callback(my_id, returned_member_callback);
556 add_split_return_callback(print_returned_user_data);
557 select_return_states_hook(USER_DATA, &db_return_states_userdata);