0e8d83c277881b9477445d28bf1a92195a300b41
[smatch.git] / check_user_data.c
blob0e8d83c277881b9477445d28bf1a92195a300b41
1 /*
2 * Copyright (C) 2011 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * There are a couple checks that try to see if a variable
20 * comes from the user. It would be better to unify them
21 * into one place. Also it we should follow the data down
22 * the call paths. Hence this file.
25 #include "smatch.h"
26 #include "smatch_slist.h"
27 #include "smatch_extra.h"
29 static int my_id;
31 STATE(capped);
32 STATE(user_data_passed);
33 STATE(user_data_set);
35 enum {
36 SET_DATA = 1,
37 PASSED_DATA = 2,
40 int is_user_macro(struct expression *expr)
42 char *macro;
43 struct range_list *rl;
45 macro = get_macro_name(expr->pos);
47 if (!macro)
48 return 0;
49 if (get_implied_rl(expr, &rl) && !is_whole_rl(rl))
50 return 0;
51 if (strcmp(macro, "ntohl") == 0)
52 return SET_DATA;
53 if (strcmp(macro, "ntohs") == 0)
54 return SET_DATA;
55 return 0;
58 static int has_user_data_state(struct expression *expr)
60 struct stree *stree;
61 struct sm_state *sm;
62 struct symbol *sym;
63 char *name;
65 expr = strip_expr(expr);
66 if (expr->type == EXPR_PREOP && expr->op == '&')
67 expr = strip_expr(expr->unop);
69 name = expr_to_str_sym(expr, &sym);
70 free_string(name);
71 if (!sym)
72 return 1;
74 stree = __get_cur_stree();
75 FOR_EACH_MY_SM(my_id, stree, sm) {
76 if (sm->sym == sym)
77 return 1;
78 } END_FOR_EACH_SM(sm);
79 return 0;
82 static int passes_user_data(struct expression *expr)
84 struct expression *arg;
86 FOR_EACH_PTR(expr->args, arg) {
87 if (is_user_data(arg))
88 return 1;
89 if (has_user_data_state(arg))
90 return 1;
91 } END_FOR_EACH_PTR(arg);
93 return 0;
96 static struct expression *db_expr;
97 static int db_user_data;
98 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
100 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
101 return 0;
102 db_user_data = 1;
103 return 0;
106 static int is_user_fn_db(struct expression *expr)
108 struct symbol *sym;
109 static char sql_filter[1024];
111 if (is_fake_call(expr))
112 return 0;
113 if (expr->fn->type != EXPR_SYMBOL)
114 return 0;
115 sym = expr->fn->symbol;
116 if (!sym)
117 return 0;
119 if (sym->ctype.modifiers & MOD_STATIC) {
120 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
121 get_filename(), sym->ident->name);
122 } else {
123 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
124 sym->ident->name);
127 db_expr = expr;
128 db_user_data = 0;
129 run_sql(db_user_data_callback,
130 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
131 USER_DATA, sql_filter);
132 return db_user_data;
135 static int is_user_function(struct expression *expr)
137 if (expr->type != EXPR_CALL)
138 return 0;
139 return is_user_fn_db(expr);
142 static int is_skb_data(struct expression *expr)
144 struct symbol *sym;
145 char *name;
146 int len;
147 int ret = 0;
149 name = expr_to_var_sym(expr, &sym);
150 if (!name || !sym)
151 goto free;
153 sym = get_base_type(sym);
154 if (!sym || sym->type != SYM_PTR)
155 goto free;
156 sym = get_base_type(sym);
157 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
158 goto free;
159 if (strcmp(sym->ident->name, "sk_buff") != 0)
160 goto free;
162 len = strlen(name);
163 if (len < 6)
164 goto free;
165 if (strcmp(name + len - 6, "->data") == 0)
166 ret = SET_DATA;
168 free:
169 free_string(name);
170 return ret;
173 static int in_container_of_macro(struct expression *expr)
175 char *macro;
177 macro = get_macro_name(expr->pos);
179 if (!macro)
180 return 0;
181 if (strcmp(macro, "container_of") == 0)
182 return 1;
183 return 0;
186 static int is_user_data_state(struct expression *expr)
188 struct stree *stree = NULL;
189 struct sm_state *tmp;
190 struct symbol *sym;
191 char *name;
192 int user = 0;
194 tmp = get_sm_state_expr(my_id, expr);
195 if (tmp) {
196 if (slist_has_state(tmp->possible, &user_data_set))
197 return SET_DATA;
198 if (slist_has_state(tmp->possible, &user_data_passed))
199 return PASSED_DATA;
200 return 0;
203 name = expr_to_str_sym(expr, &sym);
204 if (!name || !sym)
205 goto free;
207 stree = __get_cur_stree();
208 FOR_EACH_MY_SM(my_id, stree, tmp) {
209 if (tmp->sym != sym)
210 continue;
211 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
212 if (slist_has_state(tmp->possible, &user_data_set))
213 user = SET_DATA;
214 else if (slist_has_state(tmp->possible, &user_data_passed))
215 user = PASSED_DATA;
216 goto free;
218 } END_FOR_EACH_SM(tmp);
220 free:
221 free_string(name);
222 return user;
225 int is_user_data(struct expression *expr)
227 int user_data;
229 if (!expr)
230 return 0;
232 if (is_capped(expr))
233 return 0;
234 if (in_container_of_macro(expr))
235 return 0;
237 user_data = is_user_macro(expr);
238 if (user_data)
239 return user_data;
240 user_data = is_user_function(expr);
241 if (user_data)
242 return user_data;
243 user_data = is_skb_data(expr);
244 if (user_data)
245 return user_data;
247 expr = strip_expr(expr); /* this has to come after is_user_macro() */
249 if (expr->type == EXPR_BINOP) {
250 user_data = is_user_data(expr->left);
251 if (user_data)
252 return user_data;
253 if (is_array(expr))
254 return 0;
255 user_data = is_user_data(expr->right);
256 if (user_data)
257 return user_data;
258 return 0;
260 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
261 expr = strip_expr(expr->unop);
263 return is_user_data_state(expr);
266 int implied_user_data(struct expression *expr, struct range_list **rl)
268 if (!is_user_data(expr))
269 return 0;
270 get_absolute_rl(expr, rl);
271 return 1;
274 int is_capped_user_data(struct expression *expr)
276 struct sm_state *sm;
278 sm = get_sm_state_expr(my_id, expr);
279 if (!sm)
280 return 0;
281 if (slist_has_state(sm->possible, &capped))
282 return 1;
283 return 0;
286 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
288 char fullname[256];
290 /* sanity check. this should always be true. */
291 if (strncmp(key, "$$", 2) != 0)
292 return;
293 snprintf(fullname, 256, "%s%s", name, key + 2);
294 set_state(my_id, fullname, sym, &user_data_passed);
297 static void match_syscall_definition(struct symbol *sym)
299 struct symbol *arg;
300 char *macro;
302 macro = get_macro_name(sym->pos);
303 if (!macro)
304 return;
305 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
306 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
307 return;
309 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
310 set_state(my_id, arg->ident->name, arg, &user_data_set);
311 } END_FOR_EACH_PTR(arg);
314 static void match_condition(struct expression *expr)
316 switch (expr->op) {
317 case '<':
318 case SPECIAL_LTE:
319 case SPECIAL_UNSIGNED_LT:
320 case SPECIAL_UNSIGNED_LTE:
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, NULL, &capped);
325 break;
326 case '>':
327 case SPECIAL_GTE:
328 case SPECIAL_UNSIGNED_GT:
329 case SPECIAL_UNSIGNED_GTE:
330 if (is_user_data(expr->right))
331 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
332 if (is_user_data(expr->left))
333 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
334 break;
335 case SPECIAL_EQUAL:
336 if (is_user_data(expr->left))
337 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
338 if (is_user_data(expr->right))
339 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
340 break;
341 case SPECIAL_NOTEQUAL:
342 if (is_user_data(expr->left))
343 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
344 if (is_user_data(expr->right))
345 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
346 break;
347 default:
348 return;
352 static int handle_get_user(struct expression *expr)
354 char *name;
355 int ret = 0;
357 name = get_macro_name(expr->pos);
358 if (!name || strcmp(name, "get_user") != 0)
359 return 0;
361 name = expr_to_var(expr->right);
362 if (!name || strcmp(name, "__val_gu") != 0)
363 goto free;
364 set_state_expr(my_id, expr->left, &user_data_set);
365 ret = 1;
366 free:
367 free_string(name);
368 return ret;
371 static void match_assign(struct expression *expr)
373 int user_data;
375 if (handle_get_user(expr))
376 return;
378 user_data = is_user_data(expr->right);
379 if (user_data == PASSED_DATA)
380 set_state_expr(my_id, expr->left, &user_data_passed);
381 else if (user_data == SET_DATA)
382 set_state_expr(my_id, expr->left, &user_data_set);
383 else if (get_state_expr(my_id, expr->left))
384 set_state_expr(my_id, expr->left, &capped);
387 static void tag_struct_members(struct symbol *type, struct expression *expr)
389 struct symbol *tmp;
390 struct expression *member;
391 int op = '*';
393 if (expr->type == EXPR_PREOP && expr->op == '&') {
394 expr = strip_expr(expr->unop);
395 op = '.';
398 FOR_EACH_PTR(type->symbol_list, tmp) {
399 if (!tmp->ident)
400 continue;
401 member = member_expression(expr, op, tmp->ident);
402 set_state_expr(my_id, member, &user_data_set);
403 } END_FOR_EACH_PTR(tmp);
406 static void tag_base_type(struct expression *expr)
408 if (expr->type == EXPR_PREOP && expr->op == '&')
409 expr = strip_expr(expr->unop);
410 else
411 expr = deref_expression(expr);
412 set_state_expr(my_id, expr, &user_data_set);
415 static void tag_as_user_data(struct expression *expr)
417 struct symbol *type;
419 expr = strip_expr(expr);
421 type = get_type(expr);
422 if (!type || type->type != SYM_PTR)
423 return;
424 type = get_real_base_type(type);
425 if (!type)
426 return;
427 if (type == &void_ctype) {
428 set_state_expr(my_id, deref_expression(expr), &user_data_set);
429 return;
431 if (type->type == SYM_BASETYPE)
432 tag_base_type(expr);
433 if (type->type == SYM_STRUCT) {
434 if (expr->type != EXPR_PREOP || expr->op != '&')
435 expr = deref_expression(expr);
436 tag_struct_members(type, expr);
440 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
442 int param = PTR_INT(_param);
443 struct expression *dest;
445 dest = get_argument_from_call_expr(expr->args, param);
446 dest = strip_expr(dest);
447 if (!dest)
448 return;
449 tag_as_user_data(dest);
452 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
454 set_state_expr(my_id, expr->left, &user_data_set);
457 static void match_caller_info(struct expression *expr)
459 struct expression *tmp;
460 int i;
462 i = 0;
463 FOR_EACH_PTR(expr->args, tmp) {
464 if (is_user_data(tmp))
465 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
466 i++;
467 } END_FOR_EACH_PTR(tmp);
470 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
472 if (state == &capped)
473 return;
474 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
477 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
479 if (state == &capped)
480 return;
481 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
484 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
486 struct stree *stree;
487 struct sm_state *tmp;
488 int param;
489 int user_data;
490 const char *passed_or_new;
492 user_data = is_user_data(expr);
493 if (user_data == PASSED_DATA) {
494 sql_insert_return_states(return_id, return_ranges, USER_DATA,
495 -1, "$$", "2");
497 if (user_data == SET_DATA) {
498 sql_insert_return_states(return_id, return_ranges, USER_DATA,
499 -1, "$$", "1");
502 stree = __get_cur_stree();
504 FOR_EACH_MY_SM(my_id, stree, tmp) {
505 const char *param_name;
507 param = get_param_num_from_sym(tmp->sym);
508 if (param < 0)
509 continue;
511 if (is_capped_var_sym(tmp->name, tmp->sym))
512 continue;
513 /* ignore states that were already USER_DATA to begin with */
514 if (get_state_stree(get_start_states(), my_id, tmp->name, tmp->sym))
515 continue;
517 param_name = get_param_name(tmp);
518 if (!param_name || strcmp(param_name, "$$") == 0)
519 continue;
521 if (slist_has_state(tmp->possible, &user_data_set))
522 passed_or_new = "1";
523 else if (slist_has_state(tmp->possible, &user_data_passed))
524 passed_or_new = "2";
525 else
526 continue;
528 sql_insert_return_states(return_id, return_ranges, USER_DATA,
529 param, param_name, passed_or_new);
530 } END_FOR_EACH_SM(tmp);
533 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
535 char *name;
536 struct symbol *sym;
538 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$$") == 0) {
539 tag_as_user_data(expr->left);
540 return;
543 name = return_state_to_var_sym(expr, param, key, &sym);
544 if (!name || !sym)
545 goto free;
547 set_state(my_id, name, sym, &user_data_set);
548 free:
549 free_string(name);
552 void check_user_data(int id)
554 if (option_project != PROJ_KERNEL)
555 return;
556 my_id = id;
557 select_caller_info_hook(set_param_user_data, USER_DATA);
558 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
559 add_hook(&match_condition, CONDITION_HOOK);
560 add_hook(&match_assign, ASSIGNMENT_HOOK);
561 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
562 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
563 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
564 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
566 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
567 add_member_info_callback(my_id, struct_member_callback);
568 add_returned_member_callback(my_id, returned_member_callback);
569 add_split_return_callback(print_returned_user_data);
570 select_return_states_hook(USER_DATA, &db_return_states_userdata);