mirror of
https://github.com/Evolution-X-Devices/kernel_google_b1c1
synced 2026-02-01 07:34:20 +00:00
Use-after-free is seen when sending a sockev netlink message since socket is not held which can race with sk_free. KASAN: use-after-free in sockev_client_cb+0x41c/0x4b8 in net/core/sockev_nlmcast.c:104 Read of size 2 at addr ffffffc08420c550 Call trace: dump_backtrace+0x0/0x388 arch/arm64/kernel/time.c:55 show_stack+0x24/0x30 arch/arm64/kernel/traps.c:152 __dump_stack+0x24/0x2c lib/dump_stack.c:17 dump_stack+0x8c/0xd0 lib/dump_stack.c:53 print_address_description+0x74/0x234 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x240/0x264 mm/kasan/report.c:412 __asan_report_load2_noabort+0x2c/0x38 mm/kasan/report.c:431 sockev_client_cb+0x41c/0x4b8 net/core/sockev_nlmcast.c:104 notifier_call_chain+0x104/0x158 kernel/notifier.c:93 __blocking_notifier_call_chain+0x80/0xb0 kernel/notifier.c:317 blocking_notifier_call_chain+0x3c/0x4c kernel/notifier.c:328 sockev_notify+0x30/0x3c net/socket.c:181 SYSC_bind net/socket.c:1509 [inline] SyS_bind+0x1ec/0x30c net/socket.c:1489 el0_svc_naked+0x34/0x38 Freed by task 19460: save_stack mm/kasan/kasan.c:447 [inline] set_track mm/kasan/kasan.c:459 [inline] __kasan_slab_free+0x134/0x20c mm/kasan/kasan.c:520 kasan_slab_free+0x10/0x1c mm/kasan/kasan.c:527 slab_free_hook mm/slub.c:1401 [inline] slab_free_freelist_hook mm/slub.c:1422 [inline] slab_free mm/slub.c:2979 [inline] kmem_cache_free+0x114/0x664 mm/slub.c:3001 sk_prot_free net/core/sock.c:1504 [inline] __sk_destruct+0x324/0x3c0 net/core/sock.c:1585 __sk_free+0x180/0x200 net/core/sock.c:1601 sk_free+0x44/0x50 net/core/sock.c:1612 sock_put include/net/sock.h:1643 [inline] sk_common_release+0x198/0x20c net/core/sock.c:3014 raw_close+0x38/0x44 net/ipv4/raw.c:703 inet_release+0x128/0x15c net/ipv4/af_inet.c:446 __sock_release+0xb8/0x258 net/socket.c:614 sock_close+0x24/0x34 net/socket.c:1150 __fput+0x1f4/0x4e4 fs/file_table.c:345 ____fput+0x20/0x2c fs/file_table.c:380 task_work_run+0x9c/0x174 kernel/task_work.c:113 Change-Id: Idb4335889b6e4228f36d76ca5b6156cc5e5838da Signed-off-by: Sharath Chandra Vurukala <sharathv@codeaurora.org>
158 lines
3.6 KiB
C
158 lines
3.6 KiB
C
/*
|
|
* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*
|
|
* Default SOCKEV client implementation
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/export.h>
|
|
#include <linux/netlink.h>
|
|
#include <linux/sockev.h>
|
|
#include <net/sock.h>
|
|
|
|
static int registration_status;
|
|
static struct sock *socknlmsgsk;
|
|
|
|
static void sockev_skmsg_recv(struct sk_buff *skb)
|
|
{
|
|
pr_debug("%s(): Got unsolicited request\n", __func__);
|
|
}
|
|
|
|
static struct netlink_kernel_cfg nlcfg = {
|
|
.input = sockev_skmsg_recv
|
|
};
|
|
|
|
static void _sockev_event(unsigned long event, __u8 *evstr, int buflen)
|
|
{
|
|
|
|
switch (event) {
|
|
case SOCKEV_SOCKET:
|
|
strlcpy(evstr, "SOCKEV_SOCKET", buflen);
|
|
break;
|
|
case SOCKEV_BIND:
|
|
strlcpy(evstr, "SOCKEV_BIND", buflen);
|
|
break;
|
|
case SOCKEV_LISTEN:
|
|
strlcpy(evstr, "SOCKEV_LISTEN", buflen);
|
|
break;
|
|
case SOCKEV_ACCEPT:
|
|
strlcpy(evstr, "SOCKEV_ACCEPT", buflen);
|
|
break;
|
|
case SOCKEV_CONNECT:
|
|
strlcpy(evstr, "SOCKEV_CONNECT", buflen);
|
|
break;
|
|
case SOCKEV_SHUTDOWN:
|
|
strlcpy(evstr, "SOCKEV_SHUTDOWN", buflen);
|
|
break;
|
|
default:
|
|
strlcpy(evstr, "UNKNOWN", buflen);
|
|
}
|
|
}
|
|
|
|
static int sockev_client_cb(struct notifier_block *nb,
|
|
unsigned long event, void *data)
|
|
{
|
|
struct sk_buff *skb;
|
|
struct nlmsghdr *nlh;
|
|
struct sknlsockevmsg *smsg;
|
|
struct socket *sock;
|
|
struct sock *sk;
|
|
|
|
sock = (struct socket *)data;
|
|
if (!socknlmsgsk || !sock)
|
|
goto sk_null;
|
|
|
|
sk = sock->sk;
|
|
if (!sk)
|
|
goto sk_null;
|
|
|
|
sock_hold(sk);
|
|
|
|
if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)
|
|
goto done;
|
|
|
|
if (event != SOCKEV_BIND && event != SOCKEV_LISTEN)
|
|
goto done;
|
|
|
|
skb = nlmsg_new(sizeof(struct sknlsockevmsg), GFP_KERNEL);
|
|
if (!skb)
|
|
goto done;
|
|
|
|
nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct sknlsockevmsg), 0);
|
|
if (!nlh) {
|
|
kfree_skb(skb);
|
|
goto done;
|
|
}
|
|
|
|
NETLINK_CB(skb).dst_group = SKNLGRP_SOCKEV;
|
|
|
|
smsg = nlmsg_data(nlh);
|
|
|
|
memset(smsg, 0, sizeof(struct sknlsockevmsg));
|
|
|
|
smsg->pid = current->pid;
|
|
_sockev_event(event, smsg->event, sizeof(smsg->event));
|
|
smsg->skfamily = sk->sk_family;
|
|
smsg->skstate = sk->sk_state;
|
|
smsg->skprotocol = sk->sk_protocol;
|
|
smsg->sktype = sk->sk_type;
|
|
smsg->skflags = sk->sk_flags;
|
|
nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL);
|
|
done:
|
|
sock_put(sk);
|
|
sk_null:
|
|
return 0;
|
|
}
|
|
|
|
static struct notifier_block sockev_notifier_client = {
|
|
.notifier_call = sockev_client_cb,
|
|
.next = 0,
|
|
.priority = 0
|
|
};
|
|
|
|
/* ***************** Startup/Shutdown *************************************** */
|
|
|
|
static int __init sockev_client_init(void)
|
|
{
|
|
int rc;
|
|
|
|
registration_status = 1;
|
|
rc = sockev_register_notify(&sockev_notifier_client);
|
|
if (rc != 0) {
|
|
registration_status = 0;
|
|
pr_err("%s(): Failed to register cb (%d)\n", __func__, rc);
|
|
}
|
|
socknlmsgsk = netlink_kernel_create(&init_net, NETLINK_SOCKEV, &nlcfg);
|
|
if (!socknlmsgsk) {
|
|
pr_err("%s(): Failed to initialize netlink socket\n", __func__);
|
|
if (registration_status)
|
|
sockev_unregister_notify(&sockev_notifier_client);
|
|
registration_status = 0;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void __exit sockev_client_exit(void)
|
|
{
|
|
if (registration_status)
|
|
sockev_unregister_notify(&sockev_notifier_client);
|
|
}
|
|
|
|
module_init(sockev_client_init)
|
|
module_exit(sockev_client_exit)
|
|
MODULE_LICENSE("GPL v2");
|
|
|