Overview
About vulnerability
In the Linux kernel, the following vulnerability has been resolved:
net: sched: fix memory leak in tcindex_set_parms
Syzkaller reports a memory leak as follows:
BUG: memory leak
unreferenced object 0xffff88810c287f00 (size 256):
comm “syz-executor105”, pid 3600, jiffies 4294943292 (age 12.990s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
backtrace:
[] kmalloc_trace+0x20/0x90 mm/slab_common.c:1046
[] kmalloc include/linux/slab.h:576 [inline]
[] kmalloc_array include/linux/slab.h:627 [inline]
[] kcalloc include/linux/slab.h:659 [inline]
[] tcf_exts_init include/net/pkt_cls.h:250 [inline]
[] tcindex_set_parms+0xa7/0xbe0 net/sched/cls_tcindex.c:342
[] tcindex_change+0xdf/0x120 net/sched/cls_tcindex.c:553
[] tc_new_tfilter+0x4f2/0x1100 net/sched/cls_api.c:2147
[] rtnetlink_rcv_msg+0x4dc/0x5d0 net/core/rtnetlink.c:6082
[] netlink_rcv_skb+0x87/0x1d0 net/netlink/af_netlink.c:2540
[] netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
[] netlink_unicast+0x397/0x4c0 net/netlink/af_netlink.c:1345
[] netlink_sendmsg+0x396/0x710 net/netlink/af_netlink.c:1921
[] sock_sendmsg_nosec net/socket.c:714 [inline]
[] sock_sendmsg+0x56/0x80 net/socket.c:734
[] ____sys_sendmsg+0x178/0x410 net/socket.c:2482
[] ___sys_sendmsg+0xa8/0x110 net/socket.c:2536
[] __sys_sendmmsg+0x105/0x330 net/socket.c:2622
[] __do_sys_sendmmsg net/socket.c:2651 [inline]
[] __se_sys_sendmmsg net/socket.c:2648 [inline]
[] __x64_sys_sendmmsg+0x24/0x30 net/socket.c:2648
[] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
[] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
[] entry_SYSCALL_64_after_hwframe+0x63/0xcd
Kernel uses tcindex_change() to change an existing filter properties.
Yet the problem is that, during the process of changing,
if old_r is retrieved from p->perfect, then
kernel uses tcindex_alloc_perfect_hash() to newly
allocate filter results, uses tcindex_filter_result_init()
to clear the old filter result, without destroying
its tcf_exts structure, which triggers the above memory leak.
To be more specific, there are only two source for the old_r,
according to the tcindex_lookup(). old_r is retrieved from
p->perfect, or old_r is retrieved from p->h.
-
If
old_ris retrieved fromp->perfect, kernel uses tcindex_alloc_perfect_hash() to newly allocate the filter results. Thenris assigned withcp->perfect + handle, which is newly allocated. So conditionold_r && old_r != ris true in this situation, and kernel uses tcindex_filter_result_init() to clear the old filter result, without destroying its tcf_exts structure -
If
old_ris retrieved fromp->h, thenp->perfectis NULL according to the tcindex_lookup(). Considering thatcp->his directly copied fromp->handp->perfectis NULL,ris assigned withtcindex_lookup(cp, handle), whose value should be the same asold_r, so conditionold_r && old_r != ris false in this situation, kernel ignores using tcindex_filter_result_init() to clear the old filter result.
So only when old_r is retrieved from p->perfect does kernel use
tcindex_filter_result_init() to clear the old filter result, which
triggers the above memory leak.
Considering that there already exists a tc_filter_wq workqueue to destroy the old tcindex_d —truncated—
Details
- Affected product:
- AlmaLinux 9.2 ESU , CentOS 8.4 ELS , CentOS 8.5 ELS , CentOS Stream 8 ELS , Oracle Linux 7 ELS , TuxCare 9.6 ESU , Ubuntu 16.04 ELS , Ubuntu 18.04 ELS , Ubuntu 20.04 ELS
- Affected packages:
- linux-hwe @ 4.15.0 (+8 more)
In the Linux kernel, the following vulnerability has been resolved:
net: sched: fix memory leak in tcindex_set_parms
Syzkaller reports a memory leak as follows:
BUG: memory leak
unreferenced object 0xffff88810c287f00 (size 256):
comm “syz-executor105”, pid 3600, jiffies 4294943292 (age 12.990s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………….
backtrace:
[] kmalloc_trace+0x20/0x90 mm/slab_common.c:1046
[] kmalloc include/linux/slab.h:576 [inline]
[] kmalloc_array include/linux/slab.h:627 [inline]
[] kcalloc include/linux/slab.h:659 [inline]
[] tcf_exts_init include/net/pkt_cls.h:250 [inline]
[] tcindex_set_parms+0xa7/0xbe0 net/sched/cls_tcindex.c:342
[] tcindex_change+0xdf/0x120 net/sched/cls_tcindex.c:553
[] tc_new_tfilter+0x4f2/0x1100 net/sched/cls_api.c:2147
[] rtnetlink_rcv_msg+0x4dc/0x5d0 net/core/rtnetlink.c:6082
[] netlink_rcv_skb+0x87/0x1d0 net/netlink/af_netlink.c:2540
[] netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
[] netlink_unicast+0x397/0x4c0 net/netlink/af_netlink.c:1345
[] netlink_sendmsg+0x396/0x710 net/netlink/af_netlink.c:1921
[] sock_sendmsg_nosec net/socket.c:714 [inline]
[] sock_sendmsg+0x56/0x80 net/socket.c:734
[] ____sys_sendmsg+0x178/0x410 net/socket.c:2482
[] ___sys_sendmsg+0xa8/0x110 net/socket.c:2536
[] __sys_sendmmsg+0x105/0x330 net/socket.c:2622
[] __do_sys_sendmmsg net/socket.c:2651 [inline]
[] __se_sys_sendmmsg net/socket.c:2648 [inline]
[] __x64_sys_sendmmsg+0x24/0x30 net/socket.c:2648
[] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
[] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
[] entry_SYSCALL_64_after_hwframe+0x63/0xcd
Kernel uses tcindex_change() to change an existing filter properties.
Yet the problem is that, during the process of changing,
if old_r is retrieved from p->perfect, then
kernel uses tcindex_alloc_perfect_hash() to newly
allocate filter results, uses tcindex_filter_result_init()
to clear the old filter result, without destroying
its tcf_exts structure, which triggers the above memory leak.
To be more specific, there are only two source for the old_r,
according to the tcindex_lookup(). old_r is retrieved from
p->perfect, or old_r is retrieved from p->h.
-
If
old_ris retrieved fromp->perfect, kernel uses tcindex_alloc_perfect_hash() to newly allocate the filter results. Thenris assigned withcp->perfect + handle, which is newly allocated. So conditionold_r && old_r != ris true in this situation, and kernel uses tcindex_filter_result_init() to clear the old filter result, without destroying its tcf_exts structure -
If
old_ris retrieved fromp->h, thenp->perfectis NULL according to the tcindex_lookup(). Considering thatcp->his directly copied fromp->handp->perfectis NULL,ris assigned withtcindex_lookup(cp, handle), whose value should be the same asold_r, so conditionold_r && old_r != ris false in this situation, kernel ignores using tcindex_filter_result_init() to clear the old filter result.
So only when old_r is retrieved from p->perfect does kernel use
tcindex_filter_result_init() to clear the old filter result, which
triggers the above memory leak.
Considering that there already exists a tc_filter_wq workqueue to destroy the old tcindex_d —truncated—