user_data: skb->data is user data
[smatch.git] / check_user_data.c
blobbc737af660223bfff327ea1de1bf1c2fff2bb9fa
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_skb_data(struct expression *expr)
28 struct symbol *sym;
29 char *name;
30 int len;
31 int ret = 0;
33 name = get_variable_from_expr(expr, &sym);
34 if (!name || !sym)
35 goto free;
37 sym = get_base_type(sym);
38 if (!sym || sym->type != SYM_PTR)
39 goto free;
40 sym = get_base_type(sym);
41 if (!sym || sym->type != SYM_STRUCT || !sym->ident)
42 goto free;
43 if (strcmp(sym->ident->name, "sk_buff") != 0)
44 goto free;
46 len = strlen(name);
47 if (len < 6)
48 goto free;
49 if (strcmp(name + len - 6, "->data") == 0)
50 ret = 1;
52 free:
53 free_string(name);
54 return ret;
57 int is_user_data(struct expression *expr)
59 struct state_list *slist = NULL;
60 struct sm_state *tmp;
61 struct symbol *sym;
62 char *name;
63 int user = 0;
65 expr = strip_expr(expr);
66 if (!expr)
67 return 0;
68 if (is_capped(expr))
69 return 0;
70 if (is_skb_data(expr))
71 return 1;
72 if (expr->type == EXPR_BINOP) {
73 if (is_user_data(expr->left))
74 return 1;
75 if (is_user_data(expr->right))
76 return 1;
77 return 0;
79 if (expr->type == EXPR_PREOP && expr->op == '&')
80 expr = strip_expr(expr->unop);
82 tmp = get_sm_state_expr(my_id, expr);
83 if (tmp)
84 return slist_has_state(tmp->possible, &user_data);
86 name = get_variable_from_expr_complex(expr, &sym);
87 if (!name || !sym)
88 goto free;
90 slist = get_all_states(my_id);
91 FOR_EACH_PTR(slist, tmp) {
92 if (tmp->sym != sym)
93 continue;
94 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
95 if (slist_has_state(tmp->possible, &user_data))
96 user = 1;
97 goto free;
99 } END_FOR_EACH_PTR(tmp);
101 free:
102 free_slist(&slist);
103 free_string(name);
104 return user;
107 void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
109 char fullname[256];
111 if (strncmp(key, "$$", 2))
112 return;
113 snprintf(fullname, 256, "%s%s", name, key + 2);
114 set_state(my_id, fullname, sym, &user_data);
117 static void match_condition(struct expression *expr)
119 switch (expr->op) {
120 case '<':
121 case SPECIAL_LTE:
122 case SPECIAL_UNSIGNED_LT:
123 case SPECIAL_UNSIGNED_LTE:
124 if (is_user_data(expr->left))
125 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
126 if (is_user_data(expr->right))
127 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
128 break;
129 case '>':
130 case SPECIAL_GTE:
131 case SPECIAL_UNSIGNED_GT:
132 case SPECIAL_UNSIGNED_GTE:
133 if (is_user_data(expr->right))
134 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
135 if (is_user_data(expr->left))
136 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
137 break;
138 case SPECIAL_EQUAL:
139 if (is_user_data(expr->left))
140 set_true_false_states_expr(my_id, expr->left, &capped, NULL);
141 if (is_user_data(expr->right))
142 set_true_false_states_expr(my_id, expr->right, &capped, NULL);
143 break;
144 case SPECIAL_NOTEQUAL:
145 if (is_user_data(expr->left))
146 set_true_false_states_expr(my_id, expr->left, NULL, &capped);
147 if (is_user_data(expr->right))
148 set_true_false_states_expr(my_id, expr->right, NULL, &capped);
149 break;
150 default:
151 return;
156 static void match_normal_assign(struct expression *expr)
158 if (is_user_data(expr->left))
159 set_state_expr(my_id, expr->left, &capped);
162 static void match_assign(struct expression *expr)
164 char *name;
166 name = get_macro_name(expr->pos);
167 if (!name || strcmp(name, "get_user") != 0) {
168 match_normal_assign(expr);
169 return;
171 name = get_variable_from_expr(expr->right, NULL);
172 if (!name || strcmp(name, "__val_gu") != 0)
173 goto free;
174 set_state_expr(my_id, expr->left, &user_data);
175 free:
176 free_string(name);
179 static void match_user_copy(const char *fn, struct expression *expr, void *_param)
181 int param = PTR_INT(_param);
182 struct expression *dest;
184 dest = get_argument_from_call_expr(expr->args, param);
185 dest = strip_expr(dest);
186 if (!dest)
187 return;
188 /* the first thing I tested this on pass &foo to a function */
189 set_state_expr(my_id, dest, &user_data);
190 if (dest->type == EXPR_PREOP && dest->op == '&') {
191 /* but normally I'd think it would pass the actual variable */
192 dest = dest->unop;
193 set_state_expr(my_id, dest, &user_data);
197 static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
199 set_state_expr(my_id, expr->left, &user_data);
202 static void match_assign_userdata(struct expression *expr)
204 if (is_user_data(expr->right))
205 set_state_expr(my_id, expr->left, &user_data);
208 static void match_caller_info(struct expression *expr)
210 struct expression *tmp;
211 char *func;
212 int i;
214 func = get_fnptr_name(expr->fn);
215 if (!func)
216 return;
218 i = 0;
219 FOR_EACH_PTR(expr->args, tmp) {
220 if (is_user_data(tmp))
221 sm_msg("info: passes user_data %s %d '$$' %s", func, i,
222 is_static(expr->fn) ? "static" : "global");
223 i++;
224 } END_FOR_EACH_PTR(tmp);
227 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
229 if (state == &capped)
230 return;
231 sm_msg("info: passes user_data '%s' %d '%s' %s", fn, param, printed_name, global_static);
234 static void match_return(struct expression *expr)
236 if (is_user_data(expr))
237 sm_msg("info: returns_user_data %s", global_static());
240 static int db_user_data;
241 static int db_user_data_callback(void *unused, int argc, char **argv, char **azColName)
243 db_user_data = 1;
244 return 0;
247 static int passes_user_data(struct expression *expr)
249 struct expression *arg;
251 FOR_EACH_PTR(expr->args, arg) {
252 if (is_user_data(arg))
253 return 1;
254 } END_FOR_EACH_PTR(arg);
256 return 0;
259 static void match_call_assignment(struct expression *expr)
261 struct symbol *sym;
262 static char sql_filter[1024];
264 if (expr->right->fn->type != EXPR_SYMBOL)
265 return;
266 sym = expr->right->fn->symbol;
267 if (!sym)
268 return;
270 if (!passes_user_data(expr->right))
271 return;
273 if (sym->ctype.modifiers & MOD_STATIC) {
274 snprintf(sql_filter, 1024, "file = '%s' and function = '%s' and type = %d;",
275 get_filename(), sym->ident->name, USER_DATA);
276 } else {
277 snprintf(sql_filter, 1024, "function = '%s' and static = 0 and type = %d;",
278 sym->ident->name, USER_DATA);
281 db_user_data = 0;
282 run_sql(db_user_data_callback, "select value from return_info where %s",
283 sql_filter);
284 if (db_user_data)
285 set_state_expr(my_id, expr->left, &user_data);
288 void check_user_data(int id)
290 if (option_project != PROJ_KERNEL)
291 return;
292 my_id = id;
293 add_definition_db_callback(set_param_user_data, USER_DATA);
294 add_hook(match_call_assignment, CALL_ASSIGNMENT_HOOK);
295 add_hook(&match_condition, CONDITION_HOOK);
296 add_hook(&match_assign, ASSIGNMENT_HOOK);
297 add_hook(&match_assign_userdata, ASSIGNMENT_HOOK);
298 add_function_hook("copy_from_user", &match_user_copy, INT_PTR(0));
299 add_function_hook("__copy_from_user", &match_user_copy, INT_PTR(0));
300 add_function_hook("memcpy_fromiovec", &match_user_copy, INT_PTR(0));
301 add_function_assign_hook("kmemdup_user", &match_user_assign_function, NULL);
302 if (option_info) {
303 add_hook(&match_caller_info, FUNCTION_CALL_HOOK);
304 add_member_info_callback(my_id, struct_member_callback);
305 add_hook(&match_return, RETURN_HOOK);