1 /* SPDX-License-Identifier: MIT
3 * Copyright (C) 2021 Pavel Skripkin
8 * Try to find a way how to handle situations like:
10 * struct some_dev *dev = get_dev_from_smth(smth);
12 * free_netdev(dev->netdev);
16 * In this case dev is dev->netdev private data (exmpl: ems_usb_disconnect())
20 #include "smatch_extra.h"
21 #include "smatch_function_hashtable.h"
27 static void ok_to_use(struct sm_state
*sm
, struct expression
*mod_expr
)
30 set_state(my_id
, sm
->name
, sm
->sym
, &ok
);
33 static inline char *get_function_name(struct expression
*expr
)
35 if (!expr
|| expr
->type
!= EXPR_CALL
)
37 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol_name
)
39 return expr
->fn
->symbol_name
->name
;
42 static inline int is_netdev_priv(struct expression
*call
)
46 if (!call
|| call
->type
!= EXPR_CALL
)
49 name
= get_function_name(call
);
53 return !strcmp("netdev_priv", name
);
56 static const char *get_parent_netdev_name(struct expression
*expr
)
58 struct expression
*call
, *arg_expr
= NULL
;
61 call
= get_assigned_expr(strip_expr(expr
));
62 if (is_netdev_priv(call
)) {
63 arg_expr
= get_argument_from_call_expr(call
->args
, 0);
64 arg_expr
= strip_expr(arg_expr
);
69 return expr_to_var_sym(arg_expr
, &sym
);
72 static void match_free_netdev(const char *fn
, struct expression
*expr
, void *_arg_no
)
74 struct expression
*arg
;
77 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(_arg_no
));
81 name
= expr_to_var(arg
);
85 set_state(my_id
, name
, NULL
, &freed
);
88 static void match_symbol(struct expression
*expr
)
90 const char *parent_netdev
, *name
;
91 struct smatch_state
*state
;
93 if (!has_states(__get_cur_stree(), my_id
))
96 name
= expr_to_var(expr
);
100 parent_netdev
= get_parent_netdev_name(expr
);
104 state
= get_state(my_id
, parent_netdev
, NULL
);
106 sm_error("Using '%s' after free_{netdev,candev}(%s);\n", name
, parent_netdev
);
109 void check_uaf_netdev_priv(int id
)
111 if (option_project
!= PROJ_KERNEL
)
116 add_function_hook("free_netdev", &match_free_netdev
, NULL
);
117 add_function_hook("free_candev", &match_free_netdev
, NULL
);
118 add_modification_hook(my_id
, &ok_to_use
);
119 add_hook(&match_symbol
, SYM_HOOK
);