lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