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 match_kobject_put(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
);
45 const sval_t
*implies_start
, *implies_end
;
46 param_key_hook
*call_back
;
49 static struct func_info func_table
[] = {
50 { "free", PARAM_FREED
, 0, "$" },
51 { "kfree", PARAM_FREED
, 0, "$" },
52 { "vfree", PARAM_FREED
, 0, "$" },
53 { "kzfree", PARAM_FREED
, 0, "$" },
54 { "kvfree", PARAM_FREED
, 0, "$" },
56 { "kfree_skb", PARAM_FREED
, 0, "$" },
57 { "kfree_skbmem", PARAM_FREED
, 0, "$" },
59 { "mempool_free", PARAM_FREED
, 0, "$" },
60 { "kmem_cache_free", PARAM_FREED
, 1, "$" },
61 { "dma_pool_free", PARAM_FREED
, 1, "$" },
63 { "memstick_free_host", PARAM_FREED
, 0, "$" },
64 // { "spi_unregister_controller", PARAM_FREED, 0, "$" },
65 { "netif_rx_internal", PARAM_FREED
, 0, "$" },
66 { "netif_rx", PARAM_FREED
, 0, "$" },
68 { "enqueue_to_backlog", PARAM_FREED
, 0, "$" },
70 { "brelse", PARAM_FREED
, 0, "$" },
71 { "dma_free_coherent", PARAM_FREED
, 2, "$" },
72 { "free_netdev", PARAM_FREED
, 0, "$" },
73 { "sock_release", PARAM_FREED
, 0, "$" },
75 { "qdisc_enqueue", PARAM_FREED
, 0, "$" },
77 { "kobject_put", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
78 { "kref_put", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
79 { "put_device", PARAM_FREED
, 0, "$", NULL
, NULL
, &match_kobject_put
},
82 static struct name_sym_fn_list
*free_hooks
;
84 void add_free_hook(name_sym_hook
*hook
)
86 add_ptr_list(&free_hooks
, hook
);
89 static void call_free_call_backs_name_sym(struct expression
*expr
, const char *name
, struct symbol
*sym
)
94 expr
= gen_expression_from_name_sym(name
, sym
);
96 FOR_EACH_PTR(free_hooks
, hook
) {
97 hook(expr
, name
, sym
);
98 } END_FOR_EACH_PTR(hook
);
101 static void ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
103 if (sm
->state
!= &ok
)
104 set_state(my_id
, sm
->name
, sm
->sym
, &ok
);
107 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
109 if (is_impossible_path())
110 set_state(my_id
, cur
->name
, cur
->sym
, &ok
);
113 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
115 struct smatch_state
*state
;
118 if (sm
->state
!= &freed
&& sm
->state
!= &maybe_freed
)
121 if (get_param_num_from_sym(sm
->sym
) < 0)
125 * If the parent is non-there count it as freed. This is
126 * a hack for tracking return states.
128 if (parent_is_null_var_sym(sm
->name
, sm
->sym
))
131 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
134 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
136 /* It makes it easier to consider NULL pointers as freed. */
140 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
142 if (s1
== &freed
&& s2
== &maybe_freed
)
144 if (s1
== &maybe_freed
&& s2
== &freed
)
149 static int is_freed(struct expression
*expr
)
153 sm
= get_sm_state_expr(my_id
, expr
);
154 if (sm
&& slist_has_state(sm
->possible
, &freed
))
159 bool is_freed_var_sym(const char *name
, struct symbol
*sym
)
161 struct smatch_state
*state
;
163 state
= get_state(my_id
, name
, sym
);
164 if (state
== &freed
|| state
== &maybe_freed
)
170 static bool expr_is_condition(struct expression
*expr
)
172 struct statement
*stmt
;
174 stmt
= expr_get_parent_stmt(expr
);
177 if (stmt
->type
== STMT_IF
|| stmt
->type
== STMT_ITERATOR
)
182 bool is_part_of_condition(struct expression
*expr
)
184 struct expression
*parent
;
186 if (expr_is_condition(expr
))
189 parent
= expr_get_parent_expr(expr
);
192 if (parent
->type
== EXPR_LOGICAL
|| parent
->type
== EXPR_COMPARE
)
194 if (parent
->type
== EXPR_SELECT
|| parent
->type
== EXPR_CONDITIONAL
)
196 if (parent
->type
== EXPR_PREOP
&& parent
->op
== '!')
202 static bool is_percent_p(struct expression
*str_expr
, int idx
)
207 p
= str_expr
->string
->data
;
209 if (p
[0] == '%' && p
[1] == '%') {
213 /* If we have print("%.*s %p", prec, str, p); then it takes 2 params */
214 if ((p
[0] == '%' && p
[1] == '*') ||
215 (p
[0] == '%' && p
[1] == '.' && p
[2] == '*'))
219 if (idx
== cnt
&& p
[1] == 'p')
227 bool is_percent_p_print(struct expression
*expr
)
229 struct expression
*parent
, *arg
;
230 int expr_idx
, string_idx
;
232 parent
= expr_get_parent_expr(expr
);
233 if (!parent
|| parent
->type
!= EXPR_CALL
)
237 FOR_EACH_PTR(parent
->args
, arg
) {
241 } END_FOR_EACH_PTR(arg
);
247 FOR_EACH_PTR(parent
->args
, arg
) {
249 if (arg
->type
!= EXPR_STRING
)
251 if (is_percent_p(arg
, expr_idx
- string_idx
))
253 } END_FOR_EACH_PTR(arg
);
258 static void match_symbol(struct expression
*expr
)
260 struct expression
*parent
;
263 if (is_impossible_path())
265 if (__in_fake_parameter_assign
)
268 if (is_part_of_condition(expr
))
271 /* This ignores stuff like "get_new_ptr(&foo);" */
272 parent
= expr_get_parent_expr(expr
);
273 while (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '(')
274 parent
= expr_get_parent_expr(parent
);
275 if (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
281 if (is_percent_p_print(expr
))
284 name
= expr_to_var(expr
);
285 sm_warning("'%s' was already freed.", name
);
289 static void match_dereferences(struct expression
*expr
)
293 if (expr
->type
!= EXPR_PREOP
)
296 if (is_impossible_path())
298 if (__in_fake_parameter_assign
)
301 expr
= strip_expr(expr
->unop
);
304 name
= expr_to_var(expr
);
305 sm_error("dereferencing freed memory '%s'", name
);
306 set_state_expr(my_id
, expr
, &ok
);
310 static int ignored_params
[16];
312 static void set_ignored_params(struct expression
*call
)
314 struct expression
*arg
;
318 memset(&ignored_params
, 0, sizeof(ignored_params
));
321 FOR_EACH_PTR(call
->args
, arg
) {
323 if (arg
->type
!= EXPR_STRING
)
326 } END_FOR_EACH_PTR(arg
);
332 p
= arg
->string
->data
;
333 while ((p
= strchr(p
, '%'))) {
334 if (i
>= ARRAY_SIZE(ignored_params
))
346 ignored_params
[i
] = 1;
351 static int is_free_func(struct expression
*fn
)
356 name
= expr_to_str(fn
);
359 if (strstr(name
, "free"))
366 static void match_call(struct expression
*expr
)
368 struct expression
*arg
;
372 if (is_impossible_path())
375 set_ignored_params(expr
);
378 FOR_EACH_PTR(expr
->args
, arg
) {
380 if (!is_pointer(arg
))
384 if (ignored_params
[i
])
386 if (is_percent_p_print(arg
))
389 name
= expr_to_var(arg
);
390 if (is_free_func(expr
->fn
))
391 sm_error("double free of '%s'", name
);
393 sm_warning("passing freed memory '%s'", name
);
394 set_state_expr(my_id
, arg
, &ok
);
396 } END_FOR_EACH_PTR(arg
);
399 static void match_return(struct expression
*expr
)
403 if (is_impossible_path())
411 name
= expr_to_var(expr
);
412 sm_warning("returning freed memory '%s'", name
);
413 set_state_expr(my_id
, expr
, &ok
);
417 static int counter_was_inced_name_sym(const char *name
, struct symbol
*sym
, const char *counter_str
)
421 snprintf(buf
, sizeof(buf
), "%s%s", name
, counter_str
);
422 return was_inced(buf
, sym
);
425 static int counter_was_inced(struct expression
*expr
, const char *counter_str
)
431 name
= expr_to_var_sym(expr
, &sym
);
435 ret
= counter_was_inced_name_sym(name
, sym
, counter_str
);
441 static bool is_ptr_to(struct expression
*expr
, const char *type
)
445 sym
= get_type(expr
);
446 if (!is_ptr_type(sym
))
448 sym
= get_real_base_type(sym
);
449 if (sym
&& sym
->ident
&& strcmp(sym
->ident
->name
, type
) == 0)
454 static void match_free(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
456 struct expression
*arg
;
458 if (is_impossible_path())
461 arg
= gen_expression_from_name_sym(name
, sym
);
464 if (is_ptr_to(arg
, "sk_buff") &&
465 counter_was_inced(arg
, "->users.refs.counter"))
467 if (is_ptr_to(arg
, "buffer_head") &&
468 counter_was_inced(arg
, "->b_count.counter"))
471 sm_error("double free of '%s'", name
);
473 track_freed_param(arg
, &freed
);
474 call_free_call_backs_name_sym(expr
, name
, sym
);
475 set_state_expr(my_id
, arg
, &freed
);
479 static void match_kobject_put(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
481 struct expression
*arg
;
483 arg
= gen_expression_from_name_sym(name
, sym
);
486 /* kobject_put(&cdev->kobj); */
487 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
489 arg
= strip_expr(arg
->unop
);
490 if (arg
->type
!= EXPR_DEREF
)
492 arg
= strip_expr(arg
->deref
);
493 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
495 arg
= strip_expr(arg
->unop
);
496 track_freed_param(arg
, &maybe_freed
);
497 set_state_expr(my_id
, arg
, &maybe_freed
);
500 struct string_list
*handled
;
501 static bool is_handled_func(struct expression
*fn
)
503 if (!fn
|| fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
->ident
)
506 return list_has_string(handled
, fn
->symbol
->ident
->name
);
509 static void set_param_helper(struct expression
*expr
, int param
,
510 char *key
, char *value
,
511 struct smatch_state
*state
)
513 struct expression
*arg
;
518 while (expr
->type
== EXPR_ASSIGNMENT
)
519 expr
= strip_expr(expr
->right
);
520 if (expr
->type
!= EXPR_CALL
)
523 if (is_handled_func(expr
->fn
))
526 arg
= get_argument_from_call_expr(expr
->args
, param
);
529 name
= get_variable_from_key(arg
, key
, &sym
);
533 /* skbs are not free if we called skb_get(). */
534 if (counter_was_inced_name_sym(name
, sym
, "->users.refs.counter"))
537 if (state
== &freed
&& !is_impossible_path()) {
538 sm
= get_sm_state(my_id
, name
, sym
);
539 if (sm
&& slist_has_state(sm
->possible
, &freed
)) {
540 sm_warning("'%s' double freed", name
);
541 set_state(my_id
, name
, sym
, &ok
); /* fixme: doesn't silence anything. I know */
545 track_freed_param_var_sym(name
, sym
, state
);
547 call_free_call_backs_name_sym(NULL
, name
, sym
);
548 set_state(my_id
, name
, sym
, state
);
553 static void set_param_freed(struct expression
*expr
, int param
, char *key
, char *value
)
555 set_param_helper(expr
, param
, key
, value
, &freed
);
558 static void set_param_maybe_freed(struct expression
*expr
, int param
, char *key
, char *value
)
560 set_param_helper(expr
, param
, key
, value
, &maybe_freed
);
563 int parent_is_free_var_sym_strict(const char *name
, struct symbol
*sym
)
569 struct smatch_state
*state
;
571 strncpy(buf
, name
, sizeof(buf
) - 1);
572 buf
[sizeof(buf
) - 1] = '\0';
575 while ((*start
== '&'))
579 while ((end
= strrchr(end
, '-'))) {
583 state
= __get_state(my_id
, start
, sym
);
592 int parent_is_free_strict(struct expression
*expr
)
598 expr
= strip_expr(expr
);
599 var
= expr_to_var_sym(expr
, &sym
);
602 ret
= parent_is_free_var_sym_strict(var
, sym
);
608 static void match_untracked(struct expression
*call
, int param
)
610 struct state_list
*slist
= NULL
;
611 struct expression
*arg
;
617 arg
= get_argument_from_call_expr(call
->args
, param
);
621 name
= expr_to_var(arg
);
624 snprintf(buf
, sizeof(buf
), "%s->", name
);
628 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
629 if (strncmp(sm
->name
, buf
, len
) == 0)
630 add_ptr_list(&slist
, sm
);
631 } END_FOR_EACH_SM(sm
);
633 FOR_EACH_PTR(slist
, sm
) {
634 set_state(sm
->owner
, sm
->name
, sm
->sym
, &ok
);
635 } END_FOR_EACH_PTR(sm
);
640 void check_free_strict(int id
)
642 struct func_info
*info
;
648 if (option_project
!= PROJ_KERNEL
)
651 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
652 info
= &func_table
[i
];
654 insert_string(&handled
, info
->name
);
657 cb
= info
->call_back
;
661 if (info
->implies_start
) {
662 return_implies_param_key(info
->name
,
663 *info
->implies_start
, *info
->implies_end
,
664 cb
, info
->param
, info
->key
, info
);
666 add_function_param_key_hook(info
->name
, cb
,
667 info
->param
, info
->key
, info
);
672 add_hook(&match_symbol
, SYM_HOOK
);
673 add_hook(&match_dereferences
, DEREF_HOOK
);
674 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
675 add_hook(&match_return
, RETURN_HOOK
);
677 add_modification_hook_late(my_id
, &ok_to_use
);
678 add_pre_merge_hook(my_id
, &pre_merge_hook
);
679 add_unmatched_state_hook(my_id
, &unmatched_state
);
680 add_merge_hook(my_id
, &merge_frees
);
682 select_return_states_hook(PARAM_FREED
, &set_param_freed
);
683 select_return_states_hook(MAYBE_FREED
, &set_param_maybe_freed
);
684 add_untracked_param_hook(&match_untracked
);