ARM64 内核PXN机制验证测试

PXN简介

PXN全称 Privileged Execute-Never,是一种内核安全特性,用来阻止内核直接执行用户空间的代码,能够极大地提升漏洞利用的难度。

根据kernelsec网站的描述,armv8及以上版本的PXN特性由硬件支持,各平台和架构的PXN特性见下图:

(表格内容来自Linux Kernel Security Subsystem

 结合对linux源码(内核版本5.10.41)的分析可以发现,PXN和UXN机制均通过寄存器中的一个位进行控制,具体实现如下:

arch/arm64/include/asm/pgtable-hwdef.h
/*
 * Level 3 descriptor (PTE).
 */
#define PTE_PXN			(_AT(pteval_t, 1) << 53)	/* Privileged XN */
#define PTE_UXN			(_AT(pteval_t, 1) << 54)	/* User XN */

因为PXN特性取决于硬件平台是否支持,所以即使我们看到代码中有对应的实现,并不代表这个功能在系统上是有效的,因此需要进一步构造测试案例来验证。

构造测试案例

编写内核模块,在内核模块中创建proc文件系统,通过proc_write接口向内核空间传递用户空间的代码地址,然后尝试在内核空间中直接执行来自用户空间的代码。

kernel模块主要逻辑实现如下:

static ssize_t mywrite(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) 
{
    char buf[MAX_LENGTH];
    typedef void (*MY_FUNC_P)(void);

    printk(KERN_INFO "********************* dump stack **********************\n");
    dump_stack();
    
    ((MY_FUNC_P)ubuf)();
    return count;
}
 

用户空间主要逻辑实现如下:

void
payload(void)
{
        if (getuid() == 0) {
                printf("[+] PXN is gone, how dare you!\n");
                execl("/bin/sh", "sh", NULL);
        } else {
                warnx("this will never be execute.");
        }

        _exit(0);
}

extern uint32_t shellCode[];

asm
(
"    .text\n"
"    .align 2\n"
"    .globl shellCode\n\t"
"shellCode:\n\t"

"bl #payload\n\t"
);


void
trigger_vuln(int fd, int canary)
{

#define MAX_PAYLOAD (MAX + 4  * 4 )

        char buf[MAX_PAYLOAD];

        memset(buf, 0, sizeof(buf));

        void * pc = buf ;

        *(void **)pc  = (void *) shellCode;

        write(fd, buf, sizeof(buf) );

		printf("[+] write done, %d bytes\n", sizeof(buf));
}

通过执行测试案例,我们的预期结果是kernel在执行用户空间代码时抛出异常提示,但如果用户空间的测试程序执行之后输出"[+] PXN is gone, how dare you!\n",则表示PXN没有生效。

测试结果

安装内核模块:

vcu-sxxx:/home# insmod lkm_pxn.ko 
vcu-sxxx:/home# [   49.457010] hello...

执行用户空间程序:

vcu-sxxxxx:/home# chmod +x uspace 
vcu-sxxxxx:/home# ./uspace 
[   61.084617] ********************* dump stack **********************
[   61.084642] CPU: 3 PID: 1474 Comm: uspace Tainted: G           O      5.10.41-rt42+g5c4c385db992 #1
[   61.084658] Hardware name: ARM vcu-sxxxxx(DT)
[   61.084663] Call trace:
[   61.084665]  dump_backtrace+0x0/0x180
[   61.084686]  show_stack+0x18/0x70
[   61.084695]  dump_stack+0xd0/0x12c
[   61.084707]  mywrite+0x2c/0xd8 [lkm_pxn]
[   61.084720]  proc_reg_write+0xa8/0xec
[   61.084731]  vfs_write+0xf0/0x2b0
[   61.084743]  ksys_write+0x58/0xe0
[   61.084751]  __arm64_sys_write+0x20/0x30
[   61.084760]  el0_svc_common.constprop.0+0x78/0x1a0
[   61.084772]  do_el0_svc+0x24/0x90
[   61.084780]  el0_svc+0x14/0x20
[   61.084790]  el0_sync_handler+0x1a4/0x1b0
[   61.084797]  el0_sync+0x180/0x1c0
[   61.084810] Unable to handle kernel execution of user memory at virtual address 0000007fd808ce58
[   61.165015] Mem abort info:
[   61.165014] printk: console [ttyLF0]: printing thread stopped
[   61.167933]   ESR = 0x8600000f
[   61.176923]   EC = 0x21: IABT (current EL), IL = 32 bits
[   61.182402]   SET = 0, FnV = 0
[   61.185549]   EA = 0, S1PTW = 0
[   61.188788] user pgtable: 4k pages, 39-bit VAs, pgdp=000000009709d000
[   61.195406] [0000007fd808ce58] pgd=000000008c39b003, p4d=000000008c39b003, pud=000000008c39b003, pmd=0000000081f30003, pte=00e8000086663f43
[   61.208308] Internal error: Oops: 8600000f [#1] PREEMPT_RT SMP
[   61.214289] Modules linked in: lkm_pxn(O) pfeng(O)
[   61.219205] CPU: 3 PID: 1474 Comm: uspace Tainted: G           O      5.10.41-rt42+g5c4c385db992 #1
[   61.228482] Hardware name: ARM XXXXX (DT)
[   61.233300] pstate: 40000005 (nZcv daif -PAN -UAO -TCO BTYPE=--)
[   61.239457] pc : 0x7fd808ce58
[   61.242501] lr : mywrite+0xb4/0xd8 [lkm_pxn]
[   61.246882] sp : ffffffc01235b980
[   61.250275] x29: ffffffc01235b980 x28: ffffff8001d29a80 
[   61.255721] x27: 0000000000000000 x26: 0000000000000000 
[   61.261165] x25: 0000000000000000 x24: 0000000000000000 
[   61.266609] x23: 0000000000000000 x22: ffffffc01235be38 
[   61.272052] x21: 0000007fd808ce58 x20: 0000007fd808ce58 
[   61.277497] x19: 0000000000000050 x18: 00000000fffffffa 
[   61.282941] x17: 0000000000000000 x16: 0000000000000000 
[   61.288385] x15: 0000000000000020 x14: 4141414141414141 
[   61.293828] x13: 4141414141414141 x12: 4141414141414141 
[   61.299272] x11: 4141414141414141 x10: 4141414141414141 
[   61.304715] x9 : 4141414141414141 x8 : 4141414141414141 
[   61.310160] x7 : 4141414141414141 x6 : ffffffc01235b9f0 
[   61.315603] x5 : ffffffc01235b9f0 x4 : 0000000000000008 
[   61.321048] x3 : 858d0cd041414141 x2 : 0000000000000000 
[   61.326493] x1 : 0000007fd808cea8 x0 : 0000000000000000 
[   61.331938] Call trace:
[   61.334442]  0x7fd808ce58
[   61.337127]  proc_reg_write+0xa8/0xec
[   61.340886]  vfs_write+0xf0/0x2b0
[   61.344289]  ksys_write+0x58/0xe0
[   61.347688]  __arm64_sys_write+0x20/0x30
[   61.351709]  el0_svc_common.constprop.0+0x78/0x1a0
[   61.356623]  do_el0_svc+0x24/0x90
[   61.360020]  el0_svc+0x14/0x20
[   61.363154]  el0_sync_handler+0x1a4/0x1b0
[   61.367262]  el0_sync+0x180/0x1c0
[   61.370667] Code: 00000000 00000000 000000ac 00000000 (41414141) 
[   61.376915] ---[ end trace 0000000000000002 ]---
Segmentation fault

从日志“Unable to handle kernel execution of user memory at virtual address”可以确认,内核PXN机制阻止了此次用户空间代码的执行。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车联网安全杂货铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值