2 * sparse/check_rosenberg.c
4 * Copyright (C) 2011 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
10 /* Does a search for Dan Rosenberg style info leaks */
12 /* fixme: struct includes a struct with a hole in it */
13 /* function is called that clears the struct */
17 #include "smatch_function_hashtable.h"
18 #include "smatch_slist.h"
21 extern int check_assigned_expr_id
;
25 static DEFINE_HASHTABLE_INSERT(insert_struct
, char, int);
26 static DEFINE_HASHTABLE_SEARCH(search_struct
, char, int);
27 static struct hashtable
*holey_structs
;
29 static char *get_struct_type(struct expression
*expr
)
33 type
= get_type(expr
);
34 if (!type
|| type
->type
!= SYM_STRUCT
|| !type
->ident
)
36 return alloc_string(type
->ident
->name
);
39 static int holey_struct(struct expression
*expr
)
41 char *struct_type
= 0;
44 struct_type
= get_struct_type(expr
);
47 if (search_struct(holey_structs
, struct_type
))
49 free_string(struct_type
);
53 static int has_global_scope(struct expression
*expr
)
57 if (expr
->type
!= EXPR_SYMBOL
)
60 return toplevel(sym
->scope
);
63 static int was_initialized(struct expression
*expr
)
68 name
= get_variable_from_expr(expr
, &sym
);
76 static void match_clear(const char *fn
, struct expression
*expr
, void *_arg_no
)
78 struct expression
*ptr
;
79 int arg_no
= PTR_INT(_arg_no
);
81 ptr
= get_argument_from_call_expr(expr
->args
, arg_no
);
82 if (ptr
->type
!= EXPR_PREOP
|| ptr
->op
!= '&')
84 ptr
= strip_expr(ptr
->unop
);
85 set_state_expr(my_id
, ptr
, &cleared
);
88 static int was_memset(struct expression
*expr
)
90 if (get_state_expr(my_id
, expr
) == &cleared
)
95 static int member_initialized(char *name
, struct symbol
*outer
, struct symbol
*member
)
100 base
= get_base_type(member
);
101 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
104 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
105 if (get_state(check_assigned_expr_id
, buf
, outer
))
111 static int member_uninitialized(char *name
, struct symbol
*outer
, struct symbol
*member
)
117 base
= get_base_type(member
);
118 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
121 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
122 sm
= get_sm_state(check_assigned_expr_id
, buf
, outer
);
123 if (sm
&& !slist_has_state(sm
->possible
, &undefined
))
126 sm_msg("warn: check that '%s' doesn't leak information", buf
);
130 static void check_members_initialized(struct expression
*expr
)
133 struct symbol
*outer
;
137 sym
= get_type(expr
);
138 if (!sym
|| sym
->type
!= SYM_STRUCT
)
141 name
= get_variable_from_expr(expr
, &outer
);
143 if (get_state(check_assigned_expr_id
, name
, outer
))
146 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
147 if (member_initialized(name
, outer
, tmp
))
149 } END_FOR_EACH_PTR(tmp
);
153 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
154 if (member_uninitialized(name
, outer
, tmp
))
156 } END_FOR_EACH_PTR(tmp
);
161 static void match_copy_to_user(const char *fn
, struct expression
*expr
, void *unused
)
163 struct expression
*data
;
165 data
= get_argument_from_call_expr(expr
->args
, 1);
168 if (data
->type
!= EXPR_PREOP
|| data
->op
!= '&')
171 data
= strip_expr(data
->unop
);
172 if (data
->type
!= EXPR_SYMBOL
)
175 if (has_global_scope(data
))
177 if (was_initialized(data
))
179 if (was_memset(data
))
181 if (holey_struct(data
)) {
184 name
= get_variable_from_expr(data
, NULL
);
185 sm_msg("warn: check that '%s' doesn't leak information (struct has holes)", name
);
189 check_members_initialized(data
);
192 static void register_holey_structs(void)
195 const char *struct_type
;
197 token
= get_tokens_file("kernel.paholes");
200 if (token_type(token
) != TOKEN_STREAMBEGIN
)
203 while (token_type(token
) != TOKEN_STREAMEND
) {
204 if (token_type(token
) != TOKEN_IDENT
)
206 struct_type
= show_ident(token
->ident
);
207 insert_struct(holey_structs
, alloc_string(struct_type
), INT_PTR(1));
213 static void register_clears_argument(void)
219 token
= get_tokens_file("kernel.clears_argument");
222 if (token_type(token
) != TOKEN_STREAMBEGIN
)
225 while (token_type(token
) != TOKEN_STREAMEND
) {
226 if (token_type(token
) != TOKEN_IDENT
)
228 func
= show_ident(token
->ident
);
230 if (token_type(token
) != TOKEN_NUMBER
)
232 arg
= atoi(token
->number
);
234 add_function_hook(func
, &match_clear
, INT_PTR(arg
));
240 void check_rosenberg(int id
)
242 if (option_project
!= PROJ_KERNEL
)
245 holey_structs
= create_function_hashtable(10000);
247 register_holey_structs();
248 register_clears_argument();
250 add_function_hook("copy_to_user", &match_copy_to_user
, NULL
);