comparison: create expr_equal/lte_to_param() functions
[smatch.git] / check_user_data.c
blobcd8df95ab9bc60e477438ee9e2a0c9a7417699ae
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);
26 static int is_user_macro(struct expression *expr)
28 return 0;
31 static int db_user_data;
32 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
34 db_user_data = 1;
35 return 0;
38 static int passes_user_data(struct expression *expr)
40 struct expression *arg;
42 FOR_EACH_PTR(expr->args, arg) {
43 if (is_user_data(arg))
44 return 1;
45 } END_FOR_EACH_PTR(arg);
47 return 0;
50 static int is_user_fn_db(struct expression *expr)
52 struct symbol *sym;
53 static char sql_filter[1024];
55 if (expr->fn->type != EXPR_SYMBOL)
56 return 0;
57 sym = expr->fn->symbol;
58 if (!sym)
59 return 0;
61 if (!passes_user_data(expr))
62 return 0;
64 if (sym->ctype.modifiers & MOD_STATIC) {
65 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
66 get_filename(), sym->ident->name);
67 } else {
68 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
69 sym->ident->name);
72 db_user_data = 0;
73 run_sql(db_user_data_callback, "select value from return_states where type=%d and %s",
74 USER_DATA, sql_filter);
75 return db_user_data;
78 static int is_user_function(struct expression *expr)
80 if (expr->type != EXPR_CALL)
81 return 0;
82 if (sym_name_is("kmemdup_user", expr->fn))
83 return 1;
84 return is_user_fn_db(expr);
87 static int is_skb_data(struct expression *expr)
89 struct symbol *sym;
90 char *name;
91 int len;
92 int ret = 0;
94 name = expr_to_var_sym(expr, &sym);
95 if (!name || !sym)
96 goto free;
98 sym = get_base_type(sym);
99 if (!sym || sym->type != SYM_PTR)
100 goto free;
101 sym = get_base_type(sym);
102 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
103 goto free;
104 if (strcmp(sym->ident->name, "sk_buff") != 0)
105 goto free;
107 len = strlen(name);
108 if (len < 6)
109 goto free;
110 if (strcmp(name + len - 6, "->data") == 0)
111 ret = 1;
113 free:
114 free_string(name);
115 return ret;
118 static int in_container_of_macro(struct expression *expr)
120 char *macro;
122 macro = get_macro_name(expr->pos);
124 if (!macro)
125 return 0;
126 if (strcmp(macro, "container_of") == 0)
127 return 1;
128 return 0;
131 static int is_user_data_state(struct expression *expr)
133 struct state_list *slist = NULL;
134 struct sm_state *tmp;
135 struct symbol *sym;
136 char *name;
137 int user = 0;
139 tmp = get_sm_state_expr(my_id, expr);
140 if (tmp)
141 return slist_has_state(tmp->possible, &user_data);
143 name = expr_to_str_sym(expr, &sym);
144 if (!name || !sym)
145 goto free;
147 slist = get_all_states(my_id);
148 FOR_EACH_PTR(slist, tmp) {
149 if (tmp->sym != sym)
150 continue;
151 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
152 if (slist_has_state(tmp->possible, &user_data))
153 user = 1;
154 goto free;
156 } END_FOR_EACH_PTR(tmp);
158 free:
159 free_slist(&slist);
160 free_string(name);
161 return user;
164 int is_user_data(struct expression *expr)
166 if (!expr)
167 return 0;
169 if (is_capped(expr))
170 return 0;
171 if (in_container_of_macro(expr))
172 return 0;
174 if (is_user_macro(expr))
175 return 1;
176 if (is_user_function(expr))
177 return 1;
178 if (is_skb_data(expr))
179 return 1;
181 expr = strip_expr(expr); /* this has to come after is_user_macro() */
183 if (expr->type == EXPR_BINOP) {
184 if (is_user_data(expr->left))
185 return 1;
186 if (is_array(expr))
187 return 0;
188 if (is_user_data(expr->right))
189 return 1;
190 return 0;
192 if (expr->type == EXPR_PREOP && (expr->op == '&' || expr->op == '*'))
193 expr = strip_expr(expr->unop);
195 return is_user_data_state(expr);
198 int is_capped_user_data(struct expression *expr)
200 struct sm_state *sm;
202 sm = get_sm_state_expr(my_id, expr);
203 if (!sm)
204 return 0;
205 if (slist_has_state(sm->possible, &capped))
206 return 1;
207 return 0;
210 void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
212 char fullname[256];
214 /* sanity check. this should always be true. */
215 if (strncmp(key, "$$", 2) != 0)
216 return;
217 snprintf(fullname, 256, "%s%s", name, key + 2);
218 set_state(my_id, fullname, sym, &user_data);
221 static void match_syscall_definition(struct symbol *sym)
223 struct symbol *arg;
224 char *macro;
226 macro = get_macro_name(sym->pos);
227 if (!macro)
228 return;
229 if (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) != 0 &&
230 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) != 0)
231 return;
233 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
234 set_state(my_id, arg->ident->name, arg, &user_data);
235 } END_FOR_EACH_PTR(arg);
238 static void match_condition(struct expression *expr)
240 switch (expr->op) {
241 case '<':
242 case SPECIAL_LTE:
243 case SPECIAL_UNSIGNED_LT:
244 case SPECIAL_UNSIGNED_LTE:
245 if (is_user_data(expr->left))
246 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
247 if (is_user_data(expr->right))
248 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
249 break;
250 case '>':
251 case SPECIAL_GTE:
252 case SPECIAL_UNSIGNED_GT:
253 case SPECIAL_UNSIGNED_GTE:
254 if (is_user_data(expr->right))
255 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
256 if (is_user_data(expr->left))
257 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
258 break;
259 case SPECIAL_EQUAL:
260 if (is_user_data(expr->left))
261 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
262 if (is_user_data(expr->right))
263 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
264 break;
265 case SPECIAL_NOTEQUAL:
266 if (is_user_data(expr->left))
267 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
268 if (is_user_data(expr->right))
269 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
270 break;
271 default:
272 return;
276 static void match_normal_assign(struct expression *expr)
278 if (is_user_data(expr->right))
279 set_state_expr(my_id, expr->left, &user_data);
280 if (expr->op != '=')
281 return;
282 if (is_user_data(expr->left))
283 set_state_expr(my_id, expr->left, &capped);
286 static void match_assign(struct expression *expr)
288 char *name;
290 name = get_macro_name(expr->pos);
291 if (!name || strcmp(name, "get_user") != 0) {
292 match_normal_assign(expr);
293 return;
295 name = expr_to_var(expr->right);
296 if (!name || strcmp(name, "__val_gu") != 0)
297 goto free;
298 set_state_expr(my_id, expr->left, &user_data);
299 free:
300 free_string(name);
303 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
305 int param = PTR_INT(_param);
306 struct expression *dest;
308 dest = get_argument_from_call_expr(expr->args, param);
309 dest = strip_expr(dest);
310 if (!dest)
311 return;
312 /* the first thing I tested this on pass &foo to a function */
313 set_state_expr(my_id, dest, &user_data);
314 if (dest->type == EXPR_PREOP && dest->op == '&') {
315 /* but normally I'd think it would pass the actual variable */
316 dest = dest->unop;
317 set_state_expr(my_id, dest, &user_data);
321 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
323 set_state_expr(my_id, expr->left, &user_data);
326 static void match_assign_userdata(struct expression *expr)
328 if (is_user_data(expr->right))
329 set_state_expr(my_id, expr->left, &user_data);
332 static void match_caller_info(struct expression *expr)
334 struct expression *tmp;
335 int i;
337 i = 0;
338 FOR_EACH_PTR(expr->args, tmp) {
339 if (is_user_data(tmp))
340 sql_insert_caller_info(expr, USER_DATA, i, "$$", "1");
341 i++;
342 } END_FOR_EACH_PTR(tmp);
345 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state)
347 if (state == &capped)
348 return;
349 sql_insert_caller_info(call, USER_DATA, param, printed_name, "1");
352 static void print_returned_user_data(int return_id, char *return_ranges, struct expression *expr)
354 if (is_user_data(expr)) {
355 sql_insert_return_states(return_id, return_ranges, USER_DATA,
356 -1, "", "");
360 void check_user_data(int id)
362 if (option_project != PROJ_KERNEL)
363 return;
364 my_id = id;
365 add_definition_db_callback(set_param_user_data, USER_DATA);
366 add_hook(&match_syscall_definition, FUNC_DEF_HOOK);
367 add_hook(&match_condition, CONDITION_HOOK);
368 add_hook(&match_assign, ASSIGNMENT_HOOK);
369 add_hook(&match_assign_userdata, ASSIGNMENT_HOOK);
370 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
371 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
372 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
373 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
375 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
376 add_member_info_callback(my_id, struct_member_callback);
377 add_returned_state_callback(print_returned_user_data);