summaryrefslogtreecommitdiff
path: root/net/mctp/route.c
diff options
context:
space:
mode:
authorJeremy Kerr <jk@codeconstruct.com.au>2022-10-12 05:08:51 +0300
committerDavid S. Miller <davem@davemloft.net>2022-10-12 15:30:50 +0300
commit3a732b46736cd8a29092e4b0b1a9ba83e672bf89 (patch)
treef65f1c8b1b23ce517fb173eb336fd3e3da6537d3 /net/mctp/route.c
parented5d1f61b4069c8b91a00ac29cfe1cef324e8bc2 (diff)
downloadlinux-3a732b46736cd8a29092e4b0b1a9ba83e672bf89.tar.xz
mctp: prevent double key removal and unref
Currently, we have a bug where a simultaneous DROPTAG ioctl and socket close may race, as we attempt to remove a key from lists twice, and perform an unref for each removal operation. This may result in a uaf when we attempt the second unref. This change fixes the race by making __mctp_key_remove tolerant to being called on a key that has already been removed from the socket/net lists, and only performs the unref when we do the actual remove. We also need to hold the list lock on the ioctl cleanup path. This fix is based on a bug report and comprehensive analysis from butt3rflyh4ck <butterflyhuangxx@gmail.com>, found via syzkaller. Cc: stable@vger.kernel.org Fixes: 63ed1aab3d40 ("mctp: Add SIOCMCTP{ALLOC,DROP}TAG ioctls for tag control") Reported-by: butt3rflyh4ck <butterflyhuangxx@gmail.com> Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mctp/route.c')
-rw-r--r--net/mctp/route.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 3b24b8d18b5b..2155f15a074c 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -228,12 +228,12 @@ __releases(&key->lock)
if (!key->manual_alloc) {
spin_lock_irqsave(&net->mctp.keys_lock, flags);
- hlist_del(&key->hlist);
- hlist_del(&key->sklist);
+ if (!hlist_unhashed(&key->hlist)) {
+ hlist_del_init(&key->hlist);
+ hlist_del_init(&key->sklist);
+ mctp_key_unref(key);
+ }
spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
-
- /* unref for the lists */
- mctp_key_unref(key);
}
/* and one for the local reference */