【精选】使能和测试ARM64内核PAN机制

您所在的位置:网站首页 blu内核214 【精选】使能和测试ARM64内核PAN机制

【精选】使能和测试ARM64内核PAN机制

2023-10-18 02:04| 来源: 网络整理| 查看: 265

PAN机制简介

内核PAN机制(Privileged Access Never)阻止内核态程序直接访问用户态的数据,只能通过内核提供的固定接口copy_from_user,copy_to_user与用户空间交换数据。使用这一机制的原因主要是因为在某些攻击场景下,黑客通过控制用户态数据来执行漏洞利用,比如towelroot的提权POC[1]。

从实现技术上看,PAN通过修改ttbr0_el1寄存器的值(因为ttbr0_el1寄存器保存着一级页表的地址),使内核无法完成对用户态地址的寻址,从而无法操作用户态地址[2]。另外,使能PAN的内核选项CONFIG_ARM64_SW_TTBR0_PAN的字面意思也清晰地表达了PAN的实现原理——通过“switch ttbr0”来实现PAN。

ARM64使能PAN机制

在ARM64(armv8)上通过启用内核配置CONFIG_ARM64_SW_TTBR0_PAN可以启用PAN功能。需要注意的是,不同CPU架构甚至同一架构下不同版本的使能方式可能存在差别,具体可参考下表:

 (表格来源:Exploit Methods/Userspace data usage - Linux Kernel Security Subsystem)

如何测试PAN是否生效

PAN机制的测试不同于KASLR,KASLR的测试方法十分简单,通过多次启动系统对比内核符号的地址即可判断KASLR是否生效,但PAN机制没办法通过系统环境直接判断是否生效。我们可以通过编写内核模块的方式测试PAN,具体的测试步骤如下:

第一步:编写内核模块,在内核模块中使用memcpy直接访问用户空间数据。

#define BUFSIZE 100 static int kmem = 20; module_param(kmem,int,0660); static struct proc_dir_entry *entry; static ssize_t panwrite(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { int count, len, tmp; char buf[BUFSIZE]; if(*ppos > 0 || count > BUFSIZE) return -EFAULT; memcpy(buf, ubuf, count); count = sscanf(buf,"%d",&tmp); if(count != 1) return -EFAULT; kmem = tmp; len = strlen(buf); *ppos = len; return len; } static const struct proc_ops panops = { .proc_read = panread, .proc_write = panwrite, }; static int pan_init(void) { entry = proc_create("pandev", 0660, NULL, &panops); printk(KERN_ALERT "hello...\n"); return 0; } static void pan_cleanup(void) { proc_remove(entry); printk(KERN_WARNING "bye ...\n"); } module_init(pan_init); module_exit(pan_cleanup);

用户态测试程序如下,主要逻辑是通过buf向内核传递参数,修改/proc/pandev的值:

char buf[100]; int fd = open("/proc/pandev", O_RDWR); read(fd, buf, 100); puts(buf); lseek(fd, 0 , SEEK_SET); write(fd, "33", 5); lseek(fd, 0 , SEEK_SET); read(fd, buf, 100); puts(buf);

第二步:编译模块,在未启用PAN的系统上安装模块并测试。

adas:/home# insmod lkm_hello.ko [ 31.181093] hello... adas:/home# cat /proc/pandev kmem = 20 xcu-s32g274a:/home# ./uspace kmem = 20 kmem = 33 adas:/home# cat /proc/pandev kmem = 33

根据测试结果可知,在未开启PAN的系统上,内核通过memcpy的方式可以直接访问用户态的内存数据,下一步我们将用同样的测试case验证使能后的情况。

第三步:在内核配置中使能PAN。

 在内核配置中开启CONFIG_ARM64_SW_TTBR0_PAN之后重新编译内核,烧录并启动系统,确认/proc/config.gz文件中CONFIG_ARM64_SW_TTBR0_PAN是否使能。

 第四步:再次安装运行测试case。

