Print this page
11506 smatch resync
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 */
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 31
32 32 STATE(cleared);
33 33
34 34 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
35 35 {
36 36 struct symbol *type;
37 37
38 38 type = get_real_base_type(sym);
39 39 if (!type || type->type != SYM_STRUCT)
40 40 return;
41 41
42 42 set_state(my_member_id, name, sym, state);
43 43 }
44 44
45 45 static void print_holey_warning(struct expression *data, const char *member)
46 46 {
47 47 char *name;
48 48
49 49 name = expr_to_str(data);
50 50 if (member) {
51 51 sm_warning("check that '%s' doesn't leak information (struct has a hole after '%s')",
52 52 name, member);
53 53 } else {
54 54 sm_warning("check that '%s' doesn't leak information (struct has holes)",
55 55 name);
56 56 }
57 57 free_string(name);
58 58 }
59 59
60 60 static int check_struct(struct expression *expr, struct symbol *type)
61 61 {
62 62 struct symbol *tmp, *base_type;
63 63 const char *prev = NULL;
64 64 int align;
65 65
66 66 if (type->ctype.alignment == 1)
67 67 return 0;
68 68
69 69 align = 0;
70 70 FOR_EACH_PTR(type->symbol_list, tmp) {
71 71 base_type = get_real_base_type(tmp);
72 72 if (base_type && base_type->type == SYM_STRUCT) {
73 73 if (check_struct(expr, base_type))
74 74 return 1;
75 75 }
76 76
77 77 if (!tmp->ctype.alignment) {
78 78 sm_perror("cannot determine the alignment here");
79 79 } else if (align % tmp->ctype.alignment) {
80 80 print_holey_warning(expr, prev);
81 81 return 1;
82 82 }
83 83
84 84 if (base_type == &bool_ctype)
85 85 align += 1;
86 86 else if (type_bits(tmp) <= 0)
87 87 align = 0;
88 88 else
89 89 align += type_bytes(tmp);
90 90
91 91 if (tmp->ident)
92 92 prev = tmp->ident->name;
93 93 else
94 94 prev = NULL;
95 95 } END_FOR_EACH_PTR(tmp);
96 96
97 97 if (align % type->ctype.alignment) {
98 98 print_holey_warning(expr, prev);
99 99 return 1;
100 100 }
101 101
102 102 return 0;
103 103 }
104 104
105 105 static int warn_on_holey_struct(struct expression *expr)
106 106 {
107 107 struct symbol *type;
108 108 type = get_type(expr);
109 109 if (!type || type->type != SYM_STRUCT)
110 110 return 0;
111 111
112 112 return check_struct(expr, type);
113 113 }
114 114
115 115 static int has_global_scope(struct expression *expr)
116 116 {
117 117 struct symbol *sym;
118 118
119 119 if (expr->type != EXPR_SYMBOL)
120 120 return FALSE;
121 121 sym = expr->symbol;
122 122 if (!sym)
123 123 return FALSE;
124 124 return toplevel(sym->scope);
125 125 }
126 126
127 127 static int was_initialized(struct expression *expr)
128 128 {
129 129 struct symbol *sym;
130 130 char *name;
131 131
132 132 name = expr_to_var_sym(expr, &sym);
133 133 if (!name)
134 134 return 0;
135 135 if (sym->initializer)
136 136 return 1;
137 137 return 0;
138 138 }
139 139
140 140 static void match_clear(const char *fn, struct expression *expr, void *_arg_no)
141 141 {
142 142 struct expression *ptr;
143 143 int arg_no = PTR_INT(_arg_no);
144 144
145 145 ptr = get_argument_from_call_expr(expr->args, arg_no);
146 146 if (!ptr)
147 147 return;
148 148 ptr = strip_expr(ptr);
149 149 if (ptr->type != EXPR_PREOP || ptr->op != '&')
150 150 return;
151 151 ptr = strip_expr(ptr->unop);
152 152 set_state_expr(my_whole_id, ptr, &cleared);
153 153 }
154 154
155 155 static int was_memset(struct expression *expr)
156 156 {
157 157 if (get_state_expr(my_whole_id, expr) == &cleared)
158 158 return 1;
159 159 return 0;
160 160 }
161 161
162 162 static int member_initialized(char *name, struct symbol *outer, struct symbol *member, int pointer)
163 163 {
164 164 char buf[256];
165 165 struct symbol *base;
166 166
167 167 base = get_base_type(member);
168 168 if (!base || base->type != SYM_BASETYPE || !member->ident)
169 169 return FALSE;
170 170
171 171 if (pointer)
172 172 snprintf(buf, 256, "%s->%s", name, member->ident->name);
173 173 else
174 174 snprintf(buf, 256, "%s.%s", name, member->ident->name);
175 175
176 176 if (get_state(my_member_id, buf, outer))
177 177 return TRUE;
178 178
179 179 return FALSE;
180 180 }
181 181
182 182 static int member_uninitialized(char *name, struct symbol *outer, struct symbol *member, int pointer)
183 183 {
184 184 char buf[256];
185 185 struct symbol *base;
186 186 struct sm_state *sm;
187 187
188 188 base = get_base_type(member);
189 189 if (!base || base->type != SYM_BASETYPE || !member->ident)
190 190 return FALSE;
191 191
192 192 if (pointer)
193 193 snprintf(buf, 256, "%s->%s", name, member->ident->name);
194 194 else
195 195 snprintf(buf, 256, "%s.%s", name, member->ident->name);
196 196
197 197 sm = get_sm_state(my_member_id, buf, outer);
198 198 if (sm && !slist_has_state(sm->possible, &undefined))
199 199 return FALSE;
200 200
201 201 sm_warning("check that '%s' doesn't leak information", buf);
202 202 return TRUE;
203 203 }
204 204
205 205 static int check_members_initialized(struct expression *expr)
206 206 {
207 207 char *name;
208 208 struct symbol *outer;
209 209 struct symbol *sym;
210 210 struct symbol *tmp;
211 211 int pointer = 0;
212 212 int printed = 0;
213 213
214 214 sym = get_type(expr);
215 215 if (sym && sym->type == SYM_PTR) {
216 216 pointer = 1;
217 217 sym = get_real_base_type(sym);
218 218 }
219 219 if (!sym)
220 220 return 0;
221 221 if (sym->type != SYM_STRUCT)
222 222 return 0;
223 223
224 224 name = expr_to_var_sym(expr, &outer);
225 225
226 226 /*
227 227 * check that at least one member was set. If all of them were not set
228 228 * it's more likely a problem in the check than a problem in the kernel
229 229 * code.
230 230 */
231 231 FOR_EACH_PTR(sym->symbol_list, tmp) {
232 232 if (member_initialized(name, outer, tmp, pointer))
233 233 goto check;
234 234 } END_FOR_EACH_PTR(tmp);
235 235 goto out;
236 236
237 237 check:
238 238 FOR_EACH_PTR(sym->symbol_list, tmp) {
239 239 if (member_uninitialized(name, outer, tmp, pointer)) {
240 240 printed = 1;
241 241 goto out;
242 242 }
243 243 } END_FOR_EACH_PTR(tmp);
244 244 out:
245 245 free_string(name);
246 246 return printed;
247 247 }
248 248
249 249 static void check_was_initialized(struct expression *data)
250 250 {
251 251 data = strip_expr(data);
252 252 if (!data)
253 253 return;
254 254 if (data->type == EXPR_PREOP && data->op == '&')
255 255 data = strip_expr(data->unop);
256 256 if (data->type != EXPR_SYMBOL)
257 257 return;
258 258
259 259 if (has_global_scope(data))
260 260 return;
261 261 if (was_initialized(data))
262 262 return;
263 263 if (was_memset(data))
264 264 return;
265 265 if (warn_on_holey_struct(data))
266 266 return;
267 267 check_members_initialized(data);
268 268 }
269 269
270 270 static void match_copy_to_user(const char *fn, struct expression *expr, void *_arg)
271 271 {
272 272 int arg = PTR_INT(_arg);
273 273 struct expression *data;
274 274
275 275 data = get_argument_from_call_expr(expr->args, arg);
276 276 data = strip_expr(data);
277 277 if (!data)
278 278 return;
279 279 if (data->type != EXPR_PREOP || data->op != '&')
280 280 return;
281 281 check_was_initialized(data);
282 282 }
283 283
284 284 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
285 285 {
286 286 while (expr->type == EXPR_ASSIGNMENT)
287 287 expr = strip_expr(expr->right);
288 288 if (expr->type != EXPR_CALL)
289 289 return;
290 290
291 291 match_clear(NULL, expr, INT_PTR(param));
292 292 }
293 293
294 294 static void match_assign(struct expression *expr)
295 295 {
296 296 struct symbol *type;
297 297
298 298 type = get_type(expr->left);
299 299 if (!type || type->type != SYM_STRUCT)
300 300 return;
301 301 set_state_expr(my_whole_id, expr->left, &cleared);
302 302 }
303 303
304 304 static void register_clears_argument(void)
305 305 {
306 306 struct token *token;
307 307 const char *func;
308 308 int arg;
309 309
310 310 token = get_tokens_file("kernel.clears_argument");
311 311 if (!token)
312 312 return;
313 313 if (token_type(token) != TOKEN_STREAMBEGIN)
314 314 return;
315 315 token = token->next;
316 316 while (token_type(token) != TOKEN_STREAMEND) {
317 317 if (token_type(token) != TOKEN_IDENT)
318 318 return;
319 319 func = show_ident(token->ident);
320 320 token = token->next;
321 321 if (token_type(token) != TOKEN_NUMBER)
322 322 return;
323 323 arg = atoi(token->number);
324 324
325 325 add_function_hook(func, &match_clear, INT_PTR(arg));
326 326 token = token->next;
327 327 }
328 328 clear_token_alloc();
329 329 }
330 330
331 331 static void register_copy_funcs_from_file(void)
332 332 {
333 333 struct token *token;
334 334 const char *func;
335 335 int arg;
336 336
337 337 token = get_tokens_file("kernel.rosenberg_funcs");
338 338 if (!token)
339 339 return;
340 340 if (token_type(token) != TOKEN_STREAMBEGIN)
341 341 return;
342 342 token = token->next;
343 343 while (token_type(token) != TOKEN_STREAMEND) {
344 344 if (token_type(token) != TOKEN_IDENT)
345 345 return;
346 346 func = show_ident(token->ident);
347 347 token = token->next;
348 348 if (token_type(token) != TOKEN_NUMBER)
349 349 return;
350 350 arg = atoi(token->number);
351 351 add_function_hook(func, &match_copy_to_user, INT_PTR(arg));
352 352 token = token->next;
353 353 }
354 354 clear_token_alloc();
355 355 }
356 356
357 357 void check_rosenberg(int id)
358 358 {
359 359 if (option_project != PROJ_KERNEL)
360 360 return;
361 361 my_whole_id = id;
362 362
363 363 add_function_hook("memset", &match_clear, INT_PTR(0));
364 364 add_function_hook("memcpy", &match_clear, INT_PTR(0));
365 365 add_function_hook("memzero", &match_clear, INT_PTR(0));
366 366 add_function_hook("__memset", &match_clear, INT_PTR(0));
367 367 add_function_hook("__memcpy", &match_clear, INT_PTR(0));
368 368 add_function_hook("__memzero", &match_clear, INT_PTR(0));
369 369 add_function_hook("__builtin_memset", &match_clear, INT_PTR(0));
370 370 add_function_hook("__builtin_memcpy", &match_clear, INT_PTR(0));
371 371
372 372 add_hook(&match_assign, ASSIGNMENT_HOOK);
373 373 register_clears_argument();
374 374 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
↓ open down ↓ |
374 lines elided |
↑ open up ↑ |
375 375
376 376 register_copy_funcs_from_file();
377 377 }
378 378
379 379 void check_rosenberg2(int id)
380 380 {
381 381 if (option_project != PROJ_KERNEL)
382 382 return;
383 383
384 384 my_member_id = id;
385 + set_dynamic_states(my_member_id);
385 386 add_extra_mod_hook(&extra_mod_hook);
386 387 }
387 388
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX