Print this page
11972 resync smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_rosenberg.c
+++ new/usr/src/tools/smatch/src/check_rosenberg.c
1 1 /*
2 2 * Copyright (C) 2011 Dan Carpenter.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /* Does a search for Dan Rosenberg style info leaks */
19 19
20 20 /* fixme: struct includes a struct with a hole in it */
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
21 21 /* function is called that clears the struct */
22 22
23 23 #include "scope.h"
24 24 #include "smatch.h"
25 25 #include "smatch_function_hashtable.h"
26 26 #include "smatch_slist.h"
27 27 #include "smatch_extra.h"
28 28
29 29 static int my_whole_id;
30 30 static int my_member_id;
31 +static int skb_put_id;
31 32
32 33 STATE(cleared);
33 34
34 35 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
35 36 {
36 37 struct symbol *type;
37 38
38 39 type = get_real_base_type(sym);
39 40 if (!type || type->type != SYM_STRUCT)
40 41 return;
41 42
42 43 set_state(my_member_id, name, sym, state);
43 44 }
44 45
45 46 static void print_holey_warning(struct expression *data, const char *member)
46 47 {
47 48 char *name;
48 49
49 50 name = expr_to_str(data);
50 51 if (member) {
51 52 sm_warning("check that '%s' doesn't leak information (struct has a hole after '%s')",
52 53 name, member);
53 54 } else {
54 55 sm_warning("check that '%s' doesn't leak information (struct has holes)",
55 56 name);
56 57 }
57 58 free_string(name);
58 59 }
59 60
60 61 static int check_struct(struct expression *expr, struct symbol *type)
61 62 {
62 63 struct symbol *tmp, *base_type;
63 64 const char *prev = NULL;
64 65 int align;
65 66
66 67 if (type->ctype.alignment == 1)
67 68 return 0;
68 69
69 70 align = 0;
70 71 FOR_EACH_PTR(type->symbol_list, tmp) {
71 72 base_type = get_real_base_type(tmp);
72 73 if (base_type && base_type->type == SYM_STRUCT) {
73 74 if (check_struct(expr, base_type))
74 75 return 1;
75 76 }
76 77
77 78 if (!tmp->ctype.alignment) {
78 79 sm_perror("cannot determine the alignment here");
79 80 } else if (align % tmp->ctype.alignment) {
80 81 print_holey_warning(expr, prev);
81 82 return 1;
82 83 }
83 84
84 85 if (base_type == &bool_ctype)
85 86 align += 1;
86 87 else if (type_bits(tmp) <= 0)
87 88 align = 0;
88 89 else
89 90 align += type_bytes(tmp);
90 91
91 92 if (tmp->ident)
92 93 prev = tmp->ident->name;
93 94 else
94 95 prev = NULL;
95 96 } END_FOR_EACH_PTR(tmp);
96 97
97 98 if (align % type->ctype.alignment) {
98 99 print_holey_warning(expr, prev);
99 100 return 1;
100 101 }
101 102
102 103 return 0;
103 104 }
104 105
105 106 static int warn_on_holey_struct(struct expression *expr)
106 107 {
107 108 struct symbol *type;
108 109 type = get_type(expr);
109 110 if (!type || type->type != SYM_STRUCT)
110 111 return 0;
111 112
112 113 return check_struct(expr, type);
113 114 }
114 115
115 116 static int has_global_scope(struct expression *expr)
116 117 {
↓ open down ↓ |
76 lines elided |
↑ open up ↑ |
117 118 struct symbol *sym;
118 119
119 120 if (expr->type != EXPR_SYMBOL)
120 121 return FALSE;
121 122 sym = expr->symbol;
122 123 if (!sym)
123 124 return FALSE;
124 125 return toplevel(sym->scope);
125 126 }
126 127
127 -static int was_initialized(struct expression *expr)
128 -{
129 - struct symbol *sym;
130 - char *name;
131 -
132 - name = expr_to_var_sym(expr, &sym);
133 - if (!name)
134 - return 0;
135 - if (sym->initializer)
136 - return 1;
137 - return 0;
138 -}
139 -
140 128 static void match_clear(const char *fn, struct expression *expr, void *_arg_no)
141 129 {
142 130 struct expression *ptr;
143 131 int arg_no = PTR_INT(_arg_no);
144 132
145 133 ptr = get_argument_from_call_expr(expr->args, arg_no);
146 134 if (!ptr)
147 135 return;
148 136 ptr = strip_expr(ptr);
149 137 if (ptr->type != EXPR_PREOP || ptr->op != '&')
150 138 return;
151 139 ptr = strip_expr(ptr->unop);
152 140 set_state_expr(my_whole_id, ptr, &cleared);
153 141 }
154 142
155 143 static int was_memset(struct expression *expr)
156 144 {
157 145 if (get_state_expr(my_whole_id, expr) == &cleared)
158 146 return 1;
159 147 return 0;
160 148 }
161 149
162 150 static int member_initialized(char *name, struct symbol *outer, struct symbol *member, int pointer)
163 151 {
164 152 char buf[256];
165 153 struct symbol *base;
166 154
167 155 base = get_base_type(member);
168 156 if (!base || base->type != SYM_BASETYPE || !member->ident)
169 157 return FALSE;
170 158
171 159 if (pointer)
172 160 snprintf(buf, 256, "%s->%s", name, member->ident->name);
173 161 else
174 162 snprintf(buf, 256, "%s.%s", name, member->ident->name);
175 163
176 164 if (get_state(my_member_id, buf, outer))
177 165 return TRUE;
178 166
179 167 return FALSE;
180 168 }
181 169
182 170 static int member_uninitialized(char *name, struct symbol *outer, struct symbol *member, int pointer)
183 171 {
184 172 char buf[256];
185 173 struct symbol *base;
186 174 struct sm_state *sm;
187 175
188 176 base = get_base_type(member);
189 177 if (!base || base->type != SYM_BASETYPE || !member->ident)
190 178 return FALSE;
191 179
192 180 if (pointer)
193 181 snprintf(buf, 256, "%s->%s", name, member->ident->name);
194 182 else
195 183 snprintf(buf, 256, "%s.%s", name, member->ident->name);
196 184
197 185 sm = get_sm_state(my_member_id, buf, outer);
198 186 if (sm && !slist_has_state(sm->possible, &undefined))
199 187 return FALSE;
200 188
201 189 sm_warning("check that '%s' doesn't leak information", buf);
202 190 return TRUE;
203 191 }
204 192
205 193 static int check_members_initialized(struct expression *expr)
206 194 {
207 195 char *name;
208 196 struct symbol *outer;
209 197 struct symbol *sym;
210 198 struct symbol *tmp;
211 199 int pointer = 0;
212 200 int printed = 0;
213 201
214 202 sym = get_type(expr);
215 203 if (sym && sym->type == SYM_PTR) {
216 204 pointer = 1;
217 205 sym = get_real_base_type(sym);
218 206 }
219 207 if (!sym)
220 208 return 0;
221 209 if (sym->type != SYM_STRUCT)
222 210 return 0;
223 211
224 212 name = expr_to_var_sym(expr, &outer);
225 213
226 214 /*
227 215 * check that at least one member was set. If all of them were not set
228 216 * it's more likely a problem in the check than a problem in the kernel
229 217 * code.
230 218 */
231 219 FOR_EACH_PTR(sym->symbol_list, tmp) {
232 220 if (member_initialized(name, outer, tmp, pointer))
233 221 goto check;
234 222 } END_FOR_EACH_PTR(tmp);
235 223 goto out;
236 224
237 225 check:
238 226 FOR_EACH_PTR(sym->symbol_list, tmp) {
239 227 if (member_uninitialized(name, outer, tmp, pointer)) {
240 228 printed = 1;
241 229 goto out;
242 230 }
243 231 } END_FOR_EACH_PTR(tmp);
244 232 out:
245 233 free_string(name);
246 234 return printed;
247 235 }
248 236
249 237 static void check_was_initialized(struct expression *data)
250 238 {
↓ open down ↓ |
101 lines elided |
↑ open up ↑ |
251 239 data = strip_expr(data);
252 240 if (!data)
253 241 return;
254 242 if (data->type == EXPR_PREOP && data->op == '&')
255 243 data = strip_expr(data->unop);
256 244 if (data->type != EXPR_SYMBOL)
257 245 return;
258 246
259 247 if (has_global_scope(data))
260 248 return;
261 - if (was_initialized(data))
249 + if (was_memset(data))
262 250 return;
251 + if (warn_on_holey_struct(data))
252 + return;
253 + check_members_initialized(data);
254 +}
255 +
256 +static void check_skb_put(struct expression *data)
257 +{
258 + data = strip_expr(data);
259 + if (!data)
260 + return;
261 + if (data->type == EXPR_PREOP && data->op == '&')
262 + data = strip_expr(data->unop);
263 +
263 264 if (was_memset(data))
264 265 return;
265 266 if (warn_on_holey_struct(data))
266 267 return;
267 268 check_members_initialized(data);
268 269 }
269 270
270 271 static void match_copy_to_user(const char *fn, struct expression *expr, void *_arg)
271 272 {
272 273 int arg = PTR_INT(_arg);
273 274 struct expression *data;
274 275
275 276 data = get_argument_from_call_expr(expr->args, arg);
276 277 data = strip_expr(data);
277 278 if (!data)
278 279 return;
279 280 if (data->type != EXPR_PREOP || data->op != '&')
280 281 return;
281 282 check_was_initialized(data);
282 283 }
283 284
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
284 285 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
285 286 {
286 287 while (expr->type == EXPR_ASSIGNMENT)
287 288 expr = strip_expr(expr->right);
288 289 if (expr->type != EXPR_CALL)
289 290 return;
290 291
291 292 match_clear(NULL, expr, INT_PTR(param));
292 293 }
293 294
294 -static void match_assign(struct expression *expr)
295 +static struct smatch_state *alloc_expr_state(struct expression *expr)
295 296 {
297 + struct smatch_state *state;
298 + char *name;
299 +
300 + name = expr_to_str(expr);
301 + if (!name)
302 + return NULL;
303 +
304 + state = __alloc_smatch_state(0);
305 + expr = strip_expr(expr);
306 + state->name = alloc_sname(name);
307 + free_string(name);
308 + state->data = expr;
309 + return state;
310 +}
311 +
312 +static void match_skb_put(const char *fn, struct expression *expr, void *unused)
313 +{
296 314 struct symbol *type;
315 + struct smatch_state *state;
297 316
298 317 type = get_type(expr->left);
318 + type = get_real_base_type(type);
299 319 if (!type || type->type != SYM_STRUCT)
300 320 return;
301 - set_state_expr(my_whole_id, expr->left, &cleared);
321 + state = alloc_expr_state(expr->left);
322 + set_state_expr(skb_put_id, expr->left, state);
302 323 }
303 324
325 +static void match_return_skb_put(struct expression *expr)
326 +{
327 + struct sm_state *sm;
328 + struct stree *stree;
329 +
330 + if (is_error_return(expr))
331 + return;
332 +
333 + stree = __get_cur_stree();
334 +
335 + FOR_EACH_MY_SM(skb_put_id, stree, sm) {
336 + check_skb_put(sm->state->data);
337 + } END_FOR_EACH_SM(sm);
338 +}
339 +
304 340 static void register_clears_argument(void)
305 341 {
306 342 struct token *token;
307 343 const char *func;
308 344 int arg;
309 345
310 346 token = get_tokens_file("kernel.clears_argument");
311 347 if (!token)
312 348 return;
313 349 if (token_type(token) != TOKEN_STREAMBEGIN)
314 350 return;
315 351 token = token->next;
316 352 while (token_type(token) != TOKEN_STREAMEND) {
317 353 if (token_type(token) != TOKEN_IDENT)
318 354 return;
319 355 func = show_ident(token->ident);
320 356 token = token->next;
321 357 if (token_type(token) != TOKEN_NUMBER)
322 358 return;
323 359 arg = atoi(token->number);
324 360
325 361 add_function_hook(func, &match_clear, INT_PTR(arg));
326 362 token = token->next;
327 363 }
328 364 clear_token_alloc();
329 365 }
330 366
331 367 static void register_copy_funcs_from_file(void)
332 368 {
333 369 struct token *token;
334 370 const char *func;
335 371 int arg;
336 372
337 373 token = get_tokens_file("kernel.rosenberg_funcs");
338 374 if (!token)
339 375 return;
340 376 if (token_type(token) != TOKEN_STREAMBEGIN)
341 377 return;
342 378 token = token->next;
343 379 while (token_type(token) != TOKEN_STREAMEND) {
344 380 if (token_type(token) != TOKEN_IDENT)
345 381 return;
346 382 func = show_ident(token->ident);
347 383 token = token->next;
348 384 if (token_type(token) != TOKEN_NUMBER)
349 385 return;
350 386 arg = atoi(token->number);
351 387 add_function_hook(func, &match_copy_to_user, INT_PTR(arg));
352 388 token = token->next;
353 389 }
354 390 clear_token_alloc();
355 391 }
356 392
357 393 void check_rosenberg(int id)
358 394 {
359 395 if (option_project != PROJ_KERNEL)
360 396 return;
361 397 my_whole_id = id;
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
362 398
363 399 add_function_hook("memset", &match_clear, INT_PTR(0));
364 400 add_function_hook("memcpy", &match_clear, INT_PTR(0));
365 401 add_function_hook("memzero", &match_clear, INT_PTR(0));
366 402 add_function_hook("__memset", &match_clear, INT_PTR(0));
367 403 add_function_hook("__memcpy", &match_clear, INT_PTR(0));
368 404 add_function_hook("__memzero", &match_clear, INT_PTR(0));
369 405 add_function_hook("__builtin_memset", &match_clear, INT_PTR(0));
370 406 add_function_hook("__builtin_memcpy", &match_clear, INT_PTR(0));
371 407
372 - add_hook(&match_assign, ASSIGNMENT_HOOK);
373 408 register_clears_argument();
374 409 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
375 410
376 411 register_copy_funcs_from_file();
377 412 }
378 413
379 414 void check_rosenberg2(int id)
380 415 {
381 416 if (option_project != PROJ_KERNEL)
382 417 return;
383 418
384 419 my_member_id = id;
385 420 set_dynamic_states(my_member_id);
386 421 add_extra_mod_hook(&extra_mod_hook);
387 422 }
388 423
424 +void check_rosenberg3(int id)
425 +{
426 + if (option_project != PROJ_KERNEL)
427 + return;
428 +
429 + skb_put_id = id;
430 + set_dynamic_states(skb_put_id);
431 + add_function_assign_hook("skb_put", &match_skb_put, NULL);
432 + add_hook(&match_return_skb_put, RETURN_HOOK);
433 +}
434 +
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX