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
18 /* Does a search for Dan Rosenberg style info leaks */
20 /* fixme: struct includes a struct with a hole in it */
21 /* function is called that clears the struct */
25 #include "smatch_function_hashtable.h"
26 #include "smatch_slist.h"
27 #include "smatch_extra.h"
29 static int my_whole_id
;
30 static int my_member_id
;
31 static int skb_put_id
;
35 static void extra_mod_hook(const char *name
, struct symbol
*sym
, struct expression
*expr
, struct smatch_state
*state
)
39 type
= get_real_base_type(sym
);
40 if (!type
|| type
->type
!= SYM_STRUCT
)
46 if (name
&& strstr(name
, "->"))
49 set_state(my_member_id
, name
, sym
, state
);
52 static void print_holey_warning(struct expression
*data
, const char *member
)
56 name
= expr_to_str(data
);
58 sm_warning("check that '%s' doesn't leak information (struct has a hole after '%s')",
61 sm_warning("check that '%s' doesn't leak information (struct has holes)",
67 static int check_struct(struct expression
*expr
, struct symbol
*type
)
69 struct symbol
*base_type
, *prev_type
;
70 struct symbol
*tmp
, *prev
;
73 if (type
->ctype
.alignment
== 1)
79 FOR_EACH_PTR(type
->symbol_list
, tmp
) {
80 base_type
= get_real_base_type(tmp
);
81 if (base_type
&& base_type
->type
== SYM_STRUCT
) {
82 if (check_struct(expr
, base_type
))
85 if (base_type
&& base_type
->type
== SYM_BITFIELD
&&
86 prev_type
&& prev_type
->type
== SYM_BITFIELD
)
89 if (!tmp
->ctype
.alignment
) {
90 sm_perror("cannot determine the alignment here");
91 } else if (align
% tmp
->ctype
.alignment
) {
93 print_holey_warning(expr
, prev
->ident
? prev
->ident
->name
: "<unknown>");
98 if (base_type
== &bool_ctype
)
100 else if (type_bits(tmp
) <= 0)
103 align
+= type_bytes(tmp
);
106 prev_type
= base_type
;
107 } END_FOR_EACH_PTR(tmp
);
109 // FIXME: this isn't the correct fix. See sbni_siocdevprivate().
110 if (prev_type
&& prev_type
->type
== SYM_BITFIELD
)
112 if (align
% type
->ctype
.alignment
) {
113 sm_msg("%s: tmp='%s' align=%d ctype.align=%ld type='%s'", __func__
,
114 tmp
->ident
? tmp
->ident
->name
: "<unknown>",
115 align
, tmp
->ctype
.alignment
,
116 type_to_str(get_real_base_type(tmp
)));
118 print_holey_warning(expr
, (prev
&& prev
->ident
) ? prev
->ident
->name
: "<unknown>");
125 static int warn_on_holey_struct(struct expression
*expr
)
128 type
= get_type(expr
);
129 if (!type
|| type
->type
!= SYM_STRUCT
)
132 return check_struct(expr
, type
);
135 static int has_global_scope(struct expression
*expr
)
139 if (expr
->type
!= EXPR_SYMBOL
)
144 return toplevel(sym
->scope
);
147 static int was_initialized(struct expression
*expr
)
149 struct symbol
*sym
, *type
;
151 sym
= expr_to_sym(expr
);
154 if (!sym
->initializer
)
157 type
= get_real_base_type(sym
);
160 if (type
->type
!= SYM_STRUCT
)
163 /* Fully initializing a struct does not clear the holes */
164 if (sym
->initializer
->type
!= EXPR_INITIALIZER
)
166 if (ptr_list_size((struct ptr_list
*)sym
->initializer
->expr_list
) >=
167 ptr_list_size((struct ptr_list
*)type
->symbol_list
))
173 static void match_clear(const char *fn
, struct expression
*expr
, void *_arg_no
)
175 struct expression
*ptr
, *tmp
;
176 int arg_no
= PTR_INT(_arg_no
);
178 ptr
= get_argument_from_call_expr(expr
->args
, arg_no
);
181 tmp
= get_assigned_expr(ptr
);
184 ptr
= strip_expr(ptr
);
185 if (ptr
->type
!= EXPR_PREOP
|| ptr
->op
!= '&')
187 ptr
= strip_expr(ptr
->unop
);
188 set_state_expr(my_whole_id
, ptr
, &cleared
);
191 static int was_memset(struct expression
*expr
)
193 if (get_state_expr(my_whole_id
, expr
) == &cleared
)
198 static int member_initialized(char *name
, struct symbol
*outer
, struct symbol
*member
, int pointer
)
203 base
= get_base_type(member
);
204 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
208 snprintf(buf
, 256, "%s->%s", name
, member
->ident
->name
);
210 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
212 if (get_state(my_member_id
, buf
, outer
))
218 static int member_uninitialized(char *name
, struct symbol
*outer
, struct symbol
*member
, int pointer
)
224 base
= get_base_type(member
);
225 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
229 snprintf(buf
, 256, "%s->%s", name
, member
->ident
->name
);
231 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
233 sm
= get_sm_state(my_member_id
, buf
, outer
);
234 if (sm
&& !slist_has_state(sm
->possible
, &undefined
))
237 sm_warning("check that '%s' doesn't leak information", buf
);
241 static int check_members_initialized(struct expression
*expr
)
244 struct symbol
*outer
;
250 sym
= get_type(expr
);
251 if (sym
&& sym
->type
== SYM_PTR
) {
253 sym
= get_real_base_type(sym
);
257 if (sym
->type
!= SYM_STRUCT
)
260 name
= expr_to_var_sym(expr
, &outer
);
263 * check that at least one member was set. If all of them were not set
264 * it's more likely a problem in the check than a problem in the kernel
267 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
268 if (member_initialized(name
, outer
, tmp
, pointer
))
270 } END_FOR_EACH_PTR(tmp
);
274 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
275 if (member_uninitialized(name
, outer
, tmp
, pointer
)) {
279 } END_FOR_EACH_PTR(tmp
);
285 static void check_was_initialized(struct expression
*data
)
287 data
= strip_expr(data
);
290 if (data
->type
== EXPR_PREOP
&& data
->op
== '&')
291 data
= strip_expr(data
->unop
);
292 if (data
->type
!= EXPR_SYMBOL
)
295 if (has_global_scope(data
))
297 if (was_initialized(data
))
299 if (was_memset(data
))
301 if (warn_on_holey_struct(data
))
303 check_members_initialized(data
);
306 static void check_skb_put(struct expression
*data
)
308 data
= strip_expr(data
);
311 if (data
->type
== EXPR_PREOP
&& data
->op
== '&')
312 data
= strip_expr(data
->unop
);
314 if (was_memset(data
))
316 if (warn_on_holey_struct(data
))
318 check_members_initialized(data
);
321 static void match_copy_to_user(const char *fn
, struct expression
*expr
, void *_arg
)
323 int arg
= PTR_INT(_arg
);
324 struct expression
*data
;
326 data
= get_argument_from_call_expr(expr
->args
, arg
);
327 data
= strip_expr(data
);
330 if (data
->type
!= EXPR_PREOP
|| data
->op
!= '&')
332 check_was_initialized(data
);
335 static void db_param_cleared(struct expression
*expr
, int param
, char *key
, char *value
)
337 while (expr
->type
== EXPR_ASSIGNMENT
)
338 expr
= strip_expr(expr
->right
);
339 if (expr
->type
!= EXPR_CALL
)
342 match_clear(NULL
, expr
, INT_PTR(param
));
345 static struct smatch_state
*alloc_expr_state(struct expression
*expr
)
347 struct smatch_state
*state
;
350 name
= expr_to_str(expr
);
354 state
= __alloc_smatch_state(0);
355 expr
= strip_expr(expr
);
356 state
->name
= alloc_sname(name
);
362 static void match_skb_put(const char *fn
, struct expression
*expr
, void *unused
)
365 struct smatch_state
*state
;
367 type
= get_type(expr
->left
);
368 type
= get_real_base_type(type
);
369 if (!type
|| type
->type
!= SYM_STRUCT
)
371 state
= alloc_expr_state(expr
->left
);
372 set_state_expr(skb_put_id
, expr
->left
, state
);
375 static void match_return_skb_put(struct expression
*expr
)
380 if (is_error_return(expr
))
383 stree
= __get_cur_stree();
385 FOR_EACH_MY_SM(skb_put_id
, stree
, sm
) {
386 check_skb_put(sm
->state
->data
);
387 } END_FOR_EACH_SM(sm
);
390 static void register_clears_argument(void)
396 token
= get_tokens_file("kernel.clears_argument");
399 if (token_type(token
) != TOKEN_STREAMBEGIN
)
402 while (token_type(token
) != TOKEN_STREAMEND
) {
403 if (token_type(token
) != TOKEN_IDENT
)
405 func
= show_ident(token
->ident
);
407 if (token_type(token
) != TOKEN_NUMBER
)
409 arg
= atoi(token
->number
);
411 add_function_hook(func
, &match_clear
, INT_PTR(arg
));
417 static void register_copy_funcs_from_file(void)
423 token
= get_tokens_file("kernel.rosenberg_funcs");
426 if (token_type(token
) != TOKEN_STREAMBEGIN
)
429 while (token_type(token
) != TOKEN_STREAMEND
) {
430 if (token_type(token
) != TOKEN_IDENT
)
432 func
= show_ident(token
->ident
);
434 if (token_type(token
) != TOKEN_NUMBER
)
436 arg
= atoi(token
->number
);
437 add_function_hook(func
, &match_copy_to_user
, INT_PTR(arg
));
443 void check_rosenberg(int id
)
445 if (option_project
!= PROJ_KERNEL
)
449 add_function_hook("memset", &match_clear
, INT_PTR(0));
450 add_function_hook("memcpy", &match_clear
, INT_PTR(0));
451 add_function_hook("memzero", &match_clear
, INT_PTR(0));
452 add_function_hook("__memset", &match_clear
, INT_PTR(0));
453 add_function_hook("__memcpy", &match_clear
, INT_PTR(0));
454 add_function_hook("__memzero", &match_clear
, INT_PTR(0));
455 add_function_hook("__builtin_memset", &match_clear
, INT_PTR(0));
456 add_function_hook("__builtin_memcpy", &match_clear
, INT_PTR(0));
458 register_clears_argument();
459 select_return_states_hook(BUF_CLEARED
, &db_param_cleared
);
461 register_copy_funcs_from_file();
464 void check_rosenberg2(int id
)
466 if (option_project
!= PROJ_KERNEL
)
470 set_dynamic_states(my_member_id
);
471 add_extra_mod_hook(&extra_mod_hook
);
474 void check_rosenberg3(int id
)
476 if (option_project
!= PROJ_KERNEL
)
480 set_dynamic_states(skb_put_id
);
481 add_function_assign_hook("skb_put", &match_skb_put
, NULL
);
482 add_hook(&match_return_skb_put
, RETURN_HOOK
);