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
= expr_to_var_sym(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
);
84 if (ptr
->type
!= EXPR_PREOP
|| ptr
->op
!= '&')
86 ptr
= strip_expr(ptr
->unop
);
87 set_state_expr(my_id
, ptr
, &cleared
);
90 static int was_memset(struct expression
*expr
)
92 if (get_state_expr(my_id
, expr
) == &cleared
)
97 static int member_initialized(char *name
, struct symbol
*outer
, struct symbol
*member
)
102 base
= get_base_type(member
);
103 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
106 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
107 if (get_state(check_assigned_expr_id
, buf
, outer
))
113 static int member_uninitialized(char *name
, struct symbol
*outer
, struct symbol
*member
)
119 base
= get_base_type(member
);
120 if (!base
|| base
->type
!= SYM_BASETYPE
|| !member
->ident
)
123 snprintf(buf
, 256, "%s.%s", name
, member
->ident
->name
);
124 sm
= get_sm_state(check_assigned_expr_id
, buf
, outer
);
125 if (sm
&& !slist_has_state(sm
->possible
, &undefined
))
128 sm_msg("warn: check that '%s' doesn't leak information", buf
);
132 static void check_members_initialized(struct expression
*expr
)
135 struct symbol
*outer
;
139 sym
= get_type(expr
);
140 if (!sym
|| sym
->type
!= SYM_STRUCT
)
143 name
= expr_to_var_sym(expr
, &outer
);
145 if (get_state(check_assigned_expr_id
, name
, outer
))
148 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
149 if (member_initialized(name
, outer
, tmp
))
151 } END_FOR_EACH_PTR(tmp
);
155 FOR_EACH_PTR(sym
->symbol_list
, tmp
) {
156 if (member_uninitialized(name
, outer
, tmp
))
158 } END_FOR_EACH_PTR(tmp
);
163 static void match_copy_to_user(const char *fn
, struct expression
*expr
, void *unused
)
165 struct expression
*data
;
167 data
= get_argument_from_call_expr(expr
->args
, 1);
170 if (data
->type
!= EXPR_PREOP
|| data
->op
!= '&')
173 data
= strip_expr(data
->unop
);
174 if (data
->type
!= EXPR_SYMBOL
)
177 if (has_global_scope(data
))
179 if (was_initialized(data
))
181 if (was_memset(data
))
183 if (holey_struct(data
)) {
186 name
= expr_to_var(data
);
187 sm_msg("warn: check that '%s' doesn't leak information (struct has holes)", name
);
191 check_members_initialized(data
);
194 static void register_holey_structs(void)
197 const char *struct_type
;
199 token
= get_tokens_file("kernel.paholes");
202 if (token_type(token
) != TOKEN_STREAMBEGIN
)
205 while (token_type(token
) != TOKEN_STREAMEND
) {
206 if (token_type(token
) != TOKEN_IDENT
)
208 struct_type
= show_ident(token
->ident
);
209 insert_struct(holey_structs
, alloc_string(struct_type
), INT_PTR(1));
215 static void register_clears_argument(void)
221 token
= get_tokens_file("kernel.clears_argument");
224 if (token_type(token
) != TOKEN_STREAMBEGIN
)
227 while (token_type(token
) != TOKEN_STREAMEND
) {
228 if (token_type(token
) != TOKEN_IDENT
)
230 func
= show_ident(token
->ident
);
232 if (token_type(token
) != TOKEN_NUMBER
)
234 arg
= atoi(token
->number
);
236 add_function_hook(func
, &match_clear
, INT_PTR(arg
));
242 void check_rosenberg(int id
)
244 if (option_project
!= PROJ_KERNEL
)
247 holey_structs
= create_function_hashtable(10000);
249 register_holey_structs();
250 register_clears_argument();
252 add_function_hook("copy_to_user", &match_copy_to_user
, NULL
);