* [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
@ 2021-08-02 21:00 Pavel Skripkin
2021-08-03 15:08 ` Dan Carpenter
2021-08-04 14:35 ` Dan Carpenter
0 siblings, 2 replies; 8+ messages in thread
From: Pavel Skripkin @ 2021-08-02 21:00 UTC (permalink / raw)
To: smatch; +Cc: Pavel Skripkin
After manual code review I found a lot of bugs, when code uses
netdev_priv() pointer after free_{netdev,candev} call. Example:
struct some_dev *dev = netdev_priv(net_dev);
free_netdev(net_dev);
do_clean_up(dev);
Obviously, that above code snippet will trigger UAF bug, since dev
pointer goes away with net_dev. Since there isn't any check for this
type of bug in other static analysis tools, let's add it to smatch.
Side note: this code requires further work to be able to find complex
situtations like
struct some_dev *dev = get_dev_from_smth(smth);
free_netdev(dev->netdev);
do_clean_up(dev);
In this case dev is dev->netdev private data and it's a bit difficult to
to figure out if ->netdev is actual dev _parent_ or not.
Signed-off-by: Pavel Skripkin <paskripkin@gmail.com>
---
check_list.h | 1 +
check_netdev_priv.c | 117 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 118 insertions(+)
create mode 100644 check_netdev_priv.c
diff --git a/check_list.h b/check_list.h
index fd205269..972b2795 100644
--- a/check_list.h
+++ b/check_list.h
@@ -203,6 +203,7 @@ CK(check_list_add)
CK(check_list_add_late)
CK(check_sscanf_return)
CK(check_kvmalloc_NOFS)
+CK(check_uaf_netdev_priv)
/* wine specific stuff */
CK(check_wine_filehandles)
diff --git a/check_netdev_priv.c b/check_netdev_priv.c
new file mode 100644
index 00000000..87d373b5
--- /dev/null
+++ b/check_netdev_priv.c
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2021 Pavel Skripkin
+ */
+
+/* TODO:
+ *
+ * Try to find a way how to handle situations like:
+ *
+ * struct some_dev *dev = get_dev_from_smth(smth);
+ *
+ * free_netdev(dev->netdev);
+ * do_clean_up(dev);
+ *
+ *
+ * In this case dev is dev->netdev private data (exmpl: ems_usb_disconnect())
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+#include "smatch_function_hashtable.h"
+
+static int my_id;
+STATE(freed);
+STATE(ok);
+
+static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
+{
+ if (sm->state != &ok)
+ set_state(my_id, sm->name, sm->sym, &ok);
+}
+
+static inline char *get_function_name(struct expression *expr)
+{
+ if (!expr || expr->type != EXPR_CALL)
+ return NULL;
+ if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol_name)
+ return NULL;
+ return expr->fn->symbol_name->name;
+}
+
+static inline int is_netdev_priv(struct expression *call)
+{
+ char *name;
+
+ if (!call || call->type != EXPR_CALL)
+ return 0;
+
+ name = get_function_name(call);
+ if (!name)
+ return 0;
+
+ return !strcmp("netdev_priv", name);
+}
+
+static const char *get_parent_netdev_name(struct expression *expr)
+{
+ struct expression *call, *arg_expr = NULL;
+ struct symbol *sym;
+
+ call = get_assigned_expr(strip_expr(expr));
+ if (is_netdev_priv(call)) {
+ arg_expr = get_argument_from_call_expr(call->args, 0);
+ arg_expr = strip_expr(arg_expr);
+ } else {
+ return NULL;
+ }
+
+ return expr_to_var_sym(arg_expr, &sym);
+}
+
+static void match_free_netdev(const char *fn, struct expression *expr, void *_arg_no)
+{
+ struct expression *arg;
+ const char *name;
+
+ arg = get_argument_from_call_expr(expr->args, PTR_INT(_arg_no));
+ if (!arg)
+ return;
+
+ name = expr_to_var(arg);
+ if (!name)
+ return;
+
+ set_state(my_id, name, NULL, &freed);
+}
+
+static void match_symbol(struct expression *expr)
+{
+ const char *parent_netdev, *name;
+ struct smatch_state *state;
+
+ name = expr_to_var(expr);
+ if (!name)
+ return;
+
+ parent_netdev = get_parent_netdev_name(expr);
+ if (!parent_netdev)
+ return;
+
+ state = get_state(my_id, parent_netdev, NULL);
+ if (state == &freed)
+ sm_error("Using %s after free_{netdev,candev}(%s);\n", name, parent_netdev);
+}
+
+void check_uaf_netdev_priv(int id)
+{
+ if (option_project != PROJ_KERNEL)
+ return;
+
+ my_id = id;
+
+ add_function_hook("free_netdev", &match_free_netdev, NULL);
+ add_function_hook("free_candev", &match_free_netdev, NULL);
+ add_modification_hook(my_id, &ok_to_use);
+ add_hook(&match_symbol, SYM_HOOK);
+}
--
2.32.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-02 21:00 [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev Pavel Skripkin
@ 2021-08-03 15:08 ` Dan Carpenter
2021-08-03 16:03 ` Pavel Skripkin
2021-08-04 14:35 ` Dan Carpenter
1 sibling, 1 reply; 8+ messages in thread
From: Dan Carpenter @ 2021-08-03 15:08 UTC (permalink / raw)
To: Pavel Skripkin; +Cc: smatch
Thanks Pavel!
It looks really nice. I've applied it. I'll test it tonight and push
tomorrow.
I don't see any major issues with the check at all, but I have a few
comments below.
On Tue, Aug 03, 2021 at 12:00:22AM +0300, Pavel Skripkin wrote:
> +static void match_free_netdev(const char *fn, struct expression *expr, void *_arg_no)
> +{
> + struct expression *arg;
> + const char *name;
> +
> + arg = get_argument_from_call_expr(expr->args, PTR_INT(_arg_no));
> + if (!arg)
> + return;
> +
> + name = expr_to_var(arg);
> + if (!name)
> + return;
> +
> + set_state(my_id, name, NULL, &freed);
> +}
There is a new param_key API which would make this function shorter.
static void free_netdev(struct expression *expr, const char *name, struct symbol *sym, void *data)
{
set_state(my_id, name, NULL, &freed);
}
Then in the register function you'd add a hooks like this:
add_function_param_key_hook("free_netdev", &free_netdev, 0, "$", NULL);
add_function_param_key_hook("free_candev", &free_netdev, 0, "$", NULL);
Of course, you've already written your own code which works so it's
fine. But that param_key API is really the most awesome thing.
> +
> +static void match_symbol(struct expression *expr)
> +{
> + const char *parent_netdev, *name;
> + struct smatch_state *state;
> +
This hook is run for every variable so it's tempting to add a shortcut
here:
if (!has_states(my_id))
return;
> + name = expr_to_var(expr);
> + if (!name)
> + return;
> +
> + parent_netdev = get_parent_netdev_name(expr);
> + if (!parent_netdev)
> + return;
> +
> + state = get_state(my_id, parent_netdev, NULL);
> + if (state == &freed)
> + sm_error("Using %s after free_{netdev,candev}(%s);\n", name, parent_netdev);
> +}
> +
> +void check_uaf_netdev_priv(int id)
> +{
> + if (option_project != PROJ_KERNEL)
> + return;
> +
> + my_id = id;
> +
> + add_function_hook("free_netdev", &match_free_netdev, NULL);
NULL works but INT_PTR(0) is nicer. ;)
> + add_function_hook("free_candev", &match_free_netdev, NULL);
> + add_modification_hook(my_id, &ok_to_use);
> + add_hook(&match_symbol, SYM_HOOK);
> +}
Anyway, I think I will probably add the has_states() check but the
rest isn't important.
regards,
dan carpenter
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-03 15:08 ` Dan Carpenter
@ 2021-08-03 16:03 ` Pavel Skripkin
2021-08-04 7:05 ` Dan Carpenter
0 siblings, 1 reply; 8+ messages in thread
From: Pavel Skripkin @ 2021-08-03 16:03 UTC (permalink / raw)
To: Dan Carpenter; +Cc: smatch
Hi, Dan!
On 8/3/21 6:08 PM, Dan Carpenter wrote:
> Thanks Pavel!
>
> It looks really nice. I've applied it. I'll test it tonight and push
> tomorrow.
>
> I don't see any major issues with the check at all, but I have a few
> comments below.
>
> On Tue, Aug 03, 2021 at 12:00:22AM +0300, Pavel Skripkin wrote:
>> +static void match_free_netdev(const char *fn, struct expression *expr, void *_arg_no)
>> +{
>> + struct expression *arg;
>> + const char *name;
>> +
>> + arg = get_argument_from_call_expr(expr->args, PTR_INT(_arg_no));
>> + if (!arg)
>> + return;
>> +
>> + name = expr_to_var(arg);
>> + if (!name)
>> + return;
>> +
>> + set_state(my_id, name, NULL, &freed);
>> +}
>
> There is a new param_key API which would make this function shorter.
>
> static void free_netdev(struct expression *expr, const char *name, struct symbol *sym, void *data)
> {
> set_state(my_id, name, NULL, &freed);
> }
>
> Then in the register function you'd add a hooks like this:
>
> add_function_param_key_hook("free_netdev", &free_netdev, 0, "$", NULL);
> add_function_param_key_hook("free_candev", &free_netdev, 0, "$", NULL);
>
I guess, I missed that API, sorry :( Next time I will use it instead.
> Of course, you've already written your own code which works so it's
> fine. But that param_key API is really the most awesome thing.
>
>> +
>> +static void match_symbol(struct expression *expr)
>> +{
>> + const char *parent_netdev, *name;
>> + struct smatch_state *state;
>> +
>
> This hook is run for every variable so it's tempting to add a shortcut
> here:
>
> if (!has_states(my_id))
> return;
>
>> + name = expr_to_var(expr);
>> + if (!name)
>> + return;
>> +
>> + parent_netdev = get_parent_netdev_name(expr);
>> + if (!parent_netdev)
>> + return;
>> +
>> + state = get_state(my_id, parent_netdev, NULL);
>> + if (state == &freed)
>> + sm_error("Using %s after free_{netdev,candev}(%s);\n", name, parent_netdev);
>> +}
>> +
>> +void check_uaf_netdev_priv(int id)
>> +{
>> + if (option_project != PROJ_KERNEL)
>> + return;
>> +
>> + my_id = id;
>> +
>> + add_function_hook("free_netdev", &match_free_netdev, NULL);
>
> NULL works but INT_PTR(0) is nicer. ;)
>
>> + add_function_hook("free_candev", &match_free_netdev, NULL);
>> + add_modification_hook(my_id, &ok_to_use);
>> + add_hook(&match_symbol, SYM_HOOK);
>> +}
>
> Anyway, I think I will probably add the has_states() check but the
> rest isn't important.
Thank you for applying and your guidelines, I appreciate it :)
With regards,
Pavel Skripkin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-03 16:03 ` Pavel Skripkin
@ 2021-08-04 7:05 ` Dan Carpenter
0 siblings, 0 replies; 8+ messages in thread
From: Dan Carpenter @ 2021-08-04 7:05 UTC (permalink / raw)
To: Pavel Skripkin; +Cc: smatch
On Tue, Aug 03, 2021 at 07:03:59PM +0300, Pavel Skripkin wrote:
> Hi, Dan!
>
> On 8/3/21 6:08 PM, Dan Carpenter wrote:
> > Thanks Pavel!
> >
> > It looks really nice. I've applied it. I'll test it tonight and push
> > tomorrow.
> >
> > I don't see any major issues with the check at all, but I have a few
> > comments below.
> >
> > On Tue, Aug 03, 2021 at 12:00:22AM +0300, Pavel Skripkin wrote:
> > > +static void match_free_netdev(const char *fn, struct expression *expr, void *_arg_no)
> > > +{
> > > + struct expression *arg;
> > > + const char *name;
> > > +
> > > + arg = get_argument_from_call_expr(expr->args, PTR_INT(_arg_no));
> > > + if (!arg)
> > > + return;
> > > +
> > > + name = expr_to_var(arg);
> > > + if (!name)
> > > + return;
> > > +
> > > + set_state(my_id, name, NULL, &freed);
> > > +}
> >
> > There is a new param_key API which would make this function shorter.
> >
> > static void free_netdev(struct expression *expr, const char *name, struct symbol *sym, void *data)
> > {
> > set_state(my_id, name, NULL, &freed);
> > }
> >
> > Then in the register function you'd add a hooks like this:
> >
> > add_function_param_key_hook("free_netdev", &free_netdev, 0, "$", NULL);
> > add_function_param_key_hook("free_candev", &free_netdev, 0, "$", NULL);
> >
>
> I guess, I missed that API, sorry :( Next time I will use it instead.
It's new, I wouldn't have expected anyone to be aware of it yet. But
it's really nice.
regards,
dan carpenter
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-02 21:00 [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev Pavel Skripkin
2021-08-03 15:08 ` Dan Carpenter
@ 2021-08-04 14:35 ` Dan Carpenter
2021-08-04 14:40 ` Pavel Skripkin
2021-08-04 14:44 ` Pavel Skripkin
1 sibling, 2 replies; 8+ messages in thread
From: Dan Carpenter @ 2021-08-04 14:35 UTC (permalink / raw)
To: Pavel Skripkin; +Cc: smatch
Pushed!
This finds two bugs in my allmodconfig. They're both real bugs.
drivers/net/ethernet/freescale/fec_main.c:3994 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
drivers/net/ethernet/freescale/fec_main.c:3995 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
Presumably you already sent fixes or reported these?
regards,
dan carpenter
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-04 14:35 ` Dan Carpenter
@ 2021-08-04 14:40 ` Pavel Skripkin
2021-08-04 14:44 ` Pavel Skripkin
1 sibling, 0 replies; 8+ messages in thread
From: Pavel Skripkin @ 2021-08-04 14:40 UTC (permalink / raw)
To: Dan Carpenter; +Cc: smatch
On 8/4/21 5:35 PM, Dan Carpenter wrote:
> Pushed!
>
> This finds two bugs in my allmodconfig. They're both real bugs.
>
> drivers/net/ethernet/freescale/fec_main.c:3994 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> drivers/net/ethernet/freescale/fec_main.c:3995 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
>
Wow!
I did't test it with allmodconfig, but I've tested it with my config for
reproducing syzkaller bugs.
I've fixed few bugs while writing this checker and fixes are already
upstreamed.
> Presumably you already sent fixes or reported these?
>
> regards,
> dan carpenter
>
With regards,
Pavel Skripkin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-04 14:35 ` Dan Carpenter
2021-08-04 14:40 ` Pavel Skripkin
@ 2021-08-04 14:44 ` Pavel Skripkin
2021-08-04 14:55 ` Dan Carpenter
1 sibling, 1 reply; 8+ messages in thread
From: Pavel Skripkin @ 2021-08-04 14:44 UTC (permalink / raw)
To: Dan Carpenter; +Cc: smatch
On 8/4/21 5:35 PM, Dan Carpenter wrote:
> Pushed!
>
> This finds two bugs in my allmodconfig. They're both real bugs.
>
> drivers/net/ethernet/freescale/fec_main.c:3994 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> drivers/net/ethernet/freescale/fec_main.c:3995 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
>
I can send patches to fix these errors with Reported-by tag, or You will
take care of it?
With regards,
Pavel Skripkin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev
2021-08-04 14:44 ` Pavel Skripkin
@ 2021-08-04 14:55 ` Dan Carpenter
0 siblings, 0 replies; 8+ messages in thread
From: Dan Carpenter @ 2021-08-04 14:55 UTC (permalink / raw)
To: Pavel Skripkin; +Cc: smatch
On Wed, Aug 04, 2021 at 05:44:09PM +0300, Pavel Skripkin wrote:
> On 8/4/21 5:35 PM, Dan Carpenter wrote:
> > Pushed!
> >
> > This finds two bugs in my allmodconfig. They're both real bugs.
> >
> > drivers/net/ethernet/freescale/fec_main.c:3994 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> > drivers/net/ethernet/freescale/fec_main.c:3995 fec_drv_remove() error: Using fep after free_{netdev,candev}(ndev);
> > drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> > drivers/net/ethernet/neterion/vxge/vxge-main.c:3518 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> > drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> > drivers/net/ethernet/neterion/vxge/vxge-main.c:3520 vxge_device_unregister() error: Using vdev after free_{netdev,candev}(dev);
> >
>
> I can send patches to fix these errors with Reported-by tag, or You will
> take care of it?
Yes, please send the fixes. These are your discovery. You get first
dibs. ;)
regards,
dan carpenter
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-08-04 14:56 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-02 21:00 [PATCH] check_netdev_priv: warn about using netdev priv data after free_netdev Pavel Skripkin
2021-08-03 15:08 ` Dan Carpenter
2021-08-03 16:03 ` Pavel Skripkin
2021-08-04 7:05 ` Dan Carpenter
2021-08-04 14:35 ` Dan Carpenter
2021-08-04 14:40 ` Pavel Skripkin
2021-08-04 14:44 ` Pavel Skripkin
2021-08-04 14:55 ` Dan Carpenter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.