tiann / KernelSU

A Kernel based root solution for Android
https://kernelsu.org
GNU General Public License v3.0
9.09k stars 1.48k forks source link

[Custom] HTTP Toolkit compatibility for KernelSU - how to create app-visible mounts via ADB #1354

Closed pimterry closed 2 months ago

pimterry commented 5 months ago

Describe your problem.

Hi, I'm the maintainer of HTTP Toolkit. HTTP Toolkit is widely used for HTTP interception & debugging on Android, and has tools to automatically setup rooted Android devices via ADB to do so (installing a system CA certificate, and a VPN app to redirect traffic, and then passing various bits of config via intents).

This is compatible with Magisk and seemingly with the comfortable majority of real users' rooted setups that I've seen, but I have at least one KernelSU user (@ThePedroo - https://github.com/httptoolkit/httptoolkit-android/issues/18) who seems to be reporting that KernelSU's approach to rooting doesn't work with HTTP Toolkit's automated setup - the injected system CA certificates are not trusted or visible to most apps.

I'd like to fix that! :smiley:

The likely fix is probably on the HTTP Toolkit side - presumably this isn't a KernelSU bug as such - but it would be useful to understand your internals a little to find the best way to integrate with those, so I'm here looking for more information & ideas.

There's more info about what's happening here in that issue linked above, but to summarize:

I'm opening this just in case you can share some background about why this might happen, and hopefully some suggestions for KernelSU-compatible ways to do this. I can't offer any more details about the specific device setup but hopefully @ThePedroo can answer any questions there.

My best guess is that you're hooking into how mount namespaces are visible directly as part of the app root-access process, which would explain this. A nice solution for me would be a way to access that via an ADB shell, so I can detect when this is happening and mount into the non-root namespace too, or similar.

If possible, I'd really like to have a single script that handles both KernelSU and other rooting mechanisms in the same way, with just extra branches for the small details of detected scenarios (rather than trying to build an entire KernelSU module, which would live totally separate to the existing approach). Of course that depends what's actually happening here and what's possible. Any info you can share very welcome, I'd love to hear your thoughts!

tiann commented 5 months ago

KernelSU will umount modifications to apps by default, if you don't want it to be umounted, you can set it by App Profile

pimterry commented 5 months ago

Thanks @tiann that's very helpful!

KernelSU will umount modifications to apps by default

Ah, I see. This is the "umount modules by default" option described in that documentation you linked.

I understand that changing the App Profile would work for a one off case. For me though, I'm trying to fix this for all HTTP Toolkit KernelSU users (these interception scripts are used to intercept 1000s+ of Android devices every day) and I'd really like to find a way to fully automate this so KernelSU works smoothly like the other rooting mechanisms. If changing the App Profile settings is the only way then I would need to manually detect KernelSU and then show extra prompts walking every user through an extra manual process, which is quite awkward (and probably results in lots of requests from users for support, which I don't want).

I would like to find a way to fully automate this, when running a script against an arbitrary device (so I can't use the UI - just ADB). The scripts involved in HTTP Toolkit are run as root on all these devices though, so I think that's probably possible in a quite few different ways.

I've done some digging through the code to understand this better.

By the look of the umount code at the end of ksu_handle_setuid (here - I assume this is where this is implemented) this is removing a few top-level mountpoints to make this happen. Presumably those mountpoints are always created by KernelSU (i.e. this is the overlayfs) so this is effectively removing the overlayfs to reveal the 'real' filesystem underneath for the target app namespace. Is that correct?

Do you know if it's possible to reliably create mounts within the 'real' non-overlay filesystem directly from a rooted ADB shell? That would solve this problem for me immediately. In that case, when the overlayfs is unmounted, the app would still see the mounts I've created on the underlying filesystem, so everything would work fine.

Alternatively, I can see there's a fixme comment discussing specifically filtering this umounting, so it only applies to KernelSU module mounts. That would also fix this for me (at least for users using new KernelSU) and I suspect this issue will also affect many other similar tools (mostly reverse engineering & developer tools) that use custom mounts via ADB to manage rooted devices, so that would fix all those other cases as well.

Are you interested in working on that soon? I'd be happy to help, although I don't have a KernelSU development setup currently (if you have a guide to emulator setup or a suggestion of a cheap compatible Android to buy for testing, I'm open to getting involved to make this happen).

tiann commented 4 months ago

If you use KernelSU, you need to flash boot image, you can disable the "Unmount the modules by default" in settings when you install it, only do once is enough. I understand your usage scenario, but if you automate it, then we'll receive a lot of requests asking why i can't use XXX bank apps. I think making the people know what they are doing is important, simplify some steps may cause more issues.

pimterry commented 4 months ago

I don't want to automate the "Unmount the modules by default" option, if at all possible, I just want to automate injecting my mount.

I agree that permanently enabling that setting for users automatically & unexpectedly would cause problems for everybody.

However, I think a way to successfully add mounts for HTTP Toolkit only while HTTP Toolkit is running, in a temporary way (like it does right now) won't cause any problems. Even in cases where root detection causes issues, it'll be clear what's happening (while HTTP Toolkit is enabled there's a persistent notification at all times, for example, it's clear the device is in a changed state). That depends on a way to do this temporarily though, which depends on a way to use ADB to manage the mounts that non-rooted apps see.

What do you think about fixing this fixme? That would solve this, for HTTP Toolkit and any others tools & users who want to be able to manage their own mounts via adb.

Alternatively I think I can actually get 'underneath' the mounts anyway, by moving KernelSU's /system mount elsewhere via ADB (mount --move), creating the new certificate mount on the real /system, and then moving KernelSU's mount back afterwards (automated, so it would be moved for just a few milliseconds). That way, when you umount my mount will reappear from underneath. I think this would work. Do you see any big problems there?

tiann commented 4 months ago

If you don't want to automate the "umount by default", you can umount overlayfs by KernelSU, and then mount your files, and remount it again.

If you mount before KernelSU's mouonts, it will keep the mountpoint. we have post-mount.sh already, maybe you need a pre-mount.sh?

tiann commented 4 months ago

What do you think about fixing this fixme? That would solve this, for HTTP Toolkit and any others tools & users who want to be able to manage their own mounts via adb.

This doesn't help. because KernelSU mount /system, and then you mount over it, your mounts are child mounts, if /system is umounted, all child mounts will disappear.

pimterry commented 4 months ago

If you don't want to automate the "umount by default", you can umount overlayfs by KernelSU, and then mount your files, and remount it again

What's the easiest way to automate this from an ADB root shell, while making sure the system ends up back in the correct state afterwards?

I was looking at --move just because it allowed preserving the mount configuration, and I didn't want to mess with the overlayfs mount config and risk ending up in weird states, but if it's easy to just drop and recreate the overlayfs on demand then that'd be perfect!

tiann commented 4 months ago

I think --move may work, but i haven't tried it.

tiann commented 4 months ago

You can refer this commit: https://github.com/tiann/KernelSU/commit/0c52f24612cc572e70b87ea41900c540ec4b2657#diff-8166f6d05dcb9a7f70e4b6aa3299c3f62bba3e870cd07f1f5d05051f52d90e1bL711

It enters the mount namespace of specific process and make mounts for it.