In the Linux kernel, the following vulnerability has been resolved:
net: sched: fix memory leak in tcindexsetparms
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: [<ffffffff814cf9f0>] kmalloctrace+0x20/0x90 mm/slabcommon.c:1046 [<ffffffff839c9e07>] kmalloc include/linux/slab.h:576 [inline] [<ffffffff839c9e07>] kmallocarray include/linux/slab.h:627 [inline] [<ffffffff839c9e07>] kcalloc include/linux/slab.h:659 [inline] [<ffffffff839c9e07>] tcfextsinit include/net/pktcls.h:250 [inline] [<ffffffff839c9e07>] tcindexsetparms+0xa7/0xbe0 net/sched/clstcindex.c:342 [<ffffffff839caa1f>] tcindexchange+0xdf/0x120 net/sched/clstcindex.c:553 [<ffffffff8394db62>] tcnewtfilter+0x4f2/0x1100 net/sched/clsapi.c:2147 [<ffffffff8389e91c>] rtnetlinkrcvmsg+0x4dc/0x5d0 net/core/rtnetlink.c:6082 [<ffffffff839eba67>] netlinkrcvskb+0x87/0x1d0 net/netlink/afnetlink.c:2540 [<ffffffff839eab87>] netlinkunicastkernel net/netlink/afnetlink.c:1319 [inline] [<ffffffff839eab87>] netlinkunicast+0x397/0x4c0 net/netlink/afnetlink.c:1345 [<ffffffff839eb046>] netlinksendmsg+0x396/0x710 net/netlink/afnetlink.c:1921 [<ffffffff8383e796>] socksendmsgnosec net/socket.c:714 [inline] [<ffffffff8383e796>] socksendmsg+0x56/0x80 net/socket.c:734 [<ffffffff8383eb08>] syssendmsg+0x178/0x410 net/socket.c:2482 [<ffffffff83843678>] syssendmsg+0xa8/0x110 net/socket.c:2536 [<ffffffff838439c5>] _syssendmmsg+0x105/0x330 net/socket.c:2622 [<ffffffff83843c14>] _dosyssendmmsg net/socket.c:2651 [inline] [<ffffffff83843c14>] _sesyssendmmsg net/socket.c:2648 [inline] [<ffffffff83843c14>] _x64syssendmmsg+0x24/0x30 net/socket.c:2648 [<ffffffff84605fd5>] dosyscallx64 arch/x86/entry/common.c:50 [inline] [<ffffffff84605fd5>] dosyscall_64+0x35/0xb0 arch/x86/entry/common.c:80
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 tcindexallocperfecthash() to newly
allocate filter results, uses tcindexfilterresultinit()
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_r
is retrieved from p->perfect
, kernel uses
tcindexallocperfecthash() to newly allocate the
filter results. Then r
is assigned with cp->perfect + handle
,
which is newly allocated. So condition old_r && old_r != r
is
true in this situation, and kernel uses tcindexfilterresultinit()
to clear the old filter result, without destroying
its tcf_exts structure
If old_r
is retrieved from p->h
, then p->perfect
is NULL
according to the tcindexlookup(). Considering that cp->h
is directly copied from p->h
and p->perfect
is NULL,
r
is assigned with tcindex_lookup(cp, handle)
, whose value
should be the same as old_r
, so condition old_r && old_r != r
is false in this situation, kernel ignores using
tcindexfilterresultinit() to clear the old filter result.
So only when old_r
is retrieved from p->perfect
does kernel use
tcindexfilterresult_init() to clear the old filter result, which
triggers the above memory leak.
Considering that there already exists a tcfilterwq workqueue to destroy the old tcindex_d ---truncated---