adas:/home# insmod lkm_hello.ko adas:/home# [ 39.387532] hello... adas:/home# ./uspace [ 90.541095] Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000005589d52f30 [ 90.647970] printk: console [ttyLF0]: printing thread stopped [ 90.649269] Mem abort info: [ 90.656813] ESR = 0x96000005 [ 90.660425] EC = 0x25: DABT (current EL), IL = 32 bits [ 90.665952] SET = 0, FnV = 0 [ 90.669112] EA = 0, S1PTW = 0 [ 90.672367] Data abort info: [ 90.675341] ISV = 0, ISS = 0x00000005 [ 90.679289] CM = 0, WnR = 0 [ 90.682334] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000082da7000 [ 90.689038] [0000005589d52f30] pgd=00000000970de003, p4d=00000000970de003, pud=00000000970de003, pmd=0000000097020003, pte=00e80000974bdf43 [ 90.701908] Internal error: Oops: 96000005 [#1] PREEMPT_RT SMP [ 90.707895] Modules linked in: lkm_hello(O) pfeng(O) [ 90.712994] CPU: 3 PID: 1850 Comm: sh Tainted: G O 5.10.41-rt42+g5c4c385db992 #1 [ 90.721912] Hardware name: XXXXXX (DT) [ 90.726731] pstate: 80400005 (Nzcv daif +PAN -UAO -TCO BTYPE=--) [ 90.732887] pc : __memcpy+0x94/0x180 [ 90.736564] lr : mywrite+0x64/0xc4 [lkm_hello] [ 90.741125] sp : ffffffc01422bcf0 [ 90.744516] x29: ffffffc01422bcf0 x28: ffffff800ad6ea00 [ 90.749962] x27: 0000000000000000 x26: 0000000000000000 [ 90.755406] x25: 0000000000000000 x24: 0000000000000000 [ 90.760851] x23: 0000000000000000 x22: ffffffc01422be30 [ 90.766297] x21: 0000005589d52f30 x20: 0000000000000004 [ 90.771742] x19: ffffffc01422be30 x18: ffffffc010958ec8 [ 90.777187] x17: 0000000000000000 x16: 0000000000000000 [ 90.782630] x15: 0000000000000020 x14: 0000000000000000 [ 90.788074] x13: 0000000000000000 x12: fffffffffffe7687 [ 90.793517] x11: ffffffc010958ee0 x10: ffffffc010960c10 [ 90.798962] x9 : ffffffc01422bcf0 x8 : ffffffc010958ea0 [ 90.804407] x7 : ffffffc01422bb70 x6 : ffffffc01422bd2c [ 90.809851] x5 : ffffff806fc487b8 x4 : 0000000000000000 [ 90.815297] x3 : 0000000000000027 x2 : 0000000000000004 [ 90.820742] x1 : 0000005589d52f30 x0 : ffffffc01422bd2c [ 90.826188] Call trace: [ 90.828693] __memcpy+0x94/0x180 [ 90.832005] proc_reg_write+0xa8/0xec [ 90.835765] vfs_write+0xf0/0x2b0 [ 90.839164] ksys_write+0x6c/0x100 [ 90.842649] __arm64_sys_write+0x20/0x30 [ 90.846667] el0_svc_common.constprop.0+0x78/0x1a0 [ 90.851582] do_el0_svc+0x24/0x90 [ 90.854978] el0_svc+0x14/0x20 [ 90.858112] el0_sync_handler+0x1a4/0x1b0 [ 90.862219] el0_sync+0x184/0x1c0 [ 90.865625] Code: 36180062 f8408423 f80084c3 36100062 (b8404423) [ 90.871875] ---[ end trace 0000000000000002 ]---

内核模块安装成功,但是运行用户态程序之后出现崩溃,根据日志“Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000005589d52f30”等信息,我们可以确认PAN机制阻止了内核对用户态内存数据的直接访问。

参考文献

[1].towelroot提权POC

https://github.com/geekben/towelroot/blob/master/towelroot.c

[2].ARM64 PAN的实现

 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux ttbr0-pan



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3