slist: delete slist compat layer and remaining unused functions
[smatch.git] / check_user_data.c
blob40b2c2430591eb4434e9031c8711c2e72929de32
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, struct AVL *my_stree)
60 struct sm_state *sm;
61 struct symbol *sym;
62 char *name;
64 expr = strip_expr(expr);
65 if (expr->type == EXPR_PREOP && expr->op == '&')
66 expr = strip_expr(expr->unop);
68 name = expr_to_str_sym(expr, &sym);
69 free_string(name);
70 if (!sym)
71 return 1;
73 FOR_EACH_SM(my_stree, sm) {
74 if (sm->sym == sym)
75 return 1;
76 } END_FOR_EACH_SM(sm);
77 return 0;
80 static int passes_user_data(struct expression *expr)
82 struct AVL *stree;
83 struct expression *arg;
85 stree = get_all_states_stree(my_id);
86 FOR_EACH_PTR(expr->args, arg) {
87 if (is_user_data(arg))
88 return 1;
89 if (has_user_data_state(arg, stree))
90 return 1;
91 } END_FOR_EACH_PTR(arg);
92 free_stree(&stree);
94 return 0;
97 static struct expression *db_expr;
98 static int db_user_data;
99 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
101 if (atoi(argv[0]) == PASSED_DATA && !passes_user_data(db_expr))
102 return 0;
103 db_user_data = 1;
104 return 0;
107 static int is_user_fn_db(struct expression *expr)
109 struct symbol *sym;
110 static char sql_filter[1024];
112 if (is_fake_call(expr))
113 return 0;
114 if (expr->fn->type != EXPR_SYMBOL)
115 return 0;
116 sym = expr->fn->symbol;
117 if (!sym)
118 return 0;
120 if (sym->ctype.modifiers & MOD_STATIC) {
121 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
122 get_filename(), sym->ident->name);
123 } else {
124 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
125 sym->ident->name);
128 db_expr = expr;
129 db_user_data = 0;
130 run_sql(db_user_data_callback,
131 "select value from return_states where type=%d and parameter = -1 and key = '$$' and %s",
132 USER_DATA, sql_filter);
133 return db_user_data;
136 static int is_user_function(struct expression *expr)
138 if (expr->type != EXPR_CALL)
139 return 0;
140 return is_user_fn_db(expr);
143 static int is_skb_data(struct expression *expr)
145 struct symbol *sym;
146 char *name;
147 int len;
148 int ret = 0;
150 name = expr_to_var_sym(expr, &sym);
151 if (!name || !sym)
152 goto free;
154 sym = get_base_type(sym);
155 if (!sym || sym->type != SYM_PTR)
156 goto free;
157 sym = get_base_type(sym);
158 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
159 goto free;
160 if (strcmp(sym->ident->name, "sk_buff") != 0)
161 goto free;
163 len = strlen(name);
164 if (len < 6)
165 goto free;
166 if (strcmp(name + len - 6, "->data") == 0)
167 ret = SET_DATA;
169 free:
170 free_string(name);
171 return ret;
174 static int in_container_of_macro(struct expression *expr)
176 char *macro;
178 macro = get_macro_name(expr->pos);
180 if (!macro)
181 return 0;
182 if (strcmp(macro, "container_of") == 0)
183 return 1;
184 return 0;
187 static int is_user_data_state(struct expression *expr)
189 struct AVL *stree = NULL;
190 struct sm_state *tmp;
191 struct symbol *sym;
192 char *name;
193 int user = 0;
195 tmp = get_sm_state_expr(my_id, expr);
196 if (tmp) {
197 if (slist_has_state(tmp->possible, &user_data_set))
198 return SET_DATA;
199 if (slist_has_state(tmp->possible, &user_data_passed))
200 return PASSED_DATA;
201 return 0;
204 name = expr_to_str_sym(expr, &sym);
205 if (!name || !sym)
206 goto free;
208 stree = get_all_states_stree(my_id);
209 FOR_EACH_SM(stree, tmp) {
210 if (tmp->sym != sym)
211 continue;
212 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
213 if (slist_has_state(tmp->possible, &user_data_set))
214 user = SET_DATA;
215 else if (slist_has_state(tmp->possible, &user_data_passed))
216 user = PASSED_DATA;
217 goto free;
219 } END_FOR_EACH_SM(tmp);
221 free:
222 free_stree(&stree);
223 free_string(name);
224 return user;
227 int is_user_data(struct expression *expr)
229 int user_data;
231 if (!expr)
232 return 0;
234 if (is_capped(expr))
235 return 0;
236 if (in_container_of_macro(expr))
237 return 0;
239 user_data = is_user_macro(expr);
240 if (user_data)
241 return user_data;
242 user_data = is_user_function(expr);
243 if (user_data)
244 return user_data;
245 user_data = is_skb_data(expr);
246 if (user_data)
247 return user_data;
249 expr = strip_expr(expr); /* this has to come after is_user_macro() */
251 if (expr->type == EXPR_BINOP) {
252 user_data = is_user_data(expr->left);
253 if (user_data)
254 return user_data;
255 if (is_array(expr))
256 return 0;
257 user_data = is_user_data(expr->right);
258 if (user_data)
259 return user_data;
260 return 0;
262 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
263 expr = strip_expr(expr->unop);
265 return is_user_data_state(expr);
268 int is_capped_user_data(struct expression *expr)
270 struct sm_state *sm;
272 sm = get_sm_state_expr(my_id, expr);
273 if (!sm)
274 return 0;
275 if (slist_has_state(sm->possible, &capped))
276 return 1;
277 return 0;
280 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
282 char fullname[256];
284 /* sanity check. this should always be true. */
285 if (strncmp(key, "$$", 2) != 0)
286 return;
287 snprintf(fullname, 256, "%s%s", name, key + 2);
288 set_state(my_id, fullname, sym, &user_data_passed);
291 static void match_syscall_definition(struct symbol *sym)
293 struct symbol *arg;
294 char *macro;
296 macro = get_macro_name(sym->pos);
297 if (!macro)
298 return;
299 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
300 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
301 return;
303 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
304 set_state(my_id, arg->ident->name, arg, &user_data_set);
305 } END_FOR_EACH_PTR(arg);
308 static void match_condition(struct expression *expr)
310 switch (expr->op) {
311 case '<':
312 case SPECIAL_LTE:
313 case SPECIAL_UNSIGNED_LT:
314 case SPECIAL_UNSIGNED_LTE:
315 if (is_user_data(expr->left))
316 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
317 if (is_user_data(expr->right))
318 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
319 break;
320 case '>':
321 case SPECIAL_GTE:
322 case SPECIAL_UNSIGNED_GT:
323 case SPECIAL_UNSIGNED_GTE:
324 if (is_user_data(expr->right))
325 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
326 if (is_user_data(expr->left))
327 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
328 break;
329 case SPECIAL_EQUAL:
330 if (is_user_data(expr->left))
331 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
332 if (is_user_data(expr->right))
333 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
334 break;
335 case SPECIAL_NOTEQUAL:
336 if (is_user_data(expr->left))
337 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
338 if (is_user_data(expr->right))
339 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
340 break;
341 default:
342 return;
346 static int handle_get_user(struct expression *expr)
348 char *name;
349 int ret = 0;
351 name = get_macro_name(expr->pos);
352 if (!name || strcmp(name, "get_user") != 0)
353 return 0;
355 name = expr_to_var(expr->right);
356 if (!name || strcmp(name, "__val_gu") != 0)
357 goto free;
358 set_state_expr(my_id, expr->left, &user_data_set);
359 ret = 1;
360 free:
361 free_string(name);
362 return ret;
365 static void match_assign(struct expression *expr)
367 int user_data;
369 if (handle_get_user(expr))
370 return;
372 user_data = is_user_data(expr->right);
373 if (user_data == PASSED_DATA)
374 set_state_expr(my_id, expr->left, &user_data_passed);
375 else if (user_data == SET_DATA)
376 set_state_expr(my_id, expr->left, &user_data_set);
377 else if (get_state_expr(my_id, expr->left))
378 set_state_expr(my_id, expr->left, &capped);
381 static void tag_struct_members(struct symbol *type, struct expression *expr)
383 struct symbol *tmp;
384 struct expression *member;
385 int op = '*';
387 if (expr->type == EXPR_PREOP && expr->op == '&') {
388 expr = strip_expr(expr->unop);
389 op = '.';
392 FOR_EACH_PTR(type->symbol_list, tmp) {
393 if (!tmp->ident)
394 continue;
395 member = member_expression(expr, op, tmp->ident);
396 set_state_expr(my_id, member, &user_data_set);
397 } END_FOR_EACH_PTR(tmp);
400 static void tag_base_type(struct expression *expr)
402 if (expr->type == EXPR_PREOP && expr->op == '&')
403 expr = strip_expr(expr->unop);
404 else
405 expr = deref_expression(expr);
406 set_state_expr(my_id, expr, &user_data_set);
409 static void tag_as_user_data(struct expression *expr)
411 struct symbol *type;
413 expr = strip_expr(expr);
415 type = get_type(expr);
416 if (!type || type->type != SYM_PTR)
417 return;
418 type = get_real_base_type(type);
419 if (!type)
420 return;
421 if (type == &void_ctype) {
422 set_state_expr(my_id, deref_expression(expr), &user_data_set);
423 return;
425 if (type->type == SYM_BASETYPE)
426 tag_base_type(expr);
427 if (type->type == SYM_STRUCT) {
428 if (expr->type != EXPR_PREOP || expr->op != '&')
429 expr = deref_expression(expr);
430 tag_struct_members(type, expr);
434 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
436 int param = PTR_INT(_param);
437 struct expression *dest;
439 dest = get_argument_from_call_expr(expr->args, param);
440 dest = strip_expr(dest);
441 if (!dest)
442 return;
443 tag_as_user_data(dest);
446 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
448 set_state_expr(my_id, expr->left, &user_data_set);
451 static void match_caller_info(struct expression *expr)
453 struct expression *tmp;
454 int i;
456 i = 0;
457 FOR_EACH_PTR(expr->args, tmp) {
458 if (is_user_data(tmp))
459 sql_insert_caller_info(expr, USER_DATA, i, "$$", "");
460 i++;
461 } END_FOR_EACH_PTR(tmp);
464 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
466 if (state == &capped)
467 return;
468 sql_insert_caller_info(call, USER_DATA, param, printed_name, "");
471 static void returned_member_callback(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)
473 if (state == &capped)
474 return;
475 sql_insert_return_states(return_id, return_ranges, USER_DATA, -1, printed_name, "");
478 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
480 struct AVL *stree;
481 struct sm_state *tmp;
482 int param;
483 int user_data;
484 const char *passed_or_new;
486 user_data = is_user_data(expr);
487 if (user_data == PASSED_DATA) {
488 sql_insert_return_states(return_id, return_ranges, USER_DATA,
489 -1, "$$", "2");
491 if (user_data == SET_DATA) {
492 sql_insert_return_states(return_id, return_ranges, USER_DATA,
493 -1, "$$", "1");
496 stree = get_all_states_stree(my_id);
498 FOR_EACH_SM(stree, tmp) {
499 const char *param_name;
501 param = get_param_num_from_sym(tmp->sym);
502 if (param < 0)
503 continue;
505 if (is_capped_var_sym(tmp->name, tmp->sym))
506 continue;
507 /* ignore states that were already USER_DATA to begin with */
508 if (get_state_stree(get_start_states(), my_id, tmp->name, tmp->sym))
509 continue;
511 param_name = get_param_name(tmp);
512 if (!param_name || strcmp(param_name, "$$") == 0)
513 continue;
515 if (slist_has_state(tmp->possible, &user_data_set))
516 passed_or_new = "1";
517 else if (slist_has_state(tmp->possible, &user_data_passed))
518 passed_or_new = "2";
519 else
520 continue;
522 sql_insert_return_states(return_id, return_ranges, USER_DATA,
523 param, param_name, passed_or_new);
524 } END_FOR_EACH_SM(tmp);
526 free_stree(&stree);
529 static void db_return_states_userdata(struct expression *expr, int param, char *key, char *value)
531 char *name;
532 struct symbol *sym;
534 if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$$") == 0) {
535 tag_as_user_data(expr->left);
536 return;
539 name = return_state_to_var_sym(expr, param, key, &sym);
540 if (!name || !sym)
541 goto free;
543 set_state(my_id, name, sym, &user_data_set);
544 free:
545 free_string(name);
548 void check_user_data(int id)
550 if (option_project != PROJ_KERNEL)
551 return;
552 my_id = id;
553 select_caller_info_hook(set_param_user_data, USER_DATA);
554 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
555 add_hook(&match_condition, CONDITION_HOOK);
556 add_hook(&match_assign, ASSIGNMENT_HOOK);
557 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
558 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
559 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
560 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
562 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
563 add_member_info_callback(my_id, struct_member_callback);
564 add_returned_member_callback(my_id, returned_member_callback);
565 add_split_return_callback(print_returned_user_data);
566 select_return_states_hook(USER_DATA, &db_return_states_userdata);