Message ID | 20230620025350.4034422-1-linma@zju.edu.cn (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [v1] net: nfc: Fix use-after-free in nfc_genl_llc_{{get/set}_params/sdreq} | expand |
On Tue, 2023-06-20 at 10:53 +0800, Lin Ma wrote: > This commit fixes a use-after-free for object nfc_llcp_local, the root > cause of this bug is due to the race in nfc_llcp_unregister_device. > Just like the buggy time window below. Since the nfc_llcp_find_local will > not increase the reference counter of object nfc_llcp_local, UAF occurs. > > // nfc_genl_llc_get_params | // nfc_unregister_device > | > dev = nfc_get_device(idx); | device_lock(...) > if (!dev) | dev->shutting_down = true; > return -ENODEV; | device_unlock(...); > | > device_lock(...); | // nfc_llcp_unregister_device > | nfc_llcp_find_local() > nfc_llcp_find_local(...); | > | local_cleanup() > if (!local) { | > rc = -ENODEV; | // nfc_llcp_local_put > goto exit; | kref_put(.., local_release) > } | > | // local_release > | list_del(&local->list) > // nfc_genl_send_params | kfree() > local->dev->idx !!!UAF!!! | > | > To avoid this, we can add a check to dev->shutting_down inside the > device_lock critical section. Therefore, the nfc_genl_llc_get_params will > surely error return if it grabs the lock after the nfc_unregister_device > releases the lock. > > This patch applies such check for nfc_genl_llc_{{get/set}_params/sdreq} > as they all use nfc_llcp_find_local and suffer from the race condition. It looks like the mentioned race condition could apply to any callers of nfc_llcp_find_local(), is there any special reason to not add the new check directly inside nfc_llcp_find_local()? Thanks! Paolo
Hi Paolo, > > It looks like the mentioned race condition could apply to any callers > of nfc_llcp_find_local(), is there any special reason to not add the > new check directly inside nfc_llcp_find_local()? > Ooops, I actually haven't consider those cases. I will do a quick check for that. > Thanks! > > Paolo Regards Lin
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index b9264e730fd9..7e57846fdfe3 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1030,6 +1030,11 @@ static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) device_lock(&dev->dev); + if (dev->shutting_down) { + rc = -ENODEV; + goto exit; + } + local = nfc_llcp_find_local(dev); if (!local) { rc = -ENODEV; @@ -1096,6 +1101,11 @@ static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) device_lock(&dev->dev); + if (dev->shutting_down) { + rc = -ENODEV; + goto exit; + } + local = nfc_llcp_find_local(dev); if (!local) { rc = -ENODEV; @@ -1150,6 +1160,11 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) device_lock(&dev->dev); + if (dev->shutting_down) { + rc = -ENODEV; + goto exit; + } + if (dev->dep_link_up == false) { rc = -ENOLINK; goto exit;