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
;
31 static int my_strlen_id
;
33 static struct symbol
*this_func
;
35 static int get_array_size(struct expression
*expr
);
37 static void match_function_def(struct symbol
*sym
)
46 struct limiter b0_l2
= {0, 2};
47 struct limiter b1_l2
= {1, 2};
49 static void print_args(struct expression
*expr
, int size
)
60 name
= get_variable_from_expr(expr
, &sym
);
65 FOR_EACH_PTR(this_func
->ctype
.base_type
->arguments
, arg
) {
66 arg_name
= (arg
->ident
?arg
->ident
->name
:"-");
67 if (sym
== arg
&& !strcmp(name
, arg_name
)) {
68 sm_info("param %d array index. size %d", i
, size
);
72 } END_FOR_EACH_PTR(arg
);
77 static char *alloc_num(long long num
)
79 static char buff
[256];
81 if (num
== whole_range
.min
)
82 snprintf(buff
, 255, "min");
83 else if (num
== whole_range
.max
)
84 snprintf(buff
, 255, "max");
86 snprintf(buff
, 255, "(%lld)", num
);
88 snprintf(buff
, 255, "%lld", num
);
91 return alloc_sname(buff
);
94 static void delete(const char *name
, struct symbol
*sym
, struct expression
*expr
, void *unused
)
96 delete_state(my_used_id
, name
, sym
);
99 static struct smatch_state
*alloc_my_state(int val
)
101 struct smatch_state
*state
;
103 state
= __alloc_smatch_state(0);
104 state
->name
= alloc_num(val
);
105 state
->data
= malloc(sizeof(int));
106 *(int *)state
->data
= val
;
110 static int get_initializer_size(struct expression
*expr
)
114 return expr
->string
->length
;
115 case EXPR_INITIALIZER
: {
116 struct expression
*tmp
;
120 FOR_EACH_PTR(expr
->expr_list
, tmp
) {
121 if (tmp
->type
== EXPR_INDEX
&& tmp
->idx_to
> max
)
124 } END_FOR_EACH_PTR(tmp
);
130 return get_array_size(expr
);
135 static float get_cast_ratio(struct expression
*unstripped
)
137 struct expression
*start_expr
;
138 struct symbol
*start_type
;
139 struct symbol
*end_type
;
143 start_expr
= strip_expr(unstripped
);
144 start_type
= get_type(start_expr
);
145 end_type
= get_type(unstripped
);
146 if (!start_type
|| !end_type
)
149 if (start_type
->type
== SYM_PTR
)
150 start_bytes
= (get_base_type(start_type
))->ctype
.alignment
;
151 if (start_type
->type
== SYM_ARRAY
)
152 start_bytes
= (get_base_type(start_type
))->bit_size
/ 8;
153 if (end_type
->type
== SYM_PTR
)
154 end_bytes
= (get_base_type(end_type
))->ctype
.alignment
;
155 if (end_type
->type
== SYM_ARRAY
)
156 end_bytes
= (get_base_type(end_type
))->bit_size
/ 8;
158 if (!start_bytes
|| !end_bytes
)
160 return start_bytes
/ end_bytes
;
163 static int get_array_size(struct expression
*expr
)
166 struct smatch_state
*state
;
171 if (expr
->type
== EXPR_STRING
)
172 return expr
->string
->length
;
174 cast_ratio
= get_cast_ratio(expr
);
175 expr
= strip_expr(expr
);
176 tmp
= get_type(expr
);
180 if (tmp
->type
== SYM_ARRAY
) {
181 ret
= get_expression_value(tmp
->array_size
);
185 return ret
* cast_ratio
;
188 state
= get_state_expr(my_size_id
, expr
);
189 if (state
== &merged
)
191 if (state
&& state
->data
) {
192 if (tmp
->type
== SYM_PTR
)
193 tmp
= get_base_type(tmp
);
194 if (!tmp
->ctype
.alignment
)
196 ret
= *(int *)state
->data
/ tmp
->ctype
.alignment
;
197 return ret
* cast_ratio
;
200 if (expr
->type
== EXPR_SYMBOL
&& expr
->symbol
->initializer
) {
201 if (expr
->symbol
->initializer
!= expr
) /* int a = a; */
202 return get_initializer_size(expr
->symbol
->initializer
) * cast_ratio
;
205 state
= get_state_expr(my_strlen_id
, expr
);
206 if (!state
|| !state
->data
)
208 if (get_implied_max((struct expression
*)state
->data
, &len
))
209 return len
+ 1; /* add one because strlen doesn't include the NULL */
213 static int get_array_size_bytes(struct expression
*expr
)
219 if (expr
->type
== EXPR_STRING
)
220 return expr
->string
->length
;
222 tmp
= get_type(expr
);
226 if (tmp
->type
== SYM_ARRAY
) {
227 tmp
= get_base_type(tmp
);
228 element_size
= tmp
->bit_size
/ 8;
229 } else if (tmp
->type
== SYM_PTR
) {
230 tmp
= get_base_type(tmp
);
231 element_size
= tmp
->ctype
.alignment
;
235 array_size
= get_array_size(expr
);
236 return array_size
* element_size
;
239 static int definitely_just_used_as_limiter(struct expression
*array
, struct expression
*offset
)
242 struct expression
*tmp
;
246 if (!get_implied_value(offset
, &val
))
248 if (get_array_size(array
) != val
)
251 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
256 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '(')
258 if (tmp
->op
== '.' && !dot_ops
++)
260 if (step
== 1 && tmp
->op
== '&') {
264 if (step
== 2 && tmp
->type
== EXPR_COMPARE
)
267 } END_FOR_EACH_PTR_REVERSE(tmp
);
271 static void array_check(struct expression
*expr
)
273 struct expression
*array_expr
;
275 struct expression
*offset
;
279 expr
= strip_expr(expr
);
283 array_expr
= strip_parens(expr
->unop
->left
);
284 array_size
= get_array_size(array_expr
);
285 if (!array_size
|| array_size
== 1)
288 offset
= get_array_offset(expr
);
289 if (!get_fuzzy_max(offset
, &max
)) {
290 if (getting_address())
292 set_state_expr(my_used_id
, offset
, alloc_state_num(array_size
));
293 add_modification_hook_expr(my_used_id
, offset
, &delete, NULL
);
294 print_args(offset
, array_size
);
295 } else if (array_size
<= max
) {
296 const char *level
= "error";
298 if (getting_address())
301 if (definitely_just_used_as_limiter(array_expr
, offset
))
304 if (!option_spammy
) {
305 struct smatch_state
*state
;
307 state
= get_state_expr(SMATCH_EXTRA
, offset
);
308 if (state
&& is_whole_range(state
))
312 name
= get_variable_from_expr_complex(array_expr
, NULL
);
313 /* Blast. Smatch can't figure out glibc's strcmp __strcmp_cg()
314 * so it prints an error every time you compare to a string
315 * literal array with 4 or less chars.
317 if (name
&& strcmp(name
, "__s1") && strcmp(name
, "__s2")) {
318 sm_msg("%s: buffer overflow '%s' %d <= %lld",
319 level
, name
, array_size
, max
);
325 static void match_condition(struct expression
*expr
)
329 struct state_list
*slist
;
330 struct sm_state
*tmp
;
333 if (!expr
|| expr
->type
!= EXPR_COMPARE
)
335 if (get_implied_value(expr
->left
, &val
))
337 else if (get_implied_value(expr
->right
, &val
))
343 slist
= get_possible_states_expr(my_used_id
, expr
->right
);
345 slist
= get_possible_states_expr(my_used_id
, expr
->left
);
348 FOR_EACH_PTR(slist
, tmp
) {
349 if (tmp
->state
== &merged
)
351 boundary
= (int)tmp
->state
->data
;
353 if (boundary
< 1 && boundary
> -1) {
356 name
= get_variable_from_expr((left
? expr
->right
: expr
->left
), NULL
);
357 sm_msg("error: testing array offset '%s' after use.", name
);
360 } END_FOR_EACH_PTR(tmp
);
363 static void match_strlen_condition(struct expression
*expr
)
365 struct expression
*left
;
366 struct expression
*right
;
367 struct expression
*str
;
369 int strlen_right
= 0;
371 struct smatch_state
*true_state
= NULL
;
372 struct smatch_state
*false_state
= NULL
;
374 if (expr
->type
!= EXPR_COMPARE
)
376 left
= strip_expr(expr
->left
);
377 right
= strip_expr(expr
->right
);
379 if (left
->type
== EXPR_CALL
&& sym_name_is("strlen", left
->fn
)) {
380 str
= get_argument_from_call_expr(left
->args
, 0);
383 if (right
->type
== EXPR_CALL
&& sym_name_is("strlen", right
->fn
)) {
384 str
= get_argument_from_call_expr(right
->args
, 0);
388 if (!strlen_left
&& !strlen_right
)
390 if (strlen_left
&& strlen_right
)
394 if (!get_value(right
, &val
))
398 if (!get_value(left
, &val
))
402 if (expr
->op
== SPECIAL_EQUAL
) {
403 set_true_false_states_expr(my_size_id
, str
, alloc_my_state(val
+ 1), NULL
);
406 if (expr
->op
== SPECIAL_NOTEQUAL
) {
407 set_true_false_states_expr(my_size_id
, str
, NULL
, alloc_my_state(val
+ 1));
413 case SPECIAL_UNSIGNED_LT
:
415 true_state
= alloc_my_state(val
);
417 false_state
= alloc_my_state(val
+ 1);
420 case SPECIAL_UNSIGNED_LTE
:
422 true_state
= alloc_my_state(val
+ 1);
424 false_state
= alloc_my_state(val
);
427 case SPECIAL_UNSIGNED_GTE
:
429 false_state
= alloc_my_state(val
);
431 true_state
= alloc_my_state(val
+ 1);
434 case SPECIAL_UNSIGNED_GT
:
436 false_state
= alloc_my_state(val
+ 1);
438 true_state
= alloc_my_state(val
);
441 set_true_false_states_expr(my_size_id
, str
, true_state
, false_state
);
444 static struct expression
*strip_ampersands(struct expression
*expr
)
448 if (expr
->type
!= EXPR_PREOP
)
452 type
= get_type(expr
->unop
);
453 if (!type
|| type
->type
!= SYM_ARRAY
)
458 static void match_array_assignment(struct expression
*expr
)
460 struct expression
*left
;
461 struct expression
*right
;
466 left
= strip_expr(expr
->left
);
467 right
= strip_expr(expr
->right
);
468 right
= strip_ampersands(right
);
469 array_size
= get_array_size_bytes(right
);
471 set_state_expr(my_size_id
, left
, alloc_my_state(array_size
));
474 static void match_malloc(const char *fn
, struct expression
*expr
, void *unused
)
476 struct expression
*right
;
477 struct expression
*arg
;
480 right
= strip_expr(expr
->right
);
481 arg
= get_argument_from_call_expr(right
->args
, 0);
482 if (!get_implied_value(arg
, &bytes
))
484 set_state_expr(my_size_id
, expr
->left
, alloc_my_state(bytes
));
487 static void match_calloc(const char *fn
, struct expression
*expr
, void *unused
)
489 struct expression
*right
;
490 struct expression
*arg
;
494 right
= strip_expr(expr
->right
);
495 arg
= get_argument_from_call_expr(right
->args
, 0);
496 if (!get_implied_value(arg
, &elements
))
498 arg
= get_argument_from_call_expr(right
->args
, 1);
499 if (!get_implied_value(arg
, &size
))
501 set_state_expr(my_size_id
, expr
->left
, alloc_my_state(elements
* size
));
504 static void match_strlen(const char *fn
, struct expression
*expr
, void *unused
)
506 struct expression
*right
;
507 struct expression
*str
;
508 struct expression
*len_expr
;
510 struct smatch_state
*state
;
512 right
= strip_expr(expr
->right
);
513 str
= get_argument_from_call_expr(right
->args
, 0);
514 len_expr
= strip_expr(expr
->left
);
516 len_name
= get_variable_from_expr(len_expr
, NULL
);
520 state
= __alloc_smatch_state(0);
521 state
->name
= len_name
;
522 state
->data
= len_expr
;
523 set_state_expr(my_strlen_id
, str
, state
);
526 static void match_strcpy(const char *fn
, struct expression
*expr
, void *unused
)
528 struct expression
*dest
;
529 struct expression
*data
;
530 char *dest_name
= NULL
;
531 char *data_name
= NULL
;
535 dest
= get_argument_from_call_expr(expr
->args
, 0);
536 data
= get_argument_from_call_expr(expr
->args
, 1);
537 dest_size
= get_array_size_bytes(dest
);
538 data_size
= get_array_size_bytes(data
);
543 /* If the size of both arrays is known and the destination
544 * buffer is larger than the source buffer, we're okay.
546 if (data_size
&& dest_size
>= data_size
)
549 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
550 data_name
= get_variable_from_expr_complex(data
, NULL
);
553 sm_msg("error: %s() '%s' too large for '%s' (%d vs %d)",
554 fn
, data_name
, dest_name
, data_size
, dest_size
);
556 sm_msg("warn: %s() '%s' of unknown size might be too large for '%s'",
557 fn
, data_name
, dest_name
);
559 free_string(dest_name
);
560 free_string(data_name
);
563 static void match_limited(const char *fn
, struct expression
*expr
, void *_limiter
)
565 struct limiter
*limiter
= (struct limiter
*)_limiter
;
566 struct expression
*dest
;
567 struct expression
*data
;
568 char *dest_name
= NULL
;
572 dest
= get_argument_from_call_expr(expr
->args
, limiter
->buf_arg
);
573 data
= get_argument_from_call_expr(expr
->args
, limiter
->limit_arg
);
574 if (!get_fuzzy_max(data
, &needed
))
576 has
= get_array_size_bytes(dest
);
582 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
583 sm_msg("error: %s() '%s' too small (%d vs %lld)", fn
, dest_name
, has
, needed
);
584 free_string(dest_name
);
587 static void match_array_func(const char *fn
, struct expression
*expr
, void *info
)
589 struct bound
*bound_info
= (struct bound
*)info
;
590 struct expression
*arg
;
593 arg
= get_argument_from_call_expr(expr
->args
, bound_info
->param
);
594 if (!get_implied_value(arg
, &offset
))
596 if (offset
>= bound_info
->size
)
597 sm_msg("error: buffer overflow calling %s. param %d. %lld >= %d",
598 fn
, bound_info
->param
, offset
, bound_info
->size
);
601 static void register_array_funcs(void)
605 struct bound
*bound_info
= NULL
;
607 token
= get_tokens_file("kernel.array_bounds");
610 if (token_type(token
) != TOKEN_STREAMBEGIN
)
613 while (token_type(token
) != TOKEN_STREAMEND
) {
614 bound_info
= malloc(sizeof(*bound_info
));
615 if (token_type(token
) != TOKEN_IDENT
)
617 func
= show_ident(token
->ident
);
619 if (token_type(token
) != TOKEN_NUMBER
)
621 bound_info
->param
= atoi(token
->number
);
623 if (token_type(token
) != TOKEN_NUMBER
)
625 bound_info
->size
= atoi(token
->number
);
626 add_function_hook(func
, &match_array_func
, bound_info
);
629 if (token_type(token
) != TOKEN_STREAMEND
)
634 void check_overflow(int id
)
637 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
638 add_hook(&array_check
, OP_HOOK
);
639 add_hook(&match_array_assignment
, ASSIGNMENT_HOOK
);
640 add_hook(&match_condition
, CONDITION_HOOK
);
641 add_hook(&match_strlen_condition
, CONDITION_HOOK
);
642 add_function_assign_hook("malloc", &match_malloc
, NULL
);
643 add_function_assign_hook("calloc", &match_calloc
, NULL
);
644 add_function_assign_hook("strlen", &match_strlen
, NULL
);
645 add_function_hook("strcpy", &match_strcpy
, NULL
);
646 add_function_hook("strncpy", &match_limited
, &b0_l2
);
647 add_function_hook("memset", &match_limited
, &b0_l2
);
648 if (option_project
== PROJ_KERNEL
) {
649 add_function_assign_hook("kmalloc", &match_malloc
, NULL
);
650 add_function_assign_hook("kzalloc", &match_malloc
, NULL
);
651 add_function_assign_hook("vmalloc", &match_malloc
, NULL
);
652 add_function_assign_hook("__vmalloc", &match_malloc
, NULL
);
653 add_function_assign_hook("kcalloc", &match_calloc
, NULL
);
654 add_function_assign_hook("drm_malloc_ab", &match_calloc
, NULL
);
655 add_function_assign_hook("drm_calloc_large", &match_calloc
, NULL
);
656 add_function_hook("copy_to_user", &match_limited
, &b0_l2
);
657 add_function_hook("copy_to_user", &match_limited
, &b1_l2
);
658 add_function_hook("_copy_to_user", &match_limited
, &b0_l2
);
659 add_function_hook("_copy_to_user", &match_limited
, &b1_l2
);
660 add_function_hook("__copy_to_user", &match_limited
, &b0_l2
);
661 add_function_hook("__copy_to_user", &match_limited
, &b1_l2
);
662 add_function_hook("copy_from_user", &match_limited
, &b0_l2
);
663 add_function_hook("copy_from_user", &match_limited
, &b1_l2
);
664 add_function_hook("_copy_from_user", &match_limited
, &b0_l2
);
665 add_function_hook("_copy_from_user", &match_limited
, &b1_l2
);
666 add_function_hook("__copy_from_user", &match_limited
, &b0_l2
);
667 add_function_hook("__copy_from_user", &match_limited
, &b1_l2
);
668 add_function_hook("__builtin_memset", &match_limited
, &b0_l2
);
670 register_array_funcs();
673 void register_check_overflow_again(int id
)
678 void register_check_overflow_3(int id
)