2 * Copyright (C) 2010 Dan Carpenter.
3 * Copyright (C) 2020 Oracle.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
20 * This is the "strict" version which is more daring and ambitious than
21 * the check_free.c file. The difference is that this looks at split
22 * returns and the other only looks at if every path frees a parameter.
23 * Also this has a bunch of kernel specific things to do with reference
29 #include "smatch_slist.h"
30 #include "smatch_extra.h"
38 static void ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
41 set_state(my_id
, sm
->name
, sm
->sym
, &ok
);
44 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
46 if (is_impossible_path())
47 set_state(my_id
, cur
->name
, cur
->sym
, &ok
);
50 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
52 struct smatch_state
*state
;
55 if (sm
->state
!= &freed
&& sm
->state
!= &maybe_freed
)
58 if (get_param_num_from_sym(sm
->sym
) < 0)
62 * If the parent is non-there count it as freed. This is
63 * a hack for tracking return states.
65 if (parent_is_null_var_sym(sm
->name
, sm
->sym
))
68 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
71 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
73 /* It makes it easier to consider NULL pointers as freed. */
77 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
79 if (s1
== &freed
&& s2
== &maybe_freed
)
81 if (s1
== &maybe_freed
&& s2
== &freed
)
86 static int is_freed(struct expression
*expr
)
90 sm
= get_sm_state_expr(my_id
, expr
);
91 if (sm
&& slist_has_state(sm
->possible
, &freed
))
96 bool is_freed_var_sym(const char *name
, struct symbol
*sym
)
98 struct smatch_state
*state
;
100 state
= get_state(my_id
, name
, sym
);
101 if (state
== &freed
|| state
== &maybe_freed
)
107 static bool expr_is_condition(struct expression
*expr
)
109 struct statement
*stmt
;
111 stmt
= expr_get_parent_stmt(expr
);
114 if (stmt
->type
== STMT_IF
|| stmt
->type
== STMT_ITERATOR
)
119 bool is_part_of_condition(struct expression
*expr
)
121 struct expression
*parent
;
123 if (expr_is_condition(expr
))
126 parent
= expr_get_parent_expr(expr
);
129 if (parent
->type
== EXPR_LOGICAL
|| parent
->type
== EXPR_COMPARE
)
131 if (parent
->type
== EXPR_SELECT
|| parent
->type
== EXPR_CONDITIONAL
)
133 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '!')
139 static bool is_percent_p(struct expression
*str_expr
, int idx
)
144 p
= str_expr
->string
->data
;
146 if (p
[0] == '%' && p
[1] == '%') {
152 if (idx
== cnt
&& p
[1] == 'p')
160 bool is_percent_p_print(struct expression
*expr
)
162 struct expression
*parent
, *arg
;
163 int expr_idx
, string_idx
;
165 parent
= expr_get_parent_expr(expr
);
166 if (!parent
|| parent
->type
!= EXPR_CALL
)
170 FOR_EACH_PTR(parent
->args
, arg
) {
174 } END_FOR_EACH_PTR(arg
);
180 FOR_EACH_PTR(parent
->args
, arg
) {
182 if (arg
->type
!= EXPR_STRING
)
184 if (is_percent_p(arg
, expr_idx
- string_idx
))
186 } END_FOR_EACH_PTR(arg
);
191 static void match_symbol(struct expression
*expr
)
193 struct expression
*parent
;
196 if (is_impossible_path())
198 if (__in_fake_parameter_assign
)
201 if (is_part_of_condition(expr
))
204 /* This ignores stuff like "get_new_ptr(&foo);" */
205 parent
= expr_get_parent_expr(expr
);
206 while (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '(')
207 parent
= expr_get_parent_expr(parent
);
208 if (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
214 if (is_percent_p_print(expr
))
217 name
= expr_to_var(expr
);
218 sm_warning("'%s' was already freed.", name
);
222 static void match_dereferences(struct expression
*expr
)
226 if (expr
->type
!= EXPR_PREOP
)
229 if (is_impossible_path())
231 if (__in_fake_parameter_assign
)
234 expr
= strip_expr(expr
->unop
);
237 name
= expr_to_var(expr
);
238 sm_error("dereferencing freed memory '%s'", name
);
239 set_state_expr(my_id
, expr
, &ok
);
243 static int ignored_params
[16];
245 static void set_ignored_params(struct expression
*call
)
247 struct expression
*arg
;
251 memset(&ignored_params
, 0, sizeof(ignored_params
));
254 FOR_EACH_PTR(call
->args
, arg
) {
256 if (arg
->type
!= EXPR_STRING
)
259 } END_FOR_EACH_PTR(arg
);
265 p
= arg
->string
->data
;
266 while ((p
= strchr(p
, '%'))) {
267 if (i
>= ARRAY_SIZE(ignored_params
))
279 ignored_params
[i
] = 1;
284 static int is_free_func(struct expression
*fn
)
289 name
= expr_to_str(fn
);
292 if (strstr(name
, "free"))
299 static void match_call(struct expression
*expr
)
301 struct expression
*arg
;
305 if (is_impossible_path())
308 set_ignored_params(expr
);
311 FOR_EACH_PTR(expr
->args
, arg
) {
313 if (!is_pointer(arg
))
317 if (ignored_params
[i
])
319 if (is_percent_p_print(arg
))
322 name
= expr_to_var(arg
);
323 if (is_free_func(expr
->fn
))
324 sm_error("double free of '%s'", name
);
326 sm_warning("passing freed memory '%s'", name
);
327 set_state_expr(my_id
, arg
, &ok
);
329 } END_FOR_EACH_PTR(arg
);
332 static void match_return(struct expression
*expr
)
336 if (is_impossible_path())
344 name
= expr_to_var(expr
);
345 sm_warning("returning freed memory '%s'", name
);
346 set_state_expr(my_id
, expr
, &ok
);
350 static int counter_was_inced_name_sym(const char *name
, struct symbol
*sym
, const char *counter_str
)
354 snprintf(buf
, sizeof(buf
), "%s%s", name
, counter_str
);
355 return was_inced(buf
, sym
);
358 static int counter_was_inced(struct expression
*expr
, const char *counter_str
)
364 name
= expr_to_var_sym(expr
, &sym
);
368 ret
= counter_was_inced_name_sym(name
, sym
, counter_str
);
374 void set_other_states_name_sym(int owner
, const char *name
, struct symbol
*sym
, struct smatch_state
*state
)
376 struct expression
*tmp
;
379 FOR_EACH_MY_SM(check_assigned_expr_id
, __get_cur_stree(), sm
) {
380 tmp
= sm
->state
->data
;
383 if (tmp
->type
!= EXPR_SYMBOL
)
385 if (tmp
->symbol
!= sym
)
387 if (!tmp
->symbol_name
)
389 if (strcmp(tmp
->symbol_name
->name
, name
) != 0)
391 set_state(owner
, tmp
->symbol_name
->name
, tmp
->symbol
, state
);
392 } END_FOR_EACH_SM(sm
);
394 tmp
= get_assigned_expr_name_sym(name
, sym
);
396 set_state_expr(owner
, tmp
, state
);
399 void set_other_states(int owner
, struct expression
*expr
, struct smatch_state
*state
)
404 name
= expr_to_var_sym(expr
, &sym
);
408 set_other_states_name_sym(owner
, name
, sym
, state
);
414 static bool is_ptr_to(struct expression
*expr
, const char *type
)
418 sym
= get_type(expr
);
419 if (!is_ptr_type(sym
))
421 sym
= get_real_base_type(sym
);
422 if (sym
&& sym
->ident
&& strcmp(sym
->ident
->name
, type
) == 0)
427 static void match_free(const char *fn
, struct expression
*expr
, void *param
)
429 struct expression
*arg
;
431 if (is_impossible_path())
434 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
437 if (is_ptr_to(arg
, "sk_buff") &&
438 counter_was_inced(arg
, "->users.refs.counter"))
440 if (is_ptr_to(arg
, "buffer_head") &&
441 counter_was_inced(arg
, "->b_count.counter"))
444 char *name
= expr_to_var(arg
);
446 sm_error("double free of '%s'", name
);
449 track_freed_param(arg
, &freed
);
450 set_state_expr(my_id
, arg
, &freed
);
451 set_other_states(my_id
, arg
, &freed
);
454 static void match_kobject_put(const char *fn
, struct expression
*expr
, void *param
)
456 struct expression
*arg
;
458 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
461 /* kobject_put(&cdev->kobj); */
462 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
464 arg
= strip_expr(arg
->unop
);
465 if (arg
->type
!= EXPR_DEREF
)
467 arg
= strip_expr(arg
->deref
);
468 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
470 arg
= strip_expr(arg
->unop
);
471 track_freed_param(arg
, &maybe_freed
);
472 set_state_expr(my_id
, arg
, &maybe_freed
);
475 struct string_list
*handled
;
476 static bool is_handled_func(struct expression
*fn
)
478 if (!fn
|| fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
->ident
)
481 return list_has_string(handled
, fn
->symbol
->ident
->name
);
484 static void set_param_helper(struct expression
*expr
, int param
,
485 char *key
, char *value
,
486 struct smatch_state
*state
)
488 struct expression
*arg
;
493 while (expr
->type
== EXPR_ASSIGNMENT
)
494 expr
= strip_expr(expr
->right
);
495 if (expr
->type
!= EXPR_CALL
)
498 if (is_handled_func(expr
->fn
))
501 arg
= get_argument_from_call_expr(expr
->args
, param
);
504 name
= get_variable_from_key(arg
, key
, &sym
);
508 /* skbs are not free if we called skb_get(). */
509 if (counter_was_inced_name_sym(name
, sym
, "->users.refs.counter"))
512 if (state
== &freed
&& !is_impossible_path()) {
513 sm
= get_sm_state(my_id
, name
, sym
);
514 if (sm
&& slist_has_state(sm
->possible
, &freed
)) {
515 sm_warning("'%s' double freed", name
);
516 set_state(my_id
, name
, sym
, &ok
); /* fixme: doesn't silence anything. I know */
520 track_freed_param_var_sym(name
, sym
, state
);
521 set_state(my_id
, name
, sym
, state
);
522 set_other_states_name_sym(my_id
, name
, sym
, state
);
527 static void set_param_freed(struct expression
*expr
, int param
, char *key
, char *value
)
529 set_param_helper(expr
, param
, key
, value
, &freed
);
532 static void set_param_maybe_freed(struct expression
*expr
, int param
, char *key
, char *value
)
534 set_param_helper(expr
, param
, key
, value
, &maybe_freed
);
537 int parent_is_free_var_sym_strict(const char *name
, struct symbol
*sym
)
543 struct smatch_state
*state
;
545 strncpy(buf
, name
, sizeof(buf
) - 1);
546 buf
[sizeof(buf
) - 1] = '\0';
549 while ((*start
== '&'))
553 while ((end
= strrchr(end
, '-'))) {
557 state
= __get_state(my_id
, start
, sym
);
566 int parent_is_free_strict(struct expression
*expr
)
572 expr
= strip_expr(expr
);
573 var
= expr_to_var_sym(expr
, &sym
);
576 ret
= parent_is_free_var_sym_strict(var
, sym
);
582 static void match_untracked(struct expression
*call
, int param
)
584 struct state_list
*slist
= NULL
;
585 struct expression
*arg
;
591 arg
= get_argument_from_call_expr(call
->args
, param
);
595 name
= expr_to_var(arg
);
598 snprintf(buf
, sizeof(buf
), "%s->", name
);
602 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
603 if (strncmp(sm
->name
, buf
, len
) == 0)
604 add_ptr_list(&slist
, sm
);
605 } END_FOR_EACH_SM(sm
);
607 FOR_EACH_PTR(slist
, sm
) {
608 set_state(sm
->owner
, sm
->name
, sm
->sym
, &ok
);
609 } END_FOR_EACH_PTR(sm
);
614 void add_free_hook(const char *func
, func_hook
*call_back
, int param
)
616 insert_string(&handled
, func
);
617 add_function_hook(func
, call_back
, INT_PTR(param
));
620 void check_free_strict(int id
)
624 if (option_project
!= PROJ_KERNEL
)
627 add_free_hook("free", &match_free
, 0);
628 add_free_hook("kfree", &match_free
, 0);
629 add_free_hook("vfree", &match_free
, 0);
630 add_free_hook("kzfree", &match_free
, 0);
631 add_free_hook("kvfree", &match_free
, 0);
632 add_free_hook("kmem_cache_free", &match_free
, 1);
633 add_free_hook("mempool_free", &match_free
, 0);
634 add_free_hook("kfree_skb", &match_free
, 0);
635 add_free_hook("kfree_skbmem", &match_free
, 0);
636 add_free_hook("dma_pool_free", &match_free
, 1);
637 // add_free_hook("spi_unregister_controller", &match_free, 0);
638 add_free_hook("netif_rx_internal", &match_free
, 0);
639 add_free_hook("netif_rx", &match_free
, 0);
640 add_free_hook("enqueue_to_backlog", &match_free
, 0);
642 add_free_hook("brelse", &match_free
, 0);
643 add_free_hook("kobject_put", &match_kobject_put
, 0);
644 add_free_hook("kref_put", &match_kobject_put
, 0);
645 add_free_hook("put_device", &match_kobject_put
, 0);
647 add_free_hook("dma_free_coherent", match_free
, 2);
650 add_hook(&match_symbol
, SYM_HOOK
);
651 add_hook(&match_dereferences
, DEREF_HOOK
);
652 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
653 add_hook(&match_return
, RETURN_HOOK
);
655 add_modification_hook_late(my_id
, &ok_to_use
);
656 add_pre_merge_hook(my_id
, &pre_merge_hook
);
657 add_unmatched_state_hook(my_id
, &unmatched_state
);
658 add_merge_hook(my_id
, &merge_frees
);
660 select_return_states_hook(PARAM_FREED
, &set_param_freed
);
661 select_return_states_hook(MAYBE_FREED
, &set_param_maybe_freed
);
662 add_untracked_param_hook(&match_untracked
);