2019-05-19 21:51:43 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2011-12-14 23:43:12 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 Intel Corporation. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) "llcp: %s: " fmt, __func__
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/nfc.h>
|
2017-02-03 02:15:33 +08:00
|
|
|
#include <linux/sched/signal.h>
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2013-04-26 17:49:40 +08:00
|
|
|
#include "nfc.h"
|
2011-12-14 23:43:12 +08:00
|
|
|
#include "llcp.h"
|
|
|
|
|
2012-05-07 18:31:19 +08:00
|
|
|
static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
|
|
|
|
{
|
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
pr_debug("sk %p", sk);
|
|
|
|
|
|
|
|
add_wait_queue(sk_sleep(sk), &wait);
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
|
|
|
|
while (sk->sk_state != state) {
|
|
|
|
if (!timeo) {
|
|
|
|
err = -EINPROGRESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (signal_pending(current)) {
|
|
|
|
err = sock_intr_errno(timeo);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
timeo = schedule_timeout(timeo);
|
|
|
|
lock_sock(sk);
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
|
|
|
|
err = sock_error(sk);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
|
|
remove_wait_queue(sk_sleep(sk), &wait);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
static struct proto llcp_sock_proto = {
|
|
|
|
.name = "NFC_LLCP",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.obj_size = sizeof(struct nfc_llcp_sock),
|
|
|
|
};
|
|
|
|
|
|
|
|
static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct sockaddr_nfc_llcp llcp_addr;
|
|
|
|
int len, ret = 0;
|
|
|
|
|
2017-06-14 00:44:28 +08:00
|
|
|
if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
|
|
|
|
addr->sa_family != AF_NFC)
|
2011-12-14 23:43:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2012-06-29 18:03:55 +08:00
|
|
|
pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
memset(&llcp_addr, 0, sizeof(llcp_addr));
|
|
|
|
len = min_t(unsigned int, sizeof(llcp_addr), alen);
|
|
|
|
memcpy(&llcp_addr, addr, len);
|
|
|
|
|
|
|
|
/* This is going to be a listening socket, dsap must be 0 */
|
|
|
|
if (llcp_addr.dsap != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state != LLCP_CLOSED) {
|
|
|
|
ret = -EBADFD;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = nfc_get_device(llcp_addr.dev_idx);
|
|
|
|
if (dev == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (local == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
llcp_sock->dev = dev;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
llcp_sock->local = local;
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
|
|
|
|
llcp_sock->service_name_len = min_t(unsigned int,
|
2012-03-05 08:03:52 +08:00
|
|
|
llcp_addr.service_name_len,
|
|
|
|
NFC_LLCP_MAX_SERVICE_NAME);
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->service_name = kmemdup(llcp_addr.service_name,
|
2012-03-05 08:03:52 +08:00
|
|
|
llcp_sock->service_name_len,
|
|
|
|
GFP_KERNEL);
|
2019-10-05 02:08:34 +08:00
|
|
|
if (!llcp_sock->service_name) {
|
|
|
|
ret = -ENOMEM;
|
2022-03-03 03:25:20 +08:00
|
|
|
goto sock_llcp_put_local;
|
2019-10-05 02:08:34 +08:00
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock);
|
2012-06-22 21:32:20 +08:00
|
|
|
if (llcp_sock->ssap == LLCP_SAP_MAX) {
|
|
|
|
ret = -EADDRINUSE;
|
2022-03-03 03:25:20 +08:00
|
|
|
goto free_service_name;
|
2012-06-22 21:32:20 +08:00
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2012-06-22 20:48:11 +08:00
|
|
|
llcp_sock->reserved_ssap = llcp_sock->ssap;
|
|
|
|
|
2012-05-04 23:04:19 +08:00
|
|
|
nfc_llcp_sock_link(&local->sockets, sk);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
|
|
|
|
|
|
|
|
sk->sk_state = LLCP_BOUND;
|
2022-03-03 03:25:20 +08:00
|
|
|
nfc_put_device(dev);
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_service_name:
|
|
|
|
kfree(llcp_sock->service_name);
|
|
|
|
llcp_sock->service_name = NULL;
|
|
|
|
|
|
|
|
sock_llcp_put_local:
|
|
|
|
nfc_llcp_local_put(llcp_sock->local);
|
|
|
|
llcp_sock->local = NULL;
|
|
|
|
llcp_sock->dev = NULL;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
put_dev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
error:
|
|
|
|
release_sock(sk);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-27 00:16:44 +08:00
|
|
|
static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr,
|
|
|
|
int alen)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct sockaddr_nfc_llcp llcp_addr;
|
|
|
|
int len, ret = 0;
|
|
|
|
|
2017-06-14 00:44:28 +08:00
|
|
|
if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
|
|
|
|
addr->sa_family != AF_NFC)
|
2012-09-27 00:16:44 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family);
|
|
|
|
|
|
|
|
memset(&llcp_addr, 0, sizeof(llcp_addr));
|
|
|
|
len = min_t(unsigned int, sizeof(llcp_addr), alen);
|
|
|
|
memcpy(&llcp_addr, addr, len);
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state != LLCP_CLOSED) {
|
|
|
|
ret = -EBADFD;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = nfc_get_device(llcp_addr.dev_idx);
|
|
|
|
if (dev == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (local == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
llcp_sock->dev = dev;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
llcp_sock->local = local;
|
2012-09-27 00:16:44 +08:00
|
|
|
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
|
|
|
|
|
|
|
|
nfc_llcp_sock_link(&local->raw_sockets, sk);
|
|
|
|
|
|
|
|
sk->sk_state = LLCP_BOUND;
|
|
|
|
|
|
|
|
put_dev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
error:
|
|
|
|
release_sock(sk);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
static int llcp_sock_listen(struct socket *sock, int backlog)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pr_debug("sk %p backlog %d\n", sk, backlog);
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
2012-10-04 21:15:51 +08:00
|
|
|
if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) ||
|
|
|
|
sk->sk_state != LLCP_BOUND) {
|
2011-12-14 23:43:12 +08:00
|
|
|
ret = -EBADFD;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk->sk_max_ack_backlog = backlog;
|
|
|
|
sk->sk_ack_backlog = 0;
|
|
|
|
|
|
|
|
pr_debug("Socket listening\n");
|
|
|
|
sk->sk_state = LLCP_LISTEN;
|
|
|
|
|
|
|
|
error:
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-02-22 17:53:25 +08:00
|
|
|
static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
|
2020-07-23 14:09:07 +08:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2013-02-22 17:53:25 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
u32 opt;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
pr_debug("%p optname %d\n", sk, optname);
|
|
|
|
|
|
|
|
if (level != SOL_NFC)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case NFC_LLCP_RW:
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED ||
|
|
|
|
sk->sk_state == LLCP_BOUND ||
|
|
|
|
sk->sk_state == LLCP_LISTEN) {
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-04-08 16:28:45 +08:00
|
|
|
err = copy_safe_from_sockptr(&opt, sizeof(opt),
|
|
|
|
optval, optlen);
|
|
|
|
if (err)
|
2013-02-22 17:53:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (opt > LLCP_MAX_RW) {
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
llcp_sock->rw = (u8) opt;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NFC_LLCP_MIUX:
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED ||
|
|
|
|
sk->sk_state == LLCP_BOUND ||
|
|
|
|
sk->sk_state == LLCP_LISTEN) {
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-04-08 16:28:45 +08:00
|
|
|
err = copy_safe_from_sockptr(&opt, sizeof(opt),
|
|
|
|
optval, optlen);
|
|
|
|
if (err)
|
2013-02-22 17:53:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (opt > LLCP_MAX_MIUX) {
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-03-20 23:06:12 +08:00
|
|
|
llcp_sock->miux = cpu_to_be16((u16) opt);
|
2013-02-22 17:53:25 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
err = -ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
2013-02-22 18:38:05 +08:00
|
|
|
pr_debug("%p rw %d miux %d\n", llcp_sock,
|
|
|
|
llcp_sock->rw, llcp_sock->miux);
|
|
|
|
|
2013-02-22 17:53:25 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
2013-03-20 23:36:13 +08:00
|
|
|
struct nfc_llcp_local *local;
|
2013-02-22 17:53:25 +08:00
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
int len, err = 0;
|
2013-04-02 16:25:16 +08:00
|
|
|
u16 miux, remote_miu;
|
2013-03-20 23:36:13 +08:00
|
|
|
u8 rw;
|
2013-02-22 17:53:25 +08:00
|
|
|
|
|
|
|
pr_debug("%p optname %d\n", sk, optname);
|
|
|
|
|
|
|
|
if (level != SOL_NFC)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2013-03-20 23:36:13 +08:00
|
|
|
local = llcp_sock->local;
|
|
|
|
if (!local)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2013-02-22 17:53:25 +08:00
|
|
|
len = min_t(u32, len, sizeof(u32));
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case NFC_LLCP_RW:
|
2013-03-20 23:36:13 +08:00
|
|
|
rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
|
|
|
|
if (put_user(rw, (u32 __user *) optval))
|
2013-02-22 17:53:25 +08:00
|
|
|
err = -EFAULT;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NFC_LLCP_MIUX:
|
2013-03-20 23:36:13 +08:00
|
|
|
miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
|
|
|
|
be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
|
|
|
|
|
|
|
|
if (put_user(miux, (u32 __user *) optval))
|
2013-02-22 17:53:25 +08:00
|
|
|
err = -EFAULT;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2013-04-02 16:25:16 +08:00
|
|
|
case NFC_LLCP_REMOTE_MIU:
|
|
|
|
remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
|
|
|
|
local->remote_miu : llcp_sock->remote_miu;
|
|
|
|
|
|
|
|
if (put_user(remote_miu, (u32 __user *) optval))
|
|
|
|
err = -EFAULT;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NFC_LLCP_REMOTE_LTO:
|
|
|
|
if (put_user(local->remote_lto / 10, (u32 __user *) optval))
|
|
|
|
err = -EFAULT;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NFC_LLCP_REMOTE_RW:
|
|
|
|
if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
|
2013-02-22 17:53:25 +08:00
|
|
|
err = -EFAULT;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
err = -ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
if (put_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
void nfc_llcp_accept_unlink(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
|
|
|
|
pr_debug("state %d\n", sk->sk_state);
|
|
|
|
|
|
|
|
list_del_init(&llcp_sock->accept_queue);
|
|
|
|
sk_acceptq_removed(llcp_sock->parent);
|
|
|
|
llcp_sock->parent = NULL;
|
|
|
|
|
|
|
|
sock_put(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk)
|
|
|
|
{
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
struct nfc_llcp_sock *llcp_sock_parent = nfc_llcp_sock(parent);
|
|
|
|
|
|
|
|
/* Lock will be free from unlink */
|
|
|
|
sock_hold(sk);
|
|
|
|
|
|
|
|
list_add_tail(&llcp_sock->accept_queue,
|
2012-03-05 08:03:52 +08:00
|
|
|
&llcp_sock_parent->accept_queue);
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->parent = parent;
|
|
|
|
sk_acceptq_added(parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
|
2012-03-05 08:03:52 +08:00
|
|
|
struct socket *newsock)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct nfc_llcp_sock *lsk, *n, *llcp_parent;
|
|
|
|
struct sock *sk;
|
|
|
|
|
|
|
|
llcp_parent = nfc_llcp_sock(parent);
|
|
|
|
|
|
|
|
list_for_each_entry_safe(lsk, n, &llcp_parent->accept_queue,
|
2012-03-05 08:03:52 +08:00
|
|
|
accept_queue) {
|
2011-12-14 23:43:12 +08:00
|
|
|
sk = &lsk->sk;
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CLOSED) {
|
|
|
|
release_sock(sk);
|
|
|
|
nfc_llcp_accept_unlink(sk);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED || !newsock) {
|
2013-03-26 21:35:57 +08:00
|
|
|
list_del_init(&lsk->accept_queue);
|
|
|
|
sock_put(sk);
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
if (newsock)
|
|
|
|
sock_graft(sk, newsock);
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
pr_debug("Returning sk state %d\n", sk->sk_state);
|
|
|
|
|
2013-02-21 18:04:45 +08:00
|
|
|
sk_acceptq_removed(parent);
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
return sk;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int llcp_sock_accept(struct socket *sock, struct socket *newsock,
|
2024-05-09 23:20:08 +08:00
|
|
|
struct proto_accept_arg *arg)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
struct sock *sk = sock->sk, *new_sk;
|
|
|
|
long timeo;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pr_debug("parent %p\n", sk);
|
|
|
|
|
|
|
|
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
|
|
|
|
|
|
|
if (sk->sk_state != LLCP_LISTEN) {
|
|
|
|
ret = -EBADFD;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2024-05-09 23:20:08 +08:00
|
|
|
timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
/* Wait for an incoming connection. */
|
|
|
|
add_wait_queue_exclusive(sk_sleep(sk), &wait);
|
|
|
|
while (!(new_sk = nfc_llcp_accept_dequeue(sk, newsock))) {
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
|
|
|
|
if (!timeo) {
|
|
|
|
ret = -EAGAIN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (signal_pending(current)) {
|
|
|
|
ret = sock_intr_errno(timeo);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
timeo = schedule_timeout(timeo);
|
|
|
|
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
|
|
|
}
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
|
|
remove_wait_queue(sk_sleep(sk), &wait);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
newsock->state = SS_CONNECTED;
|
|
|
|
|
|
|
|
pr_debug("new socket %p\n", new_sk);
|
|
|
|
|
|
|
|
error:
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-06-21 23:41:42 +08:00
|
|
|
static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
|
2018-02-13 03:00:20 +08:00
|
|
|
int peer)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
2012-06-21 23:41:42 +08:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2012-07-05 23:43:08 +08:00
|
|
|
if (llcp_sock == NULL || llcp_sock->dev == NULL)
|
|
|
|
return -EBADFD;
|
|
|
|
|
2012-06-21 23:41:42 +08:00
|
|
|
pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx,
|
|
|
|
llcp_sock->dsap, llcp_sock->ssap);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2013-04-23 04:24:52 +08:00
|
|
|
memset(llcp_addr, 0, sizeof(*llcp_addr));
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2016-01-30 03:37:40 +08:00
|
|
|
lock_sock(sk);
|
|
|
|
if (!llcp_sock->dev) {
|
|
|
|
release_sock(sk);
|
|
|
|
return -EBADFD;
|
|
|
|
}
|
2013-04-23 04:24:52 +08:00
|
|
|
llcp_addr->sa_family = AF_NFC;
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_addr->dev_idx = llcp_sock->dev->idx;
|
2012-06-21 23:41:42 +08:00
|
|
|
llcp_addr->target_idx = llcp_sock->target_idx;
|
2013-04-23 04:24:52 +08:00
|
|
|
llcp_addr->nfc_protocol = llcp_sock->nfc_protocol;
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_addr->dsap = llcp_sock->dsap;
|
|
|
|
llcp_addr->ssap = llcp_sock->ssap;
|
|
|
|
llcp_addr->service_name_len = llcp_sock->service_name_len;
|
|
|
|
memcpy(llcp_addr->service_name, llcp_sock->service_name,
|
2012-03-05 08:03:52 +08:00
|
|
|
llcp_addr->service_name_len);
|
2016-01-30 03:37:40 +08:00
|
|
|
release_sock(sk);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2018-02-13 03:00:20 +08:00
|
|
|
return sizeof(struct sockaddr_nfc_llcp);
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
|
2017-07-03 12:01:49 +08:00
|
|
|
static inline __poll_t llcp_accept_poll(struct sock *parent)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
2014-11-06 18:20:41 +08:00
|
|
|
struct nfc_llcp_sock *llcp_sock, *parent_sock;
|
2011-12-14 23:43:12 +08:00
|
|
|
struct sock *sk;
|
|
|
|
|
|
|
|
parent_sock = nfc_llcp_sock(parent);
|
|
|
|
|
2014-11-06 18:20:41 +08:00
|
|
|
list_for_each_entry(llcp_sock, &parent_sock->accept_queue,
|
|
|
|
accept_queue) {
|
2011-12-14 23:43:12 +08:00
|
|
|
sk = &llcp_sock->sk;
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED)
|
2018-02-12 06:34:03 +08:00
|
|
|
return EPOLLIN | EPOLLRDNORM;
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-29 00:43:44 +08:00
|
|
|
static __poll_t llcp_sock_poll(struct file *file, struct socket *sock,
|
|
|
|
poll_table *wait)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
2017-07-03 12:01:49 +08:00
|
|
|
__poll_t mask = 0;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
pr_debug("%p\n", sk);
|
|
|
|
|
2018-10-23 19:40:39 +08:00
|
|
|
sock_poll_wait(file, sock, wait);
|
2018-06-29 00:43:44 +08:00
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
if (sk->sk_state == LLCP_LISTEN)
|
|
|
|
return llcp_accept_poll(sk);
|
|
|
|
|
2019-10-24 13:44:50 +08:00
|
|
|
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLERR |
|
|
|
|
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2019-10-24 13:44:50 +08:00
|
|
|
if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLIN | EPOLLRDNORM;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CLOSED)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLHUP;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2012-05-07 18:31:20 +08:00
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
|
2012-05-07 18:31:20 +08:00
|
|
|
|
|
|
|
if (sk->sk_shutdown == SHUTDOWN_MASK)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLHUP;
|
2012-05-07 18:31:20 +08:00
|
|
|
|
2013-05-04 00:29:30 +08:00
|
|
|
if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
|
2012-05-07 18:31:20 +08:00
|
|
|
else
|
2015-11-30 12:03:10 +08:00
|
|
|
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
2012-05-07 18:31:20 +08:00
|
|
|
|
|
|
|
pr_debug("mask 0x%x\n", mask);
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int llcp_sock_release(struct socket *sock)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
2012-03-05 08:03:51 +08:00
|
|
|
int err = 0;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
if (!sk)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_debug("%p\n", sk);
|
|
|
|
|
|
|
|
local = llcp_sock->local;
|
2012-03-05 08:03:51 +08:00
|
|
|
if (local == NULL) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
/* Send a DISC */
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED)
|
2013-06-04 17:34:50 +08:00
|
|
|
nfc_llcp_send_disconnect(llcp_sock);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_LISTEN) {
|
|
|
|
struct nfc_llcp_sock *lsk, *n;
|
|
|
|
struct sock *accept_sk;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
|
2012-03-05 08:03:52 +08:00
|
|
|
accept_queue) {
|
2011-12-14 23:43:12 +08:00
|
|
|
accept_sk = &lsk->sk;
|
|
|
|
lock_sock(accept_sk);
|
|
|
|
|
2013-06-04 17:34:50 +08:00
|
|
|
nfc_llcp_send_disconnect(lsk);
|
2011-12-14 23:43:12 +08:00
|
|
|
nfc_llcp_accept_unlink(accept_sk);
|
|
|
|
|
|
|
|
release_sock(accept_sk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 03:25:22 +08:00
|
|
|
if (sock->type == SOCK_RAW)
|
|
|
|
nfc_llcp_sock_unlink(&local->raw_sockets, sk);
|
|
|
|
else
|
|
|
|
nfc_llcp_sock_unlink(&local->sockets, sk);
|
|
|
|
|
2012-06-22 20:48:11 +08:00
|
|
|
if (llcp_sock->reserved_ssap < LLCP_SAP_MAX)
|
|
|
|
nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
2012-03-05 08:03:51 +08:00
|
|
|
out:
|
2011-12-14 23:43:12 +08:00
|
|
|
sock_orphan(sk);
|
|
|
|
sock_put(sk);
|
|
|
|
|
2012-03-05 08:03:51 +08:00
|
|
|
return err;
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
|
2012-03-05 08:03:52 +08:00
|
|
|
int len, int flags)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
struct sockaddr_nfc_llcp *addr = (struct sockaddr_nfc_llcp *)_addr;
|
|
|
|
struct nfc_dev *dev;
|
|
|
|
struct nfc_llcp_local *local;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);
|
|
|
|
|
2017-05-24 18:26:20 +08:00
|
|
|
if (!addr || len < sizeof(*addr) || addr->sa_family != AF_NFC)
|
2011-12-14 23:43:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2012-10-04 17:51:11 +08:00
|
|
|
if (addr->service_name_len == 0 && addr->dsap == 0)
|
2011-12-14 23:43:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx,
|
2012-03-05 08:03:52 +08:00
|
|
|
addr->target_idx, addr->nfc_protocol);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED) {
|
|
|
|
ret = -EISCONN;
|
|
|
|
goto error;
|
|
|
|
}
|
2021-03-25 11:51:13 +08:00
|
|
|
if (sk->sk_state == LLCP_CONNECTING) {
|
|
|
|
ret = -EINPROGRESS;
|
|
|
|
goto error;
|
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
dev = nfc_get_device(addr->dev_idx);
|
|
|
|
if (dev == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
local = nfc_llcp_find_local(dev);
|
|
|
|
if (local == NULL) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto put_dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
|
|
|
if (dev->dep_link_up == false) {
|
|
|
|
ret = -ENOLINK;
|
|
|
|
device_unlock(&dev->dev);
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto sock_llcp_put_local;
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
|
|
|
|
if (local->rf_mode == NFC_RF_INITIATOR &&
|
2012-03-05 08:03:52 +08:00
|
|
|
addr->target_idx != local->target_idx) {
|
2011-12-14 23:43:12 +08:00
|
|
|
ret = -ENOLINK;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto sock_llcp_put_local;
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llcp_sock->dev = dev;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
llcp_sock->local = local;
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
|
|
|
|
if (llcp_sock->ssap == LLCP_SAP_MAX) {
|
|
|
|
ret = -ENOMEM;
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
goto sock_llcp_nullify;
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
2012-06-22 20:48:11 +08:00
|
|
|
|
|
|
|
llcp_sock->reserved_ssap = llcp_sock->ssap;
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
if (addr->service_name_len == 0)
|
|
|
|
llcp_sock->dsap = addr->dsap;
|
|
|
|
else
|
|
|
|
llcp_sock->dsap = LLCP_SAP_SDP;
|
|
|
|
llcp_sock->nfc_protocol = addr->nfc_protocol;
|
|
|
|
llcp_sock->service_name_len = min_t(unsigned int,
|
2012-03-05 08:03:52 +08:00
|
|
|
addr->service_name_len,
|
|
|
|
NFC_LLCP_MAX_SERVICE_NAME);
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->service_name = kmemdup(addr->service_name,
|
2012-03-05 08:03:52 +08:00
|
|
|
llcp_sock->service_name_len,
|
|
|
|
GFP_KERNEL);
|
2019-03-19 11:19:44 +08:00
|
|
|
if (!llcp_sock->service_name) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto sock_llcp_release;
|
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2012-05-04 23:04:19 +08:00
|
|
|
nfc_llcp_sock_link(&local->connecting_sockets, sk);
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
ret = nfc_llcp_send_connect(llcp_sock);
|
|
|
|
if (ret)
|
2012-05-04 23:04:19 +08:00
|
|
|
goto sock_unlink;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2013-05-04 00:29:30 +08:00
|
|
|
sk->sk_state = LLCP_CONNECTING;
|
|
|
|
|
2012-05-07 18:31:19 +08:00
|
|
|
ret = sock_wait_state(sk, LLCP_CONNECTED,
|
|
|
|
sock_sndtimeo(sk, flags & O_NONBLOCK));
|
2013-05-04 00:29:30 +08:00
|
|
|
if (ret && ret != -EINPROGRESS)
|
2012-05-04 23:04:19 +08:00
|
|
|
goto sock_unlink;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
release_sock(sk);
|
2012-05-07 18:31:19 +08:00
|
|
|
|
2013-05-04 00:29:30 +08:00
|
|
|
return ret;
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2012-05-04 23:04:19 +08:00
|
|
|
sock_unlink:
|
|
|
|
nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
|
2021-03-25 11:51:12 +08:00
|
|
|
kfree(llcp_sock->service_name);
|
|
|
|
llcp_sock->service_name = NULL;
|
2012-05-04 23:04:19 +08:00
|
|
|
|
2019-03-19 11:19:44 +08:00
|
|
|
sock_llcp_release:
|
|
|
|
nfc_llcp_put_ssap(local, llcp_sock->ssap);
|
2022-03-03 03:25:19 +08:00
|
|
|
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
sock_llcp_nullify:
|
net/nfc: fix use-after-free llcp_sock_bind/connect
Commits 8a4cd82d ("nfc: fix refcount leak in llcp_sock_connect()")
and c33b1cc62 ("nfc: fix refcount leak in llcp_sock_bind()")
fixed a refcount leak bug in bind/connect but introduced a
use-after-free if the same local is assigned to 2 different sockets.
This can be triggered by the following simple program:
int sock1 = socket( AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP );
int sock2 = socket( AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP );
memset( &addr, 0, sizeof(struct sockaddr_nfc_llcp) );
addr.sa_family = AF_NFC;
addr.nfc_protocol = NFC_PROTO_NFC_DEP;
bind( sock1, (struct sockaddr*) &addr, sizeof(struct sockaddr_nfc_llcp) )
bind( sock2, (struct sockaddr*) &addr, sizeof(struct sockaddr_nfc_llcp) )
close(sock1);
close(sock2);
Fix this by assigning NULL to llcp_sock->local after calling
nfc_llcp_local_put.
This addresses CVE-2021-23134.
Reported-by: Or Cohen <orcohen@paloaltonetworks.com>
Reported-by: Nadav Markus <nmarkus@paloaltonetworks.com>
Fixes: c33b1cc62 ("nfc: fix refcount leak in llcp_sock_bind()")
Signed-off-by: Or Cohen <orcohen@paloaltonetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-05-04 15:16:46 +08:00
|
|
|
llcp_sock->local = NULL;
|
2022-03-03 03:25:19 +08:00
|
|
|
llcp_sock->dev = NULL;
|
2019-03-19 11:19:44 +08:00
|
|
|
|
net: nfc: Fix use-after-free caused by nfc_llcp_find_local
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@zju.edu.cn>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-06-25 17:10:07 +08:00
|
|
|
sock_llcp_put_local:
|
|
|
|
nfc_llcp_local_put(local);
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
put_dev:
|
|
|
|
nfc_put_device(dev);
|
|
|
|
|
|
|
|
error:
|
|
|
|
release_sock(sk);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-02 15:37:48 +08:00
|
|
|
static int llcp_sock_sendmsg(struct socket *sock, struct msghdr *msg,
|
|
|
|
size_t len)
|
2012-03-05 08:03:37 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
pr_debug("sock %p sk %p", sock, sk);
|
|
|
|
|
|
|
|
ret = sock_error(sk);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (msg->msg_flags & MSG_OOB)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
2022-01-19 15:48:16 +08:00
|
|
|
if (!llcp_sock->local) {
|
|
|
|
release_sock(sk);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2012-10-16 21:04:10 +08:00
|
|
|
if (sk->sk_type == SOCK_DGRAM) {
|
2023-12-20 01:49:44 +08:00
|
|
|
if (sk->sk_state != LLCP_BOUND) {
|
|
|
|
release_sock(sk);
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
|
2014-01-18 05:53:15 +08:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, addr,
|
|
|
|
msg->msg_name);
|
2012-10-16 21:04:10 +08:00
|
|
|
|
|
|
|
if (msg->msg_namelen < sizeof(*addr)) {
|
|
|
|
release_sock(sk);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return nfc_llcp_send_ui_frame(llcp_sock, addr->dsap, addr->ssap,
|
|
|
|
msg, len);
|
|
|
|
}
|
|
|
|
|
2012-03-05 08:03:37 +08:00
|
|
|
if (sk->sk_state != LLCP_CONNECTED) {
|
|
|
|
release_sock(sk);
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return nfc_llcp_send_i_frame(llcp_sock, msg, len);
|
|
|
|
}
|
|
|
|
|
2015-03-02 15:37:48 +08:00
|
|
|
static int llcp_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
|
|
|
size_t len, int flags)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
unsigned int copied, rlen;
|
|
|
|
struct sk_buff *skb, *cskb;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
pr_debug("%p %zu\n", sk, len);
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CLOSED &&
|
2012-03-05 08:03:52 +08:00
|
|
|
skb_queue_empty(&sk->sk_receive_queue)) {
|
2011-12-14 23:43:12 +08:00
|
|
|
release_sock(sk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
if (flags & (MSG_OOB))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2022-04-05 00:30:22 +08:00
|
|
|
skb = skb_recv_datagram(sk, flags, &err);
|
2011-12-14 23:43:12 +08:00
|
|
|
if (!skb) {
|
|
|
|
pr_err("Recv datagram failed state %d %d %d",
|
2012-03-05 08:03:52 +08:00
|
|
|
sk->sk_state, err, sock_error(sk));
|
2011-12-14 23:43:12 +08:00
|
|
|
|
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2012-03-05 08:03:52 +08:00
|
|
|
rlen = skb->len; /* real length of skb */
|
2011-12-14 23:43:12 +08:00
|
|
|
copied = min_t(unsigned int, rlen, len);
|
|
|
|
|
|
|
|
cskb = skb;
|
2014-11-06 05:46:40 +08:00
|
|
|
if (skb_copy_datagram_msg(cskb, 0, msg, copied)) {
|
2011-12-14 23:43:12 +08:00
|
|
|
if (!(flags & MSG_PEEK))
|
|
|
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
2012-11-27 22:44:24 +08:00
|
|
|
sock_recv_timestamp(msg, sk, skb);
|
|
|
|
|
2012-10-15 23:44:44 +08:00
|
|
|
if (sk->sk_type == SOCK_DGRAM && msg->msg_name) {
|
|
|
|
struct nfc_llcp_ui_cb *ui_cb = nfc_llcp_ui_skb_cb(skb);
|
2014-01-18 05:53:15 +08:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, sockaddr,
|
|
|
|
msg->msg_name);
|
2012-10-15 23:44:44 +08:00
|
|
|
|
2013-01-11 21:48:48 +08:00
|
|
|
msg->msg_namelen = sizeof(struct sockaddr_nfc_llcp);
|
2012-10-15 23:44:44 +08:00
|
|
|
|
2013-01-11 21:48:48 +08:00
|
|
|
pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
|
2012-10-15 23:44:44 +08:00
|
|
|
|
2013-04-07 09:51:58 +08:00
|
|
|
memset(sockaddr, 0, sizeof(*sockaddr));
|
2013-01-11 21:48:48 +08:00
|
|
|
sockaddr->sa_family = AF_NFC;
|
|
|
|
sockaddr->nfc_protocol = NFC_PROTO_NFC_DEP;
|
|
|
|
sockaddr->dsap = ui_cb->dsap;
|
|
|
|
sockaddr->ssap = ui_cb->ssap;
|
2012-10-15 23:44:44 +08:00
|
|
|
}
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
/* Mark read part of skb as used */
|
|
|
|
if (!(flags & MSG_PEEK)) {
|
|
|
|
|
|
|
|
/* SOCK_STREAM: re-queue skb if it contains unreceived data */
|
2012-10-15 23:44:44 +08:00
|
|
|
if (sk->sk_type == SOCK_STREAM ||
|
|
|
|
sk->sk_type == SOCK_DGRAM ||
|
|
|
|
sk->sk_type == SOCK_RAW) {
|
2011-12-14 23:43:12 +08:00
|
|
|
skb_pull(skb, copied);
|
|
|
|
if (skb->len) {
|
|
|
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX Queue backlogged skbs */
|
|
|
|
|
|
|
|
done:
|
|
|
|
/* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */
|
|
|
|
if (sk->sk_type == SOCK_SEQPACKET && (flags & MSG_TRUNC))
|
|
|
|
copied = rlen;
|
|
|
|
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct proto_ops llcp_sock_ops = {
|
|
|
|
.family = PF_NFC,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.bind = llcp_sock_bind,
|
|
|
|
.connect = llcp_sock_connect,
|
|
|
|
.release = llcp_sock_release,
|
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
|
.accept = llcp_sock_accept,
|
|
|
|
.getname = llcp_sock_getname,
|
2018-06-29 00:43:44 +08:00
|
|
|
.poll = llcp_sock_poll,
|
2011-12-14 23:43:12 +08:00
|
|
|
.ioctl = sock_no_ioctl,
|
|
|
|
.listen = llcp_sock_listen,
|
|
|
|
.shutdown = sock_no_shutdown,
|
2013-02-22 17:53:25 +08:00
|
|
|
.setsockopt = nfc_llcp_setsockopt,
|
|
|
|
.getsockopt = nfc_llcp_getsockopt,
|
2012-03-05 08:03:37 +08:00
|
|
|
.sendmsg = llcp_sock_sendmsg,
|
2011-12-14 23:43:12 +08:00
|
|
|
.recvmsg = llcp_sock_recvmsg,
|
|
|
|
.mmap = sock_no_mmap,
|
|
|
|
};
|
|
|
|
|
2012-09-27 00:16:44 +08:00
|
|
|
static const struct proto_ops llcp_rawsock_ops = {
|
|
|
|
.family = PF_NFC,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.bind = llcp_raw_sock_bind,
|
|
|
|
.connect = sock_no_connect,
|
|
|
|
.release = llcp_sock_release,
|
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
|
.accept = sock_no_accept,
|
|
|
|
.getname = llcp_sock_getname,
|
2018-06-29 00:43:44 +08:00
|
|
|
.poll = llcp_sock_poll,
|
2012-09-27 00:16:44 +08:00
|
|
|
.ioctl = sock_no_ioctl,
|
|
|
|
.listen = sock_no_listen,
|
|
|
|
.shutdown = sock_no_shutdown,
|
|
|
|
.sendmsg = sock_no_sendmsg,
|
|
|
|
.recvmsg = llcp_sock_recvmsg,
|
|
|
|
.mmap = sock_no_mmap,
|
|
|
|
};
|
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
static void llcp_sock_destruct(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
|
|
|
|
pr_debug("%p\n", sk);
|
|
|
|
|
|
|
|
if (sk->sk_state == LLCP_CONNECTED)
|
|
|
|
nfc_put_device(llcp_sock->dev);
|
|
|
|
|
|
|
|
skb_queue_purge(&sk->sk_receive_queue);
|
|
|
|
|
|
|
|
nfc_llcp_sock_free(llcp_sock);
|
|
|
|
|
|
|
|
if (!sock_flag(sk, SOCK_DEAD)) {
|
|
|
|
pr_err("Freeing alive NFC LLCP socket %p\n", sk);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-09 10:09:13 +08:00
|
|
|
struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp, int kern)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk;
|
|
|
|
struct nfc_llcp_sock *llcp_sock;
|
|
|
|
|
2015-05-09 10:09:13 +08:00
|
|
|
sk = sk_alloc(&init_net, PF_NFC, gfp, &llcp_sock_proto, kern);
|
2011-12-14 23:43:12 +08:00
|
|
|
if (!sk)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
llcp_sock = nfc_llcp_sock(sk);
|
|
|
|
|
|
|
|
sock_init_data(sock, sk);
|
|
|
|
sk->sk_state = LLCP_CLOSED;
|
|
|
|
sk->sk_protocol = NFC_SOCKPROTO_LLCP;
|
|
|
|
sk->sk_type = type;
|
|
|
|
sk->sk_destruct = llcp_sock_destruct;
|
|
|
|
|
|
|
|
llcp_sock->ssap = 0;
|
|
|
|
llcp_sock->dsap = LLCP_SAP_SDP;
|
2013-02-22 18:38:05 +08:00
|
|
|
llcp_sock->rw = LLCP_MAX_RW + 1;
|
2013-03-20 23:06:12 +08:00
|
|
|
llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
|
2011-12-14 23:43:12 +08:00
|
|
|
llcp_sock->send_n = llcp_sock->send_ack_n = 0;
|
|
|
|
llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
|
|
|
|
llcp_sock->remote_ready = 1;
|
2012-06-22 20:48:11 +08:00
|
|
|
llcp_sock->reserved_ssap = LLCP_SAP_MAX;
|
2013-04-02 16:25:15 +08:00
|
|
|
nfc_llcp_socket_remote_param_init(llcp_sock);
|
2011-12-14 23:43:12 +08:00
|
|
|
skb_queue_head_init(&llcp_sock->tx_queue);
|
|
|
|
skb_queue_head_init(&llcp_sock->tx_pending_queue);
|
|
|
|
INIT_LIST_HEAD(&llcp_sock->accept_queue);
|
|
|
|
|
|
|
|
if (sock != NULL)
|
|
|
|
sock->state = SS_UNCONNECTED;
|
|
|
|
|
|
|
|
return sk;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
|
|
|
|
{
|
|
|
|
kfree(sock->service_name);
|
|
|
|
|
|
|
|
skb_queue_purge(&sock->tx_queue);
|
|
|
|
skb_queue_purge(&sock->tx_pending_queue);
|
|
|
|
|
|
|
|
list_del_init(&sock->accept_queue);
|
2012-03-05 08:03:51 +08:00
|
|
|
|
2011-12-14 23:43:12 +08:00
|
|
|
sock->parent = NULL;
|
2012-05-04 17:24:16 +08:00
|
|
|
|
|
|
|
nfc_llcp_local_put(sock->local);
|
2011-12-14 23:43:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int llcp_sock_create(struct net *net, struct socket *sock,
|
2015-05-09 10:09:13 +08:00
|
|
|
const struct nfc_protocol *nfc_proto, int kern)
|
2011-12-14 23:43:12 +08:00
|
|
|
{
|
|
|
|
struct sock *sk;
|
|
|
|
|
|
|
|
pr_debug("%p\n", sock);
|
|
|
|
|
2012-09-27 00:16:44 +08:00
|
|
|
if (sock->type != SOCK_STREAM &&
|
|
|
|
sock->type != SOCK_DGRAM &&
|
|
|
|
sock->type != SOCK_RAW)
|
2011-12-14 23:43:12 +08:00
|
|
|
return -ESOCKTNOSUPPORT;
|
|
|
|
|
2019-09-20 15:35:49 +08:00
|
|
|
if (sock->type == SOCK_RAW) {
|
|
|
|
if (!capable(CAP_NET_RAW))
|
|
|
|
return -EPERM;
|
2012-09-27 00:16:44 +08:00
|
|
|
sock->ops = &llcp_rawsock_ops;
|
2019-09-20 15:35:49 +08:00
|
|
|
} else {
|
2012-09-27 00:16:44 +08:00
|
|
|
sock->ops = &llcp_sock_ops;
|
2019-09-20 15:35:49 +08:00
|
|
|
}
|
2011-12-14 23:43:12 +08:00
|
|
|
|
2015-05-09 10:09:13 +08:00
|
|
|
sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC, kern);
|
2011-12-14 23:43:12 +08:00
|
|
|
if (sk == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct nfc_protocol llcp_nfc_proto = {
|
|
|
|
.id = NFC_SOCKPROTO_LLCP,
|
|
|
|
.proto = &llcp_sock_proto,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.create = llcp_sock_create
|
|
|
|
};
|
|
|
|
|
|
|
|
int __init nfc_llcp_sock_init(void)
|
|
|
|
{
|
|
|
|
return nfc_proto_register(&llcp_nfc_proto);
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfc_llcp_sock_exit(void)
|
|
|
|
{
|
|
|
|
nfc_proto_unregister(&llcp_nfc_proto);
|
|
|
|
}
|