2 * smatch/check_overflow.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
13 #include "smatch_slist.h"
14 #include "smatch_extra.h"
22 * This check has two smatch IDs.
23 * my_used_id - keeps a record of array offsets that have been used.
24 * If the code checks that they are within bounds later on,
25 * we complain about using an array offset before checking
26 * that it is within bounds.
28 static int my_used_id
;
30 static struct symbol
*this_func
;
32 static void match_function_def(struct symbol
*sym
)
41 static struct limiter b0_l2
= {0, 2};
42 static struct limiter b1_l2
= {1, 2};
44 static void delete(struct sm_state
*sm
, struct expression
*mod_expr
)
46 set_state(my_used_id
, sm
->name
, sm
->sym
, &undefined
);
49 static int definitely_just_used_as_limiter(struct expression
*array
, struct expression
*offset
)
52 struct expression
*tmp
;
56 if (!get_implied_value(offset
, &sval
))
58 if (get_array_size(array
) != sval
.value
)
61 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
66 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '(')
68 if (tmp
->op
== '.' && !dot_ops
++)
70 if (step
== 1 && tmp
->op
== '&') {
74 if (step
== 2 && tmp
->type
== EXPR_COMPARE
)
76 if (step
== 2 && tmp
->type
== EXPR_ASSIGNMENT
)
79 } END_FOR_EACH_PTR_REVERSE(tmp
);
83 static int get_the_max(struct expression
*expr
, sval_t
*sval
)
85 if (get_hard_max(expr
, sval
))
89 if (is_user_data(expr
))
90 return get_absolute_max(expr
, sval
);
91 /* FIXME: get_fuzzy_max() is not working well across function boundaries */
95 static int common_false_positives(char *name
)
100 /* Smatch can't figure out glibc's strcmp __strcmp_cg()
101 * so it prints an error every time you compare to a string
102 * literal array with 4 or less chars.
104 if (strcmp(name
, "__s1") == 0 || strcmp(name
, "__s2") == 0)
108 * passing WORK_CPU_UNBOUND is idiomatic but Smatch doesn't understand
109 * how it's used so it causes a bunch of false positives.
111 if (option_project
== PROJ_KERNEL
&&
112 strcmp(name
, "__per_cpu_offset") == 0)
117 static void array_check(struct expression
*expr
)
119 struct expression
*array_expr
;
121 struct expression
*offset
;
125 expr
= strip_expr(expr
);
129 array_expr
= strip_parens(expr
->unop
->left
);
130 array_size
= get_array_size(array_expr
);
131 if (!array_size
|| array_size
== 1)
134 offset
= get_array_offset(expr
);
135 if (!get_the_max(offset
, &max
)) {
136 if (getting_address())
138 if (is_capped(offset
))
140 set_state_expr(my_used_id
, offset
, alloc_state_num(array_size
));
141 } else if (array_size
<= max
.value
) {
142 const char *level
= "error";
144 if (getting_address())
147 if (definitely_just_used_as_limiter(array_expr
, offset
))
150 if (!option_spammy
) {
151 struct smatch_state
*state
;
153 state
= get_state_expr(SMATCH_EXTRA
, offset
);
154 if (state
&& estate_is_whole(state
))
158 name
= expr_to_str(array_expr
);
159 if (!common_false_positives(name
)) {
160 sm_msg("%s: buffer overflow '%s' %d <= %s",
161 level
, name
, array_size
, sval_to_str(max
));
167 static void match_condition(struct expression
*expr
)
171 struct state_list
*slist
;
172 struct sm_state
*tmp
;
175 if (!expr
|| expr
->type
!= EXPR_COMPARE
)
177 if (get_macro_name(expr
->pos
))
179 if (get_implied_value(expr
->left
, &sval
))
181 else if (get_implied_value(expr
->right
, &sval
))
187 slist
= get_possible_states_expr(my_used_id
, expr
->right
);
189 slist
= get_possible_states_expr(my_used_id
, expr
->left
);
192 FOR_EACH_PTR(slist
, tmp
) {
193 if (tmp
->state
== &merged
|| tmp
->state
== &undefined
)
195 boundary
= PTR_INT(tmp
->state
->data
);
196 boundary
-= sval
.value
;
197 if (boundary
< 1 && boundary
> -1) {
200 name
= expr_to_var(left
? expr
->right
: expr
->left
);
201 sm_msg("error: testing array offset '%s' after use.", name
);
204 } END_FOR_EACH_PTR(tmp
);
207 static void match_strcpy(const char *fn
, struct expression
*expr
, void *unused
)
209 struct expression
*dest
;
210 struct expression
*data
;
211 char *dest_name
= NULL
;
212 char *data_name
= NULL
;
216 dest
= get_argument_from_call_expr(expr
->args
, 0);
217 data
= get_argument_from_call_expr(expr
->args
, 1);
218 dest_size
= get_array_size_bytes(dest
);
219 data_size
= get_array_size_bytes(data
);
224 /* If the size of both arrays is known and the destination
225 * buffer is larger than the source buffer, we're okay.
227 if (data_size
&& dest_size
>= data_size
)
230 dest_name
= expr_to_str(dest
);
231 data_name
= expr_to_str(data
);
234 sm_msg("error: %s() '%s' too large for '%s' (%d vs %d)",
235 fn
, data_name
, dest_name
, data_size
, dest_size
);
236 else if (option_spammy
)
237 sm_msg("warn: %s() '%s' of unknown size might be too large for '%s'",
238 fn
, data_name
, dest_name
);
240 free_string(dest_name
);
241 free_string(data_name
);
244 static void match_snprintf(const char *fn
, struct expression
*expr
, void *unused
)
246 struct expression
*dest
;
247 struct expression
*dest_size_expr
;
248 struct expression
*format_string
;
249 struct expression
*data
;
250 char *data_name
= NULL
;
256 dest
= get_argument_from_call_expr(expr
->args
, 0);
257 dest_size_expr
= get_argument_from_call_expr(expr
->args
, 1);
258 format_string
= get_argument_from_call_expr(expr
->args
, 2);
259 data
= get_argument_from_call_expr(expr
->args
, 3);
261 dest_size
= get_array_size_bytes(dest
);
262 if (!get_implied_value(dest_size_expr
, &limit_size
))
264 if (dest_size
&& dest_size
< limit_size
.value
)
265 sm_msg("error: snprintf() is printing too much %s vs %d",
266 sval_to_str(limit_size
), dest_size
);
267 format
= expr_to_var(format_string
);
270 if (strcmp(format
, "\"%s\""))
272 data_name
= expr_to_str(data
);
273 data_size
= get_array_size_bytes(data
);
274 if (limit_size
.value
< data_size
)
275 sm_msg("error: snprintf() chops off the last chars of '%s': %d vs %s",
276 data_name
, data_size
, sval_to_str(limit_size
));
278 free_string(data_name
);
282 static void match_sprintf(const char *fn
, struct expression
*expr
, void *unused
)
284 struct expression
*dest
;
285 struct expression
*format_string
;
286 struct expression
*data
;
287 char *data_name
= NULL
;
292 dest
= get_argument_from_call_expr(expr
->args
, 0);
293 format_string
= get_argument_from_call_expr(expr
->args
, 1);
294 data
= get_argument_from_call_expr(expr
->args
, 2);
296 dest_size
= get_array_size_bytes(dest
);
299 format
= expr_to_var(format_string
);
302 if (strcmp(format
, "\"%s\""))
304 data_name
= expr_to_str(data
);
305 data_size
= get_array_size_bytes(data
);
306 if (dest_size
< data_size
)
307 sm_msg("error: sprintf() copies too much data from '%s': %d vs %d",
308 data_name
, data_size
, dest_size
);
310 free_string(data_name
);
314 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
316 struct limiter
*limiter
= (struct limiter
*)_limiter
;
317 struct expression
*dest
;
318 struct expression
*data
;
319 char *dest_name
= NULL
;
323 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
324 data
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
325 if (!get_the_max(data
, &needed
))
327 has
= get_array_size_bytes(dest
);
330 if (has
>= needed
.value
)
333 dest_name
= expr_to_str(dest
);
334 sm_msg("error: %s() '%s' too small (%d vs %s)", fn
, dest_name
, has
, sval_to_str(needed
));
335 free_string(dest_name
);
338 static void db_returns_buf_size(struct expression
*expr
, int param
, char *unused
, char *math
)
340 struct expression
*call
;
345 if (expr
->type
!= EXPR_ASSIGNMENT
)
347 call
= strip_expr(expr
->right
);
348 type
= get_pointer_type(expr
->left
);
350 if (!parse_call_math(call
, math
, &sval
) || sval
.value
== 0)
354 bytes
= bits_to_bytes(type
->bit_size
);
357 if (sval
.uvalue
>= bytes
)
359 sm_msg("error: not allocating enough data %d vs %s", bytes
, sval_to_str(sval
));
362 static void register_funcs_from_file(void)
368 struct limiter
*limiter
;
370 snprintf(name
, 256, "%s.sizeof_param", option_project_str
);
372 token
= get_tokens_file(name
);
375 if (token_type(token
) != TOKEN_STREAMBEGIN
)
378 while (token_type(token
) != TOKEN_STREAMEND
) {
379 if (token_type(token
) != TOKEN_IDENT
)
381 func
= show_ident(token
->ident
);
384 if (token_type(token
) != TOKEN_NUMBER
)
386 size
= atoi(token
->number
);
389 if (token_type(token
) != TOKEN_NUMBER
)
391 buf
= atoi(token
->number
);
393 limiter
= malloc(sizeof(*limiter
));
394 limiter
->limit_arg
= size
;
395 limiter
->buf_arg
= buf
;
397 add_function_hook(func
, &match_limited
, limiter
);
404 void check_overflow(int id
)
407 register_funcs_from_file();
408 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
409 add_hook(&array_check
, OP_HOOK
);
410 add_hook(&match_condition
, CONDITION_HOOK
);
411 add_function_hook("strcpy", &match_strcpy
, NULL
);
412 add_function_hook("snprintf", &match_snprintf
, NULL
);
413 add_function_hook("sprintf", &match_sprintf
, NULL
);
414 add_function_hook("memcmp", &match_limited
, &b0_l2
);
415 add_function_hook("memcmp", &match_limited
, &b1_l2
);
416 select_return_states_hook(BUF_SIZE
, &db_returns_buf_size
);
417 add_modification_hook(my_used_id
, &delete);
418 if (option_project
== PROJ_KERNEL
) {
419 add_function_hook("copy_to_user", &match_limited
, &b0_l2
);
420 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
421 add_function_hook("_copy_to_user", &match_limited
, &b0_l2
);
422 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
423 add_function_hook("__copy_to_user", &match_limited
, &b0_l2
);
424 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
425 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
426 add_function_hook("copy_from_user", &match_limited
, &b1_l2
);
427 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
428 add_function_hook("_copy_from_user", &match_limited
, &b1_l2
);
429 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);
430 add_function_hook("__copy_from_user", &match_limited
, &b1_l2
);