2 * smatch/check_deference.c
4 * Copyright (C) 2006 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_size_id - used to store the size of arrays.
24 * my_used_id - keeps a record of array offsets that have been used.
25 * If the code checks that they are within bounds later on,
26 * we complain about using an array offset before checking
27 * that it is within bounds.
29 static int my_size_id
;
30 static int my_used_id
;
32 static struct symbol
*this_func
;
34 static int get_array_size(struct expression
*expr
);
36 static void match_function_def(struct symbol
*sym
)
45 struct limiter b0_l2
= {0, 2};
46 struct limiter b1_l2
= {1, 2};
48 static void print_args(struct expression
*expr
, int size
)
59 name
= get_variable_from_expr(expr
, &sym
);
64 FOR_EACH_PTR(this_func
->ctype
.base_type
->arguments
, arg
) {
65 arg_name
= (arg
->ident
?arg
->ident
->name
:"-");
66 if (sym
== arg
&& !strcmp(name
, arg_name
)) {
67 sm_info("param %d array index. size %d", i
, size
);
71 } END_FOR_EACH_PTR(arg
);
76 static char *alloc_num(long long num
)
78 static char buff
[256];
80 if (num
== whole_range
.min
)
81 snprintf(buff
, 255, "min");
82 else if (num
== whole_range
.max
)
83 snprintf(buff
, 255, "max");
85 snprintf(buff
, 255, "(%lld)", num
);
87 snprintf(buff
, 255, "%lld", num
);
90 return alloc_sname(buff
);
93 static void delete(const char *name
, struct symbol
*sym
, struct expression
*expr
, void *unused
)
95 delete_state(my_used_id
, name
, sym
);
98 static struct smatch_state
*alloc_my_state(int val
)
100 struct smatch_state
*state
;
102 state
= __alloc_smatch_state(0);
103 state
->name
= alloc_num(val
);
104 state
->data
= malloc(sizeof(int));
105 *(int *)state
->data
= val
;
109 static int get_initializer_size(struct expression
*expr
)
113 return expr
->string
->length
;
114 case EXPR_INITIALIZER
: {
115 struct expression
*tmp
;
119 FOR_EACH_PTR(expr
->expr_list
, tmp
) {
120 if (tmp
->type
== EXPR_INDEX
&& tmp
->idx_to
> max
)
123 } END_FOR_EACH_PTR(tmp
);
129 return get_array_size(expr
);
134 static float get_cast_ratio(struct expression
*unstripped
)
136 struct expression
*start_expr
;
137 struct symbol
*start_type
;
138 struct symbol
*end_type
;
142 start_expr
= strip_expr(unstripped
);
143 start_type
= get_type(start_expr
);
144 end_type
= get_type(unstripped
);
145 if (!start_type
|| !end_type
)
148 if (start_type
->type
== SYM_PTR
)
149 start_bytes
= (get_base_type(start_type
))->ctype
.alignment
;
150 if (start_type
->type
== SYM_ARRAY
)
151 start_bytes
= (get_base_type(start_type
))->bit_size
/ 8;
152 if (end_type
->type
== SYM_PTR
)
153 end_bytes
= (get_base_type(end_type
))->ctype
.alignment
;
154 if (end_type
->type
== SYM_ARRAY
)
155 end_bytes
= (get_base_type(end_type
))->bit_size
/ 8;
157 if (!start_bytes
|| !end_bytes
)
159 return start_bytes
/ end_bytes
;
162 static int get_array_size(struct expression
*expr
)
165 struct smatch_state
*state
;
169 if (expr
->type
== EXPR_STRING
)
170 return expr
->string
->length
;
172 cast_ratio
= get_cast_ratio(expr
);
173 expr
= strip_expr(expr
);
174 tmp
= get_type(expr
);
178 if (tmp
->type
== SYM_ARRAY
) {
179 ret
= get_expression_value(tmp
->array_size
);
183 return ret
* cast_ratio
;
186 state
= get_state_expr(my_size_id
, expr
);
187 if (state
== &merged
)
189 if (state
&& state
->data
) {
190 if (tmp
->type
== SYM_PTR
)
191 tmp
= get_base_type(tmp
);
192 if (!tmp
->ctype
.alignment
)
194 ret
= *(int *)state
->data
/ tmp
->ctype
.alignment
;
195 return ret
* cast_ratio
;
198 if (expr
->type
== EXPR_SYMBOL
&& expr
->symbol
->initializer
) {
199 if (expr
->symbol
->initializer
!= expr
) /* int a = a; */
200 return get_initializer_size(expr
->symbol
->initializer
) * cast_ratio
;
205 static int get_array_size_bytes(struct expression
*expr
)
211 if (expr
->type
== EXPR_STRING
)
212 return expr
->string
->length
;
214 tmp
= get_type(expr
);
218 if (tmp
->type
== SYM_ARRAY
) {
219 tmp
= get_base_type(tmp
);
220 element_size
= tmp
->bit_size
/ 8;
221 } else if (tmp
->type
== SYM_PTR
) {
222 tmp
= get_base_type(tmp
);
223 element_size
= tmp
->ctype
.alignment
;
227 array_size
= get_array_size(expr
);
228 return array_size
* element_size
;
231 static int definitely_just_used_as_limiter(struct expression
*array
, struct expression
*offset
)
234 struct expression
*tmp
;
238 if (!get_implied_value(offset
, &val
))
240 if (get_array_size(array
) != val
)
243 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
248 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '(')
250 if (tmp
->op
== '.' && !dot_ops
++)
252 if (step
== 1 && tmp
->op
== '&') {
256 if (step
== 2 && tmp
->type
== EXPR_COMPARE
)
259 } END_FOR_EACH_PTR_REVERSE(tmp
);
263 static void array_check(struct expression
*expr
)
265 struct expression
*array_expr
;
267 struct expression
*offset
;
271 expr
= strip_expr(expr
);
275 array_expr
= strip_parens(expr
->unop
->left
);
276 array_size
= get_array_size(array_expr
);
277 if (!array_size
|| array_size
== 1)
280 offset
= get_array_offset(expr
);
281 if (!get_fuzzy_max(offset
, &max
)) {
282 if (getting_address())
284 set_state_expr(my_used_id
, offset
, alloc_state_num(array_size
));
285 add_modification_hook_expr(my_used_id
, offset
, &delete, NULL
);
286 print_args(offset
, array_size
);
287 } else if (array_size
<= max
) {
288 const char *level
= "error";
290 if (getting_address())
293 if (definitely_just_used_as_limiter(array_expr
, offset
))
296 if (!option_spammy
) {
297 struct smatch_state
*state
;
299 state
= get_state_expr(SMATCH_EXTRA
, offset
);
300 if (state
&& is_whole_range(state
))
304 name
= get_variable_from_expr_complex(array_expr
, NULL
);
305 /* Blast. Smatch can't figure out glibc's strcmp __strcmp_cg()
306 * so it prints an error every time you compare to a string
307 * literal array with 4 or less chars.
309 if (name
&& strcmp(name
, "__s1") && strcmp(name
, "__s2")) {
310 sm_msg("%s: buffer overflow '%s' %d <= %lld",
311 level
, name
, array_size
, max
);
317 static void match_condition(struct expression
*expr
)
321 struct state_list
*slist
;
322 struct sm_state
*tmp
;
325 if (!expr
|| expr
->type
!= EXPR_COMPARE
)
327 if (get_implied_value(expr
->left
, &val
))
329 else if (get_implied_value(expr
->right
, &val
))
335 slist
= get_possible_states_expr(my_used_id
, expr
->right
);
337 slist
= get_possible_states_expr(my_used_id
, expr
->left
);
340 FOR_EACH_PTR(slist
, tmp
) {
341 if (tmp
->state
== &merged
)
343 boundary
= (int)tmp
->state
->data
;
345 if (boundary
< 1 && boundary
> -1) {
348 name
= get_variable_from_expr((left
? expr
->right
: expr
->left
), NULL
);
349 sm_msg("error: testing array offset '%s' after use.", name
);
352 } END_FOR_EACH_PTR(tmp
);
355 static struct expression
*strip_ampersands(struct expression
*expr
)
359 if (expr
->type
!= EXPR_PREOP
)
363 type
= get_type(expr
->unop
);
364 if (!type
|| type
->type
!= SYM_ARRAY
)
369 static void match_array_assignment(struct expression
*expr
)
371 struct expression
*left
;
372 struct expression
*right
;
377 left
= strip_expr(expr
->left
);
378 right
= strip_expr(expr
->right
);
379 right
= strip_ampersands(right
);
380 array_size
= get_array_size_bytes(right
);
382 set_state_expr(my_size_id
, left
, alloc_my_state(array_size
));
385 static void match_malloc(const char *fn
, struct expression
*expr
, void *unused
)
387 struct expression
*right
;
388 struct expression
*arg
;
391 right
= strip_expr(expr
->right
);
392 arg
= get_argument_from_call_expr(right
->args
, 0);
393 if (!get_implied_value(arg
, &bytes
))
395 set_state_expr(my_size_id
, expr
->left
, alloc_my_state(bytes
));
398 static void match_calloc(const char *fn
, struct expression
*expr
, void *unused
)
400 struct expression
*right
;
401 struct expression
*arg
;
405 right
= strip_expr(expr
->right
);
406 arg
= get_argument_from_call_expr(right
->args
, 0);
407 if (!get_implied_value(arg
, &elements
))
409 arg
= get_argument_from_call_expr(right
->args
, 1);
410 if (!get_implied_value(arg
, &size
))
412 set_state_expr(my_size_id
, expr
->left
, alloc_my_state(elements
* size
));
415 static void match_strcpy(const char *fn
, struct expression
*expr
, void *unused
)
417 struct expression
*dest
;
418 struct expression
*data
;
419 char *dest_name
= NULL
;
420 char *data_name
= NULL
;
424 dest
= get_argument_from_call_expr(expr
->args
, 0);
425 data
= get_argument_from_call_expr(expr
->args
, 1);
426 dest_size
= get_array_size_bytes(dest
);
427 data_size
= get_array_size_bytes(data
);
428 if (!dest_size
|| !data_size
)
430 if (dest_size
>= data_size
)
433 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
434 data_name
= get_variable_from_expr_complex(data
, NULL
);
435 sm_msg("error: %s() '%s' too large for '%s' (%d vs %d)",
436 fn
, data_name
, dest_name
, data_size
, dest_size
);
437 free_string(dest_name
);
438 free_string(data_name
);
441 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
443 struct limiter
*limiter
= (struct limiter
*)_limiter
;
444 struct expression
*dest
;
445 struct expression
*data
;
446 char *dest_name
= NULL
;
450 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
451 data
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
452 if (!get_fuzzy_max(data
, &needed
))
454 has
= get_array_size_bytes(dest
);
460 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
461 sm_msg("error: %s() '%s' too small (%d vs %lld)", fn
, dest_name
, has
, needed
);
462 free_string(dest_name
);
465 static void match_array_func(const char *fn
, struct expression
*expr
, void *info
)
467 struct bound
*bound_info
= (struct bound
*)info
;
468 struct expression
*arg
;
471 arg
= get_argument_from_call_expr(expr
->args
, bound_info
->param
);
472 if (!get_implied_value(arg
, &offset
))
474 if (offset
>= bound_info
->size
)
475 sm_msg("error: buffer overflow calling %s. param %d. %lld >= %d",
476 fn
, bound_info
->param
, offset
, bound_info
->size
);
479 static void register_array_funcs(void)
483 struct bound
*bound_info
= NULL
;
485 token
= get_tokens_file("kernel.array_bounds");
488 if (token_type(token
) != TOKEN_STREAMBEGIN
)
491 while (token_type(token
) != TOKEN_STREAMEND
) {
492 bound_info
= malloc(sizeof(*bound_info
));
493 if (token_type(token
) != TOKEN_IDENT
)
495 func
= show_ident(token
->ident
);
497 if (token_type(token
) != TOKEN_NUMBER
)
499 bound_info
->param
= atoi(token
->number
);
501 if (token_type(token
) != TOKEN_NUMBER
)
503 bound_info
->size
= atoi(token
->number
);
504 add_function_hook(func
, &match_array_func
, bound_info
);
507 if (token_type(token
) != TOKEN_STREAMEND
)
512 void check_overflow(int id
)
515 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
516 add_hook(&array_check
, OP_HOOK
);
517 add_hook(&match_array_assignment
, ASSIGNMENT_HOOK
);
518 add_hook(&match_condition
, CONDITION_HOOK
);
519 add_function_assign_hook("malloc", &match_malloc
, NULL
);
520 add_function_assign_hook("calloc", &match_calloc
, NULL
);
521 add_function_hook("strcpy", &match_strcpy
, NULL
);
522 add_function_hook("strncpy", &match_limited
, &b0_l2
);
523 add_function_hook("memset", &match_limited
, &b0_l2
);
524 if (option_project
== PROJ_KERNEL
) {
525 add_function_assign_hook("kmalloc", &match_malloc
, NULL
);
526 add_function_assign_hook("kzalloc", &match_malloc
, NULL
);
527 add_function_assign_hook("vmalloc", &match_malloc
, NULL
);
528 add_function_assign_hook("__vmalloc", &match_malloc
, NULL
);
529 add_function_assign_hook("kcalloc", &match_calloc
, NULL
);
530 add_function_assign_hook("drm_malloc_ab", &match_calloc
, NULL
);
531 add_function_assign_hook("drm_calloc_large", &match_calloc
, NULL
);
532 add_function_hook("copy_to_user", &match_limited
, &b0_l2
);
533 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
534 add_function_hook("_copy_to_user", &match_limited
, &b0_l2
);
535 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
536 add_function_hook("__copy_to_user", &match_limited
, &b0_l2
);
537 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
538 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
539 add_function_hook("copy_from_user", &match_limited
, &b1_l2
);
540 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
541 add_function_hook("_copy_from_user", &match_limited
, &b1_l2
);
542 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);
543 add_function_hook("__copy_from_user", &match_limited
, &b1_l2
);
544 add_function_hook("__builtin_memset", &match_limited
, &b0_l2
);
546 register_array_funcs();
549 void register_check_overflow_again(int id
)