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
)
59 * If the parent is non-there count it as freed. This is
60 * a hack for tracking return states.
62 if (parent_is_null_var_sym(sm
->name
, sm
->sym
))
65 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
68 if (!estate_get_single_value(state
, &sval
) || sval
.value
!= 0)
70 /* It makes it easier to consider NULL pointers as freed. */
74 struct smatch_state
*merge_frees(struct smatch_state
*s1
, struct smatch_state
*s2
)
76 if (s1
== &freed
&& s2
== &maybe_freed
)
78 if (s1
== &maybe_freed
&& s2
== &freed
)
83 static int is_freed(struct expression
*expr
)
87 sm
= get_sm_state_expr(my_id
, expr
);
88 if (sm
&& slist_has_state(sm
->possible
, &freed
))
93 bool is_freed_var_sym(const char *name
, struct symbol
*sym
)
95 struct smatch_state
*state
;
97 state
= get_state(my_id
, name
, sym
);
98 if (state
== &freed
|| state
== &maybe_freed
)
104 static void match_symbol(struct expression
*expr
)
106 struct expression
*parent
;
109 if (is_impossible_path())
111 if (__in_fake_parameter_assign
)
114 parent
= expr_get_parent_expr(expr
);
115 while (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '(')
116 parent
= expr_get_parent_expr(parent
);
117 if (parent
&& parent
->type
== EXPR_PREOP
&& parent
->op
== '&')
122 name
= expr_to_var(expr
);
123 sm_warning("'%s' was already freed.", name
);
127 static void match_dereferences(struct expression
*expr
)
131 if (expr
->type
!= EXPR_PREOP
)
134 if (is_impossible_path())
136 if (__in_fake_parameter_assign
)
139 expr
= strip_expr(expr
->unop
);
142 name
= expr_to_var(expr
);
143 sm_error("dereferencing freed memory '%s'", name
);
144 set_state_expr(my_id
, expr
, &ok
);
148 static int ignored_params
[16];
150 static void set_ignored_params(struct expression
*call
)
152 struct expression
*arg
;
156 memset(&ignored_params
, 0, sizeof(ignored_params
));
159 FOR_EACH_PTR(call
->args
, arg
) {
161 if (arg
->type
!= EXPR_STRING
)
164 } END_FOR_EACH_PTR(arg
);
170 p
= arg
->string
->data
;
171 while ((p
= strchr(p
, '%'))) {
172 if (i
>= ARRAY_SIZE(ignored_params
))
184 ignored_params
[i
] = 1;
189 static int is_free_func(struct expression
*fn
)
194 name
= expr_to_str(fn
);
197 if (strstr(name
, "free"))
204 static void match_call(struct expression
*expr
)
206 struct expression
*arg
;
210 if (is_impossible_path())
213 set_ignored_params(expr
);
216 FOR_EACH_PTR(expr
->args
, arg
) {
218 if (!is_pointer(arg
))
222 if (ignored_params
[i
])
225 name
= expr_to_var(arg
);
226 if (is_free_func(expr
->fn
))
227 sm_error("double free of '%s'", name
);
229 sm_warning("passing freed memory '%s'", name
);
230 set_state_expr(my_id
, arg
, &ok
);
232 } END_FOR_EACH_PTR(arg
);
235 static void match_return(struct expression
*expr
)
239 if (is_impossible_path())
247 name
= expr_to_var(expr
);
248 sm_warning("returning freed memory '%s'", name
);
249 set_state_expr(my_id
, expr
, &ok
);
253 static int counter_was_inced(struct expression
*expr
)
260 name
= expr_to_var_sym(expr
, &sym
);
264 snprintf(buf
, sizeof(buf
), "%s->users.counter", name
);
265 ret
= was_inced(buf
, sym
);
271 void set_other_states_name_sym(int owner
, const char *name
, struct symbol
*sym
, struct smatch_state
*state
)
273 struct expression
*tmp
;
276 FOR_EACH_MY_SM(check_assigned_expr_id
, __get_cur_stree(), sm
) {
277 tmp
= sm
->state
->data
;
280 if (tmp
->type
!= EXPR_SYMBOL
)
282 if (tmp
->symbol
!= sym
)
284 if (!tmp
->symbol_name
)
286 if (strcmp(tmp
->symbol_name
->name
, name
) != 0)
288 set_state(owner
, tmp
->symbol_name
->name
, tmp
->symbol
, state
);
289 } END_FOR_EACH_SM(sm
);
291 tmp
= get_assigned_expr_name_sym(name
, sym
);
293 set_state_expr(owner
, tmp
, state
);
296 void set_other_states(int owner
, struct expression
*expr
, struct smatch_state
*state
)
301 name
= expr_to_var_sym(expr
, &sym
);
305 set_other_states_name_sym(owner
, name
, sym
, state
);
311 static void match_free(const char *fn
, struct expression
*expr
, void *param
)
313 struct expression
*arg
;
315 if (is_impossible_path())
318 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
321 if (strcmp(fn
, "kfree_skb") == 0 && counter_was_inced(arg
))
324 char *name
= expr_to_var(arg
);
326 sm_error("double free of '%s'", name
);
329 track_freed_param(arg
, &freed
);
330 set_state_expr(my_id
, arg
, &freed
);
331 set_other_states(my_id
, arg
, &freed
);
334 static void match_kobject_put(const char *fn
, struct expression
*expr
, void *param
)
336 struct expression
*arg
;
338 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
341 /* kobject_put(&cdev->kobj); */
342 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '&')
344 arg
= strip_expr(arg
->unop
);
345 if (arg
->type
!= EXPR_DEREF
)
347 arg
= strip_expr(arg
->deref
);
348 if (arg
->type
!= EXPR_PREOP
|| arg
->op
!= '*')
350 arg
= strip_expr(arg
->unop
);
351 track_freed_param(arg
, &maybe_freed
);
352 set_state_expr(my_id
, arg
, &maybe_freed
);
355 struct string_list
*handled
;
356 static bool is_handled_func(struct expression
*fn
)
358 if (!fn
|| fn
->type
!= EXPR_SYMBOL
|| !fn
->symbol
->ident
)
361 return list_has_string(handled
, fn
->symbol
->ident
->name
);
364 static void set_param_helper(struct expression
*expr
, int param
,
365 char *key
, char *value
,
366 struct smatch_state
*state
)
368 struct expression
*arg
;
373 while (expr
->type
== EXPR_ASSIGNMENT
)
374 expr
= strip_expr(expr
->right
);
375 if (expr
->type
!= EXPR_CALL
)
378 if (is_handled_func(expr
->fn
))
381 arg
= get_argument_from_call_expr(expr
->args
, param
);
384 name
= get_variable_from_key(arg
, key
, &sym
);
388 if (state
== &freed
&& !is_impossible_path()) {
389 sm
= get_sm_state(my_id
, name
, sym
);
390 if (sm
&& slist_has_state(sm
->possible
, &freed
)) {
391 sm_warning("'%s' double freed", name
);
392 set_state(my_id
, name
, sym
, &ok
); /* fixme: doesn't silence anything. I know */
396 track_freed_param_var_sym(name
, sym
, state
);
397 set_state(my_id
, name
, sym
, state
);
398 set_other_states_name_sym(my_id
, name
, sym
, state
);
403 static void set_param_freed(struct expression
*expr
, int param
, char *key
, char *value
)
405 set_param_helper(expr
, param
, key
, value
, &freed
);
408 static void set_param_maybe_freed(struct expression
*expr
, int param
, char *key
, char *value
)
410 set_param_helper(expr
, param
, key
, value
, &maybe_freed
);
413 int parent_is_free_var_sym_strict(const char *name
, struct symbol
*sym
)
419 struct smatch_state
*state
;
421 strncpy(buf
, name
, sizeof(buf
) - 1);
422 buf
[sizeof(buf
) - 1] = '\0';
425 while ((*start
== '&'))
429 while ((end
= strrchr(end
, '-'))) {
433 state
= __get_state(my_id
, start
, sym
);
442 int parent_is_free_strict(struct expression
*expr
)
448 expr
= strip_expr(expr
);
449 var
= expr_to_var_sym(expr
, &sym
);
452 ret
= parent_is_free_var_sym_strict(var
, sym
);
458 static void match_untracked(struct expression
*call
, int param
)
460 struct state_list
*slist
= NULL
;
461 struct expression
*arg
;
467 arg
= get_argument_from_call_expr(call
->args
, param
);
471 name
= expr_to_var(arg
);
474 snprintf(buf
, sizeof(buf
), "%s->", name
);
478 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
479 if (strncmp(sm
->name
, buf
, len
) == 0)
480 add_ptr_list(&slist
, sm
);
481 } END_FOR_EACH_SM(sm
);
483 FOR_EACH_PTR(slist
, sm
) {
484 set_state(sm
->owner
, sm
->name
, sm
->sym
, &ok
);
485 } END_FOR_EACH_PTR(sm
);
490 void add_free_hook(const char *func
, func_hook
*call_back
, int param
)
492 insert_string(&handled
, func
);
493 add_function_hook(func
, call_back
, INT_PTR(param
));
496 void check_free_strict(int id
)
500 if (option_project
!= PROJ_KERNEL
)
503 add_free_hook("free", &match_free
, 0);
504 add_free_hook("kfree", &match_free
, 0);
505 add_free_hook("vfree", &match_free
, 0);
506 add_free_hook("kzfree", &match_free
, 0);
507 add_free_hook("kvfree", &match_free
, 0);
508 add_free_hook("kmem_cache_free", &match_free
, 1);
509 add_free_hook("kfree_skb", &match_free
, 0);
510 add_free_hook("kfree_skbmem", &match_free
, 0);
511 add_free_hook("dma_pool_free", &match_free
, 1);
512 // add_free_hook("spi_unregister_controller", &match_free, 0);
513 add_free_hook("netif_rx_internal", &match_free
, 0);
514 add_free_hook("netif_rx", &match_free
, 0);
515 add_free_hook("enqueue_to_backlog", &match_free
, 0);
517 add_free_hook("brelse", &match_free
, 0);
518 add_free_hook("kobject_put", &match_kobject_put
, 0);
519 add_free_hook("kref_put", &match_kobject_put
, 0);
520 add_free_hook("put_device", &match_kobject_put
, 0);
522 add_free_hook("dma_free_coherent", match_free
, 2);
525 add_hook(&match_symbol
, SYM_HOOK
);
526 add_hook(&match_dereferences
, DEREF_HOOK
);
527 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
528 add_hook(&match_return
, RETURN_HOOK
);
530 add_modification_hook_late(my_id
, &ok_to_use
);
531 add_pre_merge_hook(my_id
, &pre_merge_hook
);
532 add_unmatched_state_hook(my_id
, &unmatched_state
);
533 add_merge_hook(my_id
, &merge_frees
);
535 select_return_states_hook(PARAM_FREED
, &set_param_freed
);
536 select_return_states_hook(MAYBE_FREED
, &set_param_maybe_freed
);
537 add_untracked_param_hook(&match_untracked
);