[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ZJgunIR1d/T7uuu0@corigine.com>
Date: Sun, 25 Jun 2023 14:10:04 +0200
From: Simon Horman <simon.horman@...igine.com>
To: Lin Ma <linma@....edu.cn>
Cc: krzysztof.kozlowski@...aro.org, davem@...emloft.net,
edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com,
netdev@...r.kernel.org, sameo@...ux.intel.com,
thierry.escande@...ux.intel.com
Subject: Re: [PATCH v5] net: nfc: Fix use-after-free caused by
nfc_llcp_find_local
+ maintainers; corrected Davem's email address
On Sun, Jun 25, 2023 at 05:10:07PM +0800, Lin Ma wrote:
> This commit fixes several use-after-free that caused by function
> nfc_llcp_find_local(). For example, one UAF can happen when below buggy
> time window 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!!! |
> |
>
> and the crash trace for the one of the discussed UAF like:
>
> BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
> Read of size 8 at addr ffff888105b0e410 by task 20114
>
> Call Trace:
> <TASK>
> __dump_stack lib/dump_stack.c:88 [inline]
> dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106
> print_address_description mm/kasan/report.c:319 [inline]
> print_report+0xcc/0x620 mm/kasan/report.c:430
> kasan_report+0xb2/0xe0 mm/kasan/report.c:536
> nfc_genl_send_params net/nfc/netlink.c:999 [inline]
> nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045
> genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968
> genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline]
> genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065
> netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548
> genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076
> netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
> netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365
> netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913
> sock_sendmsg_nosec net/socket.c:724 [inline]
> sock_sendmsg+0x1b6/0x200 net/socket.c:747
> ____sys_sendmsg+0x6e9/0x890 net/socket.c:2501
> ___sys_sendmsg+0x110/0x1b0 net/socket.c:2555
> __sys_sendmsg+0xf7/0x1d0 net/socket.c:2584
> do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
> entry_SYSCALL_64_after_hwframe+0x72/0xdc
> RIP: 0033:0x7f34640a2389
> RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
> RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389
> RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006
> RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000
> </TASK>
>
> Allocated by task 20116:
> kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> ____kasan_kmalloc mm/kasan/common.c:374 [inline]
> __kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383
> kmalloc include/linux/slab.h:580 [inline]
> kzalloc include/linux/slab.h:720 [inline]
> nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567
> nfc_register_device+0x61/0x260 net/nfc/core.c:1124
> nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257
> virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148
> misc_open+0x379/0x4a0 drivers/char/misc.c:165
> chrdev_open+0x26c/0x780 fs/char_dev.c:414
> do_dentry_open+0x6c4/0x12a0 fs/open.c:920
> do_open fs/namei.c:3560 [inline]
> path_openat+0x24fe/0x37e0 fs/namei.c:3715
> do_filp_open+0x1ba/0x410 fs/namei.c:3742
> do_sys_openat2+0x171/0x4c0 fs/open.c:1356
> do_sys_open fs/open.c:1372 [inline]
> __do_sys_openat fs/open.c:1388 [inline]
> __se_sys_openat fs/open.c:1383 [inline]
> __x64_sys_openat+0x143/0x200 fs/open.c:1383
> do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
> entry_SYSCALL_64_after_hwframe+0x72/0xdc
>
> Freed by task 20115:
> kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free mm/kasan/common.c:200 [inline]
> __kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244
> kasan_slab_free include/linux/kasan.h:162 [inline]
> slab_free_hook mm/slub.c:1781 [inline]
> slab_free_freelist_hook mm/slub.c:1807 [inline]
> slab_free mm/slub.c:3787 [inline]
> __kmem_cache_free+0x7a/0x190 mm/slub.c:3800
> local_release net/nfc/llcp_core.c:174 [inline]
> kref_put include/linux/kref.h:65 [inline]
> nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline]
> nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline]
> nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620
> nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179
> virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163
> __fput+0x252/0xa20 fs/file_table.c:321
> task_work_run+0x174/0x270 kernel/task_work.c:179
> resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
> exit_to_user_mode_loop kernel/entry/common.c:171 [inline]
> exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204
> __syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline]
> syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297
> do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x72/0xdc
>
> Last potentially related work creation:
> kasan_save_stack+0x22/0x50 mm/kasan/common.c:45
> __kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491
> kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328
> drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735
> unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773
> unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753
> neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895
> addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684
> notifier_call_chain+0xbe/0x210 kernel/notifier.c:87
> call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937
> call_netdevice_notifiers_extack net/core/dev.c:1975 [inline]
> call_netdevice_notifiers net/core/dev.c:1989 [inline]
> dev_change_name+0x3c3/0x870 net/core/dev.c:1211
> dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376
> dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542
> sock_do_ioctl+0x160/0x260 net/socket.c:1213
> sock_ioctl+0x3f9/0x670 net/socket.c:1316
> vfs_ioctl fs/ioctl.c:51 [inline]
> __do_sys_ioctl fs/ioctl.c:870 [inline]
> __se_sys_ioctl fs/ioctl.c:856 [inline]
> __x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856
> do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80
> entry_SYSCALL_64_after_hwframe+0x72/0xdc
>
> The buggy address belongs to the object at ffff888105b0e400
> which belongs to the cache kmalloc-1k of size 1024
> The buggy address is located 16 bytes inside of
> freed 1024-byte region [ffff888105b0e400, ffff888105b0e800)
>
> The buggy address belongs to the physical page:
> head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0
> flags: 0x200000000010200(slab|head|node=0|zone=2)
> raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10
> raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> >ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>
> In summary, this patch solves those use-after-free by
>
> 1. Re-implement the nfc_llcp_find_local(). The current version does not
> grab the reference when getting the local from the linked list. For
> example, the llcp_sock_bind() gets the reference like below:
>
> // llcp_sock_bind()
>
> local = nfc_llcp_find_local(dev); // A
> ..... \
> | raceable
> ..... /
> llcp_sock->local = nfc_llcp_local_get(local); // B
>
> There is an apparent race window that one can drop the reference
> and free the local object fetched in (A) before (B) gets the reference.
>
> 2. Some callers of the nfc_llcp_find_local() do not grab the reference
> at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions.
> We add the nfc_llcp_local_put() for them. Moreover, we add the necessary
> error handling function to put the reference.
>
> 3. Add the nfc_llcp_remove_local() helper. The local object is removed
> from the linked list in local_release() when all reference is gone. This
> patch removes it when nfc_llcp_unregister_device() is called.
>
> Therefore, every caller of nfc_llcp_find_local() will get a reference
> even when the nfc_llcp_unregister_device() is called. This promises no
> use-after-free for the local object is ever possible.
>
> Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support")
> Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket")
> Signed-off-by: Lin Ma <linma@....edu.cn>
> ---
> V1 -> V2: not just fix nfc_genl_llc_{{get/set}_params/sdreq}
> but concern on all callers of nfc_llcp_find_local()
> V2 -> V3: make nfc_llcp_local_get() static to ease the prototype
> warning, and make the commit message more clear
> V3 -> V4: make nfc_llcp_remove_local() also static
> V4 -> V5: fix the buggy error handling in llcp_sock_connect(), make
> sure llcp_sock->local/dev reset to NULL
Thanks. My only issue with v4 has been resolved by v5.
Reviewed-by: Simon Horman <simon.horman@...igine.com>
[ full patch left in place below for the benefit of newly CCed people ]
> net/nfc/llcp.h | 1 -
> net/nfc/llcp_commands.c | 12 +++++++---
> net/nfc/llcp_core.c | 49 +++++++++++++++++++++++++++++++++++------
> net/nfc/llcp_sock.c | 18 ++++++++-------
> net/nfc/netlink.c | 20 ++++++++++++-----
> net/nfc/nfc.h | 1 +
> 6 files changed, 77 insertions(+), 24 deletions(-)
>
> diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h
> index c1d9be636933..d8345ed57c95 100644
> --- a/net/nfc/llcp.h
> +++ b/net/nfc/llcp.h
> @@ -201,7 +201,6 @@ void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
> void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
> void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
> struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
> -struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
> int nfc_llcp_local_put(struct nfc_llcp_local *local);
> u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
> struct nfc_llcp_sock *sock);
> diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c
> index 41e3a20c8935..5d2d4bc26ef9 100644
> --- a/net/nfc/llcp_commands.c
> +++ b/net/nfc/llcp_commands.c
> @@ -359,6 +359,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
> struct sk_buff *skb;
> struct nfc_llcp_local *local;
> u16 size = 0;
> + int err;
>
> local = nfc_llcp_find_local(dev);
> if (local == NULL)
> @@ -368,8 +369,10 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
> size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
>
> skb = alloc_skb(size, GFP_KERNEL);
> - if (skb == NULL)
> - return -ENOMEM;
> + if (skb == NULL) {
> + err = -ENOMEM;
> + goto out;
> + }
>
> skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
>
> @@ -379,8 +382,11 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
>
> nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_TX);
>
> - return nfc_data_exchange(dev, local->target_idx, skb,
> + err = nfc_data_exchange(dev, local->target_idx, skb,
> nfc_llcp_recv, local);
> +out:
> + nfc_llcp_local_put(local);
> + return err;
> }
>
> int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
> diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c
> index a27e1842b2a0..f60e424e0607 100644
> --- a/net/nfc/llcp_core.c
> +++ b/net/nfc/llcp_core.c
> @@ -17,6 +17,8 @@
> static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
>
> static LIST_HEAD(llcp_devices);
> +/* Protects llcp_devices list */
> +static DEFINE_SPINLOCK(llcp_devices_lock);
>
> static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
>
> @@ -141,7 +143,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
> write_unlock(&local->raw_sockets.lock);
> }
>
> -struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
> +static struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
> {
> kref_get(&local->ref);
>
> @@ -169,7 +171,6 @@ static void local_release(struct kref *ref)
>
> local = container_of(ref, struct nfc_llcp_local, ref);
>
> - list_del(&local->list);
> local_cleanup(local);
> kfree(local);
> }
> @@ -282,12 +283,33 @@ static void nfc_llcp_sdreq_timer(struct timer_list *t)
> struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
> {
> struct nfc_llcp_local *local;
> + struct nfc_llcp_local *res = NULL;
>
> + spin_lock(&llcp_devices_lock);
> list_for_each_entry(local, &llcp_devices, list)
> - if (local->dev == dev)
> + if (local->dev == dev) {
> + res = nfc_llcp_local_get(local);
> + break;
> + }
> + spin_unlock(&llcp_devices_lock);
> +
> + return res;
> +}
> +
> +static struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
> +{
> + struct nfc_llcp_local *local, *tmp;
> +
> + spin_lock(&llcp_devices_lock);
> + list_for_each_entry_safe(local, tmp, &llcp_devices, list)
> + if (local->dev == dev) {
> + list_del(&local->list);
> + spin_unlock(&llcp_devices_lock);
> return local;
> + }
> + spin_unlock(&llcp_devices_lock);
>
> - pr_debug("No device found\n");
> + pr_warn("Shutting down device not found\n");
>
> return NULL;
> }
> @@ -608,12 +630,15 @@ u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len)
>
> *general_bytes_len = local->gb_len;
>
> + nfc_llcp_local_put(local);
> +
> return local->gb;
> }
>
> int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len)
> {
> struct nfc_llcp_local *local;
> + int err;
>
> if (gb_len < 3 || gb_len > NFC_MAX_GT_LEN)
> return -EINVAL;
> @@ -630,12 +655,16 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len)
>
> if (memcmp(local->remote_gb, llcp_magic, 3)) {
> pr_err("MAC does not support LLCP\n");
> - return -EINVAL;
> + err = -EINVAL;
> + goto out;
> }
>
> - return nfc_llcp_parse_gb_tlv(local,
> + err = nfc_llcp_parse_gb_tlv(local,
> &local->remote_gb[3],
> local->remote_gb_len - 3);
> +out:
> + nfc_llcp_local_put(local);
> + return err;
> }
>
> static u8 nfc_llcp_dsap(const struct sk_buff *pdu)
> @@ -1517,6 +1546,8 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
>
> __nfc_llcp_recv(local, skb);
>
> + nfc_llcp_local_put(local);
> +
> return 0;
> }
>
> @@ -1533,6 +1564,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
>
> /* Close and purge all existing sockets */
> nfc_llcp_socket_release(local, true, 0);
> +
> + nfc_llcp_local_put(local);
> }
>
> void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
> @@ -1558,6 +1591,8 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
> mod_timer(&local->link_timer,
> jiffies + msecs_to_jiffies(local->remote_lto));
> }
> +
> + nfc_llcp_local_put(local);
> }
>
> int nfc_llcp_register_device(struct nfc_dev *ndev)
> @@ -1608,7 +1643,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
>
> void nfc_llcp_unregister_device(struct nfc_dev *dev)
> {
> - struct nfc_llcp_local *local = nfc_llcp_find_local(dev);
> + struct nfc_llcp_local *local = nfc_llcp_remove_local(dev);
>
> if (local == NULL) {
> pr_debug("No such device\n");
> diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
> index 77642d18a3b4..645677f84dba 100644
> --- a/net/nfc/llcp_sock.c
> +++ b/net/nfc/llcp_sock.c
> @@ -99,7 +99,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
> }
>
> llcp_sock->dev = dev;
> - llcp_sock->local = nfc_llcp_local_get(local);
> + llcp_sock->local = local;
> llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
> llcp_sock->service_name_len = min_t(unsigned int,
> llcp_addr.service_name_len,
> @@ -186,7 +186,7 @@ static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr,
> }
>
> llcp_sock->dev = dev;
> - llcp_sock->local = nfc_llcp_local_get(local);
> + llcp_sock->local = local;
> llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
>
> nfc_llcp_sock_link(&local->raw_sockets, sk);
> @@ -696,22 +696,22 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
> if (dev->dep_link_up == false) {
> ret = -ENOLINK;
> device_unlock(&dev->dev);
> - goto put_dev;
> + goto sock_llcp_put_local;
> }
> device_unlock(&dev->dev);
>
> if (local->rf_mode == NFC_RF_INITIATOR &&
> addr->target_idx != local->target_idx) {
> ret = -ENOLINK;
> - goto put_dev;
> + goto sock_llcp_put_local;
> }
>
> llcp_sock->dev = dev;
> - llcp_sock->local = nfc_llcp_local_get(local);
> + llcp_sock->local = local;
> llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
> if (llcp_sock->ssap == LLCP_SAP_MAX) {
> ret = -ENOMEM;
> - goto sock_llcp_put_local;
> + goto sock_llcp_nullify;
> }
>
> llcp_sock->reserved_ssap = llcp_sock->ssap;
> @@ -757,11 +757,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
> sock_llcp_release:
> nfc_llcp_put_ssap(local, llcp_sock->ssap);
>
> -sock_llcp_put_local:
> - nfc_llcp_local_put(llcp_sock->local);
> +sock_llcp_nullify:
> llcp_sock->local = NULL;
> llcp_sock->dev = NULL;
>
> +sock_llcp_put_local:
> + nfc_llcp_local_put(local);
> +
> put_dev:
> nfc_put_device(dev);
>
> diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
> index b9264e730fd9..e9ac6a6f934e 100644
> --- a/net/nfc/netlink.c
> +++ b/net/nfc/netlink.c
> @@ -1039,11 +1039,14 @@ static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info)
> msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> if (!msg) {
> rc = -ENOMEM;
> - goto exit;
> + goto put_local;
> }
>
> rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq);
>
> +put_local:
> + nfc_llcp_local_put(local);
> +
> exit:
> device_unlock(&dev->dev);
>
> @@ -1105,7 +1108,7 @@ static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
> if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) {
> if (dev->dep_link_up) {
> rc = -EINPROGRESS;
> - goto exit;
> + goto put_local;
> }
>
> local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]);
> @@ -1117,6 +1120,9 @@ static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info)
> if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX])
> local->miux = cpu_to_be16(miux);
>
> +put_local:
> + nfc_llcp_local_put(local);
> +
> exit:
> device_unlock(&dev->dev);
>
> @@ -1172,7 +1178,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
>
> if (rc != 0) {
> rc = -EINVAL;
> - goto exit;
> + goto put_local;
> }
>
> if (!sdp_attrs[NFC_SDP_ATTR_URI])
> @@ -1191,7 +1197,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
> sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
> if (sdreq == NULL) {
> rc = -ENOMEM;
> - goto exit;
> + goto put_local;
> }
>
> tlvs_len += sdreq->tlv_len;
> @@ -1201,10 +1207,14 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
>
> if (hlist_empty(&sdreq_list)) {
> rc = -EINVAL;
> - goto exit;
> + goto put_local;
> }
>
> rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
> +
> +put_local:
> + nfc_llcp_local_put(local);
> +
> exit:
> device_unlock(&dev->dev);
>
> diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
> index de2ec66d7e83..0b1e6466f4fb 100644
> --- a/net/nfc/nfc.h
> +++ b/net/nfc/nfc.h
> @@ -52,6 +52,7 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len);
> u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
> int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
> struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
> +int nfc_llcp_local_put(struct nfc_llcp_local *local);
> int __init nfc_llcp_init(void);
> void nfc_llcp_exit(void);
> void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
> --
> 2.17.1
>
>
Powered by blists - more mailing lists