diff mbox series

[v2] net: nfc: Fix use-after-free caused by nfc_llcp_find_local

Message ID 20230622150331.1242706-1-linma@zju.edu.cn (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [v2] net: nfc: Fix use-after-free caused by nfc_llcp_find_local | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 9 this patch: 13
netdev/cc_maintainers fail 2 blamed authors not CCed: sameo@linux.intel.com thierry.escande@linux.intel.com; 3 maintainers not CCed: sameo@linux.intel.com davem@davemloft.net thierry.escande@linux.intel.com
netdev/build_clang fail Errors and warnings before: 8 this patch: 11
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes fail Problems with Fixes tag: 2
netdev/build_allmodconfig_warn fail Errors and warnings before: 9 this patch: 13
netdev/checkpatch warning CHECK: Alignment should match open parenthesis CHECK: Comparison to NULL could be written "!skb" WARNING: Please use correct Fixes: style 'Fixes: <12 chars of sha1> ("<title line>")' - ie: 'Fixes: ed9a49854a36 ("net: nfc: Fix use-after-free caused by nfc_llcp_find_local")'
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Lin Ma June 22, 2023, 3:03 p.m. UTC
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:
page:ffffea000416c200 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x105b08
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

It seems that the root cause of such use-after-free is the current
implementation of nfc_llcp_find_local() suffers from the race condition.
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 a apparent race window that one can possibly drop the reference
and free the local object fetched in (A) before (B) gets the reference.

To avoid such cases, this patch re-implements the nfc_llcp_find_local()
to make sure it grabs the reference under the lock protection. We also
add other reference cleanup code for error handling. Hence, the
reference promises that even when the nfc_llcp_unregister_device() is
called, no caller of nfc_llcp_find_local() will get alike UAF.

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@zju.edu.cn>
---
V1 -> V2: not just fix nfc_genl_llc_{{get/set}_params/sdreq}
          but concern on all callers of nfc_llcp_find_local()

 net/nfc/llcp.h          |  1 -
 net/nfc/llcp_commands.c | 12 ++++++++---
 net/nfc/llcp_core.c     | 47 +++++++++++++++++++++++++++++++++++------
 net/nfc/llcp_sock.c     | 16 +++++++-------
 net/nfc/netlink.c       | 20 +++++++++++++-----
 net/nfc/nfc.h           |  1 +
 6 files changed, 74 insertions(+), 23 deletions(-)

Comments

kernel test robot June 22, 2023, 6:25 p.m. UTC | #1
Hi Lin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net/main]
[also build test WARNING on net-next/main linus/master horms-ipvs/master v6.4-rc7 next-20230622]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lin-Ma/net-nfc-Fix-use-after-free-caused-by-nfc_llcp_find_local/20230622-230631
base:   net/main
patch link:    https://lore.kernel.org/r/20230622150331.1242706-1-linma%40zju.edu.cn
patch subject: [PATCH v2] net: nfc: Fix use-after-free caused by nfc_llcp_find_local
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20230623/202306230247.UPcyNhPl-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230623/202306230247.UPcyNhPl-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306230247.UPcyNhPl-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> net/nfc/llcp_core.c:146:24: warning: no previous prototype for 'nfc_llcp_local_get' [-Wmissing-prototypes]
     146 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
         |                        ^~~~~~~~~~~~~~~~~~
>> net/nfc/llcp_core.c:299:24: warning: no previous prototype for 'nfc_llcp_remove_local' [-Wmissing-prototypes]
     299 | struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
         |                        ^~~~~~~~~~~~~~~~~~~~~


vim +/nfc_llcp_local_get +146 net/nfc/llcp_core.c

d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  145  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04 @146  struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  147  {
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  148  	kref_get(&local->ref);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  149  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  150  	return local;
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  151  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  152  
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  153  static void local_cleanup(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  154  {
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  155  	nfc_llcp_socket_release(local, false, ENXIO);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  156  	del_timer_sync(&local->link_timer);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  157  	skb_queue_purge(&local->tx_queue);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  158  	cancel_work_sync(&local->tx_work);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  159  	cancel_work_sync(&local->rx_work);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  160  	cancel_work_sync(&local->timeout_work);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  161  	kfree_skb(local->rx_pending);
4bb4db7f3187c6 net/nfc/llcp_core.c Jisoo Jang      2023-01-11  162  	local->rx_pending = NULL;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  163  	del_timer_sync(&local->sdreq_timer);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  164  	cancel_work_sync(&local->sdreq_timeout_work);
d9b8d8e19b0730 net/nfc/llcp/llcp.c Thierry Escande 2013-02-15  165  	nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  166  }
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  167  
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  168  static void local_release(struct kref *ref)
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  169  {
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  170  	struct nfc_llcp_local *local;
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  171  
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  172  	local = container_of(ref, struct nfc_llcp_local, ref);
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  173  
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  174  	local_cleanup(local);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  175  	kfree(local);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  176  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  177  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  178  int nfc_llcp_local_put(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  179  {
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  180  	if (local == NULL)
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  181  		return 0;
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  182  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  183  	return kref_put(&local->ref, local_release);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  184  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  185  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  186  static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  187  					       u8 ssap, u8 dsap)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  188  {
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  189  	struct sock *sk;
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  190  	struct nfc_llcp_sock *llcp_sock, *tmp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  191  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  192  	pr_debug("ssap dsap %d %d\n", ssap, dsap);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  193  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  194  	if (ssap == 0 && dsap == 0)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  195  		return NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  196  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  197  	read_lock(&local->sockets.lock);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  198  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  199  	llcp_sock = NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  200  
b67bfe0d42cac5 net/nfc/llcp/llcp.c Sasha Levin     2013-02-27  201  	sk_for_each(sk, &local->sockets.head) {
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  202  		tmp_sock = nfc_llcp_sock(sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  203  
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  204  		if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) {
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  205  			llcp_sock = tmp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  206  			break;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  207  		}
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  208  	}
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  209  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  210  	read_unlock(&local->sockets.lock);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  211  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  212  	if (llcp_sock == NULL)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  213  		return NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  214  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  215  	sock_hold(&llcp_sock->sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  216  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  217  	return llcp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  218  }
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  219  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  220  static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  221  {
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  222  	sock_put(&sock->sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  223  }
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  224  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  225  static void nfc_llcp_timeout_work(struct work_struct *work)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  226  {
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  227  	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  228  						    timeout_work);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  229  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  230  	nfc_dep_link_down(local->dev);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  231  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  232  
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  233  static void nfc_llcp_symm_timer(struct timer_list *t)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  234  {
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  235  	struct nfc_llcp_local *local = from_timer(local, t, link_timer);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  236  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  237  	pr_err("SYMM timeout\n");
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  238  
916082b073ebb7 net/nfc/llcp/llcp.c Linus Torvalds  2012-10-02  239  	schedule_work(&local->timeout_work);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  240  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  241  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  242  static void nfc_llcp_sdreq_timeout_work(struct work_struct *work)
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  243  {
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  244  	unsigned long time;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  245  	HLIST_HEAD(nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  246  	struct hlist_node *n;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  247  	struct nfc_llcp_sdp_tlv *sdp;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  248  	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  249  						    sdreq_timeout_work);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  250  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  251  	mutex_lock(&local->sdreq_lock);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  252  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  253  	time = jiffies - msecs_to_jiffies(3 * local->remote_lto);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  254  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  255  	hlist_for_each_entry_safe(sdp, n, &local->pending_sdreqs, node) {
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  256  		if (time_after(sdp->time, time))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  257  			continue;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  258  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  259  		sdp->sap = LLCP_SDP_UNBOUND;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  260  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  261  		hlist_del(&sdp->node);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  262  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  263  		hlist_add_head(&sdp->node, &nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  264  	}
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  265  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  266  	if (!hlist_empty(&local->pending_sdreqs))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  267  		mod_timer(&local->sdreq_timer,
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  268  			  jiffies + msecs_to_jiffies(3 * local->remote_lto));
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  269  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  270  	mutex_unlock(&local->sdreq_lock);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  271  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  272  	if (!hlist_empty(&nl_sdres_list))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  273  		nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  274  }
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  275  
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  276  static void nfc_llcp_sdreq_timer(struct timer_list *t)
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  277  {
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  278  	struct nfc_llcp_local *local = from_timer(local, t, sdreq_timer);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  279  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  280  	schedule_work(&local->sdreq_timeout_work);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  281  }
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  282  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  283  struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  284  {
29e27dd86b5c4f net/nfc/llcp_core.c Axel Lin        2014-02-26  285  	struct nfc_llcp_local *local;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  286  	struct nfc_llcp_local *res = NULL;
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  287  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  288  	spin_lock(&llcp_devices_lock);
29e27dd86b5c4f net/nfc/llcp_core.c Axel Lin        2014-02-26  289  	list_for_each_entry(local, &llcp_devices, list)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  290  		if (local->dev == dev) {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  291  			res = nfc_llcp_local_get(local);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  292  			break;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  293  		}
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  294  	spin_unlock(&llcp_devices_lock);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  295  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  296  	return res;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  297  }
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  298  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22 @299  struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  300  {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  301  	struct nfc_llcp_local *local, *tmp;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  302  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  303  	spin_lock(&llcp_devices_lock);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  304  	list_for_each_entry_safe(local, tmp, &llcp_devices, list)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  305  		if (local->dev == dev) {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  306  			list_del(&local->list);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  307  			spin_unlock(&llcp_devices_lock);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  308  			return local;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  309  		}
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  310  	spin_unlock(&llcp_devices_lock);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  311  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  312  	pr_warn("Shutting down device not found\n");
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  313  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  314  	return NULL;
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  315  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  316
kernel test robot June 22, 2023, 10:41 p.m. UTC | #2
Hi Lin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net/main]
[also build test WARNING on net-next/main linus/master horms-ipvs/master v6.4-rc7 next-20230622]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lin-Ma/net-nfc-Fix-use-after-free-caused-by-nfc_llcp_find_local/20230622-230631
base:   net/main
patch link:    https://lore.kernel.org/r/20230622150331.1242706-1-linma%40zju.edu.cn
patch subject: [PATCH v2] net: nfc: Fix use-after-free caused by nfc_llcp_find_local
config: s390-randconfig-r036-20230622 (https://download.01.org/0day-ci/archive/20230623/202306230631.Pk3BN4Kg-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230623/202306230631.Pk3BN4Kg-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306230631.Pk3BN4Kg-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from net/nfc/llcp_core.c:14:
   In file included from net/nfc/nfc.h:13:
   In file included from include/net/nfc/nfc.h:16:
   In file included from include/linux/skbuff.h:28:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/s390/include/asm/io.h:75:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
         |                                                           ^
   include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16'
     102 | #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
         |                                                      ^
   In file included from net/nfc/llcp_core.c:14:
   In file included from net/nfc/nfc.h:13:
   In file included from include/net/nfc/nfc.h:16:
   In file included from include/linux/skbuff.h:28:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/s390/include/asm/io.h:75:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
         |                                                           ^
   include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32'
     115 | #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
         |                                                      ^
   In file included from net/nfc/llcp_core.c:14:
   In file included from net/nfc/nfc.h:13:
   In file included from include/net/nfc/nfc.h:16:
   In file included from include/linux/skbuff.h:28:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/s390/include/asm/io.h:75:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     692 |         readsb(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     700 |         readsw(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     708 |         readsl(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     717 |         writesb(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     726 |         writesw(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     735 |         writesl(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
>> net/nfc/llcp_core.c:146:24: warning: no previous prototype for function 'nfc_llcp_local_get' [-Wmissing-prototypes]
     146 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
         |                        ^
   net/nfc/llcp_core.c:146:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
     146 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
         | ^
         | static 
>> net/nfc/llcp_core.c:299:24: warning: no previous prototype for function 'nfc_llcp_remove_local' [-Wmissing-prototypes]
     299 | struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
         |                        ^
   net/nfc/llcp_core.c:299:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
     299 | struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
         | ^
         | static 
   14 warnings generated.


vim +/nfc_llcp_local_get +146 net/nfc/llcp_core.c

d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  145  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04 @146  struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  147  {
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  148  	kref_get(&local->ref);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  149  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  150  	return local;
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  151  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  152  
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  153  static void local_cleanup(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  154  {
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  155  	nfc_llcp_socket_release(local, false, ENXIO);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  156  	del_timer_sync(&local->link_timer);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  157  	skb_queue_purge(&local->tx_queue);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  158  	cancel_work_sync(&local->tx_work);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  159  	cancel_work_sync(&local->rx_work);
474fee3db16c63 net/nfc/llcp/llcp.c Tejun Heo       2012-08-22  160  	cancel_work_sync(&local->timeout_work);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  161  	kfree_skb(local->rx_pending);
4bb4db7f3187c6 net/nfc/llcp_core.c Jisoo Jang      2023-01-11  162  	local->rx_pending = NULL;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  163  	del_timer_sync(&local->sdreq_timer);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  164  	cancel_work_sync(&local->sdreq_timeout_work);
d9b8d8e19b0730 net/nfc/llcp/llcp.c Thierry Escande 2013-02-15  165  	nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  166  }
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  167  
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  168  static void local_release(struct kref *ref)
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  169  {
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  170  	struct nfc_llcp_local *local;
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  171  
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  172  	local = container_of(ref, struct nfc_llcp_local, ref);
3536da06db0baa net/nfc/llcp/llcp.c Samuel Ortiz    2013-02-21  173  
c470e319b48bf1 net/nfc/llcp/llcp.c Samuel Ortiz    2013-04-03  174  	local_cleanup(local);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  175  	kfree(local);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  176  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  177  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  178  int nfc_llcp_local_put(struct nfc_llcp_local *local)
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  179  {
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  180  	if (local == NULL)
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  181  		return 0;
a69f32af86e389 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  182  
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  183  	return kref_put(&local->ref, local_release);
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  184  }
c7aa12252f5142 net/nfc/llcp/llcp.c Samuel Ortiz    2012-05-04  185  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  186  static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  187  					       u8 ssap, u8 dsap)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  188  {
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  189  	struct sock *sk;
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  190  	struct nfc_llcp_sock *llcp_sock, *tmp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  191  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  192  	pr_debug("ssap dsap %d %d\n", ssap, dsap);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  193  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  194  	if (ssap == 0 && dsap == 0)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  195  		return NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  196  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  197  	read_lock(&local->sockets.lock);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  198  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  199  	llcp_sock = NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  200  
b67bfe0d42cac5 net/nfc/llcp/llcp.c Sasha Levin     2013-02-27  201  	sk_for_each(sk, &local->sockets.head) {
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  202  		tmp_sock = nfc_llcp_sock(sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  203  
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  204  		if (tmp_sock->ssap == ssap && tmp_sock->dsap == dsap) {
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  205  			llcp_sock = tmp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  206  			break;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  207  		}
a8df0f379213f1 net/nfc/llcp/llcp.c Samuel Ortiz    2012-10-16  208  	}
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  209  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  210  	read_unlock(&local->sockets.lock);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  211  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  212  	if (llcp_sock == NULL)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  213  		return NULL;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  214  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  215  	sock_hold(&llcp_sock->sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  216  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  217  	return llcp_sock;
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  218  }
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  219  
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  220  static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  221  {
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  222  	sock_put(&sock->sk);
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  223  }
8f50020ed9b81b net/nfc/llcp/llcp.c Samuel Ortiz    2012-06-25  224  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  225  static void nfc_llcp_timeout_work(struct work_struct *work)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  226  {
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  227  	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  228  						    timeout_work);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  229  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  230  	nfc_dep_link_down(local->dev);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  231  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  232  
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  233  static void nfc_llcp_symm_timer(struct timer_list *t)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  234  {
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  235  	struct nfc_llcp_local *local = from_timer(local, t, link_timer);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  236  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  237  	pr_err("SYMM timeout\n");
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  238  
916082b073ebb7 net/nfc/llcp/llcp.c Linus Torvalds  2012-10-02  239  	schedule_work(&local->timeout_work);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  240  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  241  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  242  static void nfc_llcp_sdreq_timeout_work(struct work_struct *work)
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  243  {
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  244  	unsigned long time;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  245  	HLIST_HEAD(nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  246  	struct hlist_node *n;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  247  	struct nfc_llcp_sdp_tlv *sdp;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  248  	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  249  						    sdreq_timeout_work);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  250  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  251  	mutex_lock(&local->sdreq_lock);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  252  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  253  	time = jiffies - msecs_to_jiffies(3 * local->remote_lto);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  254  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  255  	hlist_for_each_entry_safe(sdp, n, &local->pending_sdreqs, node) {
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  256  		if (time_after(sdp->time, time))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  257  			continue;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  258  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  259  		sdp->sap = LLCP_SDP_UNBOUND;
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  260  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  261  		hlist_del(&sdp->node);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  262  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  263  		hlist_add_head(&sdp->node, &nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  264  	}
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  265  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  266  	if (!hlist_empty(&local->pending_sdreqs))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  267  		mod_timer(&local->sdreq_timer,
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  268  			  jiffies + msecs_to_jiffies(3 * local->remote_lto));
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  269  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  270  	mutex_unlock(&local->sdreq_lock);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  271  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  272  	if (!hlist_empty(&nl_sdres_list))
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  273  		nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  274  }
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  275  
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  276  static void nfc_llcp_sdreq_timer(struct timer_list *t)
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  277  {
4b519bb493e086 net/nfc/llcp_core.c Allen Pais      2017-10-11  278  	struct nfc_llcp_local *local = from_timer(local, t, sdreq_timer);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  279  
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  280  	schedule_work(&local->sdreq_timeout_work);
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  281  }
40213fa8513c2a net/nfc/llcp/llcp.c Thierry Escande 2013-03-04  282  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  283  struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  284  {
29e27dd86b5c4f net/nfc/llcp_core.c Axel Lin        2014-02-26  285  	struct nfc_llcp_local *local;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  286  	struct nfc_llcp_local *res = NULL;
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  287  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  288  	spin_lock(&llcp_devices_lock);
29e27dd86b5c4f net/nfc/llcp_core.c Axel Lin        2014-02-26  289  	list_for_each_entry(local, &llcp_devices, list)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  290  		if (local->dev == dev) {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  291  			res = nfc_llcp_local_get(local);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  292  			break;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  293  		}
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  294  	spin_unlock(&llcp_devices_lock);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  295  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  296  	return res;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  297  }
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  298  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22 @299  struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  300  {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  301  	struct nfc_llcp_local *local, *tmp;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  302  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  303  	spin_lock(&llcp_devices_lock);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  304  	list_for_each_entry_safe(local, tmp, &llcp_devices, list)
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  305  		if (local->dev == dev) {
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  306  			list_del(&local->list);
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  307  			spin_unlock(&llcp_devices_lock);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  308  			return local;
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  309  		}
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  310  	spin_unlock(&llcp_devices_lock);
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  311  
972f46a30da575 net/nfc/llcp_core.c Lin Ma          2023-06-22  312  	pr_warn("Shutting down device not found\n");
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  313  
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  314  	return NULL;
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  315  }
d646960f7986fe net/nfc/llcp/llcp.c Samuel Ortiz    2011-12-14  316
diff mbox series

Patch

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..34eea997318c 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);
 
@@ -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;
+}
+
+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..fa6a9e455b53 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,20 +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) {
+		llcp_sock->local = NULL;
+		llcp_sock->dev = NULL;
 		ret = -ENOMEM;
 		goto sock_llcp_put_local;
 	}
@@ -758,9 +760,7 @@  static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 	nfc_llcp_put_ssap(local, llcp_sock->ssap);
 
 sock_llcp_put_local:
-	nfc_llcp_local_put(llcp_sock->local);
-	llcp_sock->local = NULL;
-	llcp_sock->dev = NULL;
+	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);