We're hiring! Join us and help create the future of ARM virtualization.

Using Root from Apps

Technical WriteupsJanuary 2021

Note: If you reached this article because you want applications to use root and don't care about the technical bits - just checkout our repository sud, which contains the instructions needed.

Today a customer was requesting some assistance with how to use `su` from an app that they are installing. While our devices are modeled after a stock Ranchu (AOSP) userdebug device and do include the `su` binary, it is not technically reachable by an application because of a few different security measures put in place by Android. These measures can be easily modified and persisted for allowing anything to use root on your device, but there are a few hindrances from the stock image we are required to get around.

First, the shipped `su` binary from the AOSP image is not accessible to everyone, which we can see here:

shell:/$ stat /system/xbin/su
  File: /system/xbin/su
  Size: 10352           Blocks: 24         IO Block: 4096   regular file
Device: fe00h/65024d    Inode: 10909       Links: 1
Access: (4750/-rwsr-x---)  Uid: (    0/    root)   Gid: ( 2000/   shell)
Access: 2020-12-17 16:09:26.000000000 -0500
Modify: 2020-12-17 16:09:26.000000000 -0500
Change: 2020-12-17 16:09:26.000000000 -0500

This is easy to fix, as we can just change by `chmod`ing it after remounting the `system` partition.

shell:/$ su
root:/# mount -orw,remount /system
root:/# chmod 06755 /system/xbin/su
root:/# stat /system/xbin/su
  File: /system/xbin/su
  Size: 10352           Blocks: 24         IO Block: 4096   regular file
Device: fe00h/65024d    Inode: 10909       Links: 1
Access: (6755/-rwsr-sr-x)  Uid: (    0/    root)   Gid: ( 2000/   shell)
Access: 2020-12-17 16:09:26.000000000 -0500
Modify: 2020-12-17 16:09:26.000000000 -0500
Change: 2021-01-19 20:14:22.305000000 -0500

At this point, we can switch to the userid of any app process and try to use `su`. This file is now executable and accessible; however, we will quickly see the second issue we must address:

root:/# su u0_a47
u0_a47:/$ su
su: not allowed

This secondary issue in AOSP's bundled `su` binary checks if the UID is `AID_ROOT` or `AID_SHELL`, and if it is not, it shows the above message of `not allowed`. This can be seen in the source code for `platform/system/extras/su/su.c` for the tag [7.1.2_r39] and below;

int main(int argc, char** argv) {
    uid_t current_uid = getuid();
    if (current_uid != AID_ROOT && current_uid != AID_SHELL) error(1, 0, "not allowed");

Now we can remove this check, and it will succeed from the command line when we are a different user.

However, there are still more hurdles we need to overcome. Since switching via `su` from a `shell` instance doesn't change the whole context, we don't actually see the next issue until we try to run root as an application. It turns out that the `app_process` which launches the `zygote` will drop the ability for us to add or transfer capabilities to the process, as seen below:

    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
        // EINVAL. Don't die on such kernels.
        if (errno != EINVAL) {
            LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
            return 12;
        }
    }

This can be solved by compiling a new version of `app_process32` and `app_process64`, though now we can see that this is getting to be quiet a messy fix. Even when fixing this problem, we still end up having issues which are actually presented in the kernel - since the application namespaces do not have the `CAP_SETGID` capability, which is checked in the `setgid` function seen below:

SYSCALL_DEFINE1(setgid, gid_t, gid)
{
        struct user_namespace *ns = current_user_ns();
        const struct cred *old;
        struct cred *new;
        int retval;
        kgid_t kgid;
        kgid = make_kgid(ns, gid);
        if (!gid_valid(kgid))
                return -EINVAL;
        new = prepare_creds();
        if (!new)
                return -ENOMEM;
        old = current_cred();
        retval = -EPERM;
        if (ns_capable(old->user_ns, CAP_SETGID))
                new->gid = new->egid = new->sgid = new->fsgid = kgid;
        else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
                new->egid = new->fsgid = kgid;
        else
                goto error;
        return commit_creds(new);
error:
        abort_creds(new);
        return retval;
}

We definitely don't want to have to recompile `su`, `app_process` and the `kernel` - so let us look to the open source world and see how this was solved on real devices. As we see from many different projects like [Superuser], [SuperSU] and [Magisk], they take a su daemon approach. They actually all take this approach, since it appears they all originated from the same source code to begin with. Since all these projects aim to support many devices and install via recoveries, we're going to avoid just using their binaries. They're a bit over-complicated for what we're looking to do, and we would rather have a small, compact binary to do something simple.

Now, as previously mentioned, the aforementioned projects make use of a su daemon. The design is as follows in the below diagram:

    boot
     |
    init
     |
 init-sud.rc            adb (etc)
     |                         |
 su-daemon               su (cli)
     |                         |
   __main thread               |
  |  |                         |
  |  accept(AF_LOCAL)<---------|
  |  |\                        |
  |__| \                       |
       | fork()                |
       | dup2(0, sock)         |______
       | dup2(1, sock)         |      | select(STDIO (client) | STDOUT (forked daemon))
       | execvp(/vendor/bin/sh)|      |
       |<--------------------->|______|

Since Android doesn't want to share the `root` `uid` with anyone who is an application, we just start a daemon process that already holds this permission. Then as applications require `root`, they utilize a socket to connect to the daemon and ask it to perform work for them. There isn't much new here as this has been leveraged for years - though with Corellium we can quickly change these files around and not worry about complexities that are introduced for real devices, such as "systemless" files and `dm-verity`.

This means that by utilizing our su daemon, named `sud`, we can simply copy over the `su` file, set the permissions, and an `rc` file for initialization and `reboot`. After this, the device is ready to go for your use. `sud` is just a simpistic refactor of `Superuser` and can be found at our github repository. For those who are uninterested in compiling the binary, we have also released it in binary form at the same repository in the [release] section.

To setup a device with this new daemon, we simply connect to the device using `adb`, push the files, and then move them to the proper locations and reboot. From a local machine or utilizing the web-ui, simply push/upload the files to the `/data/local/tmp/` directory;

adb push init.sud.rc /data/local/tmp/
adb push bin/su /data/local/tmp/

Then get a `shell` -- either via `adb` or using the `console` tab in the web-ui -- and run the following commands. In both instances, you could simply copy and paste this and it should work fine:

su
/system/bin/mount -orw,remount /system
/vendor/bin/cp /data/local/tmp/su /system/xbin/su
/vendor/bin/chown root /system/xbin/su
/system/bin/chcon u:object_r:su_exec:s0 /system/xbin/su
/vendor/bin/chmod 06755 /system/xbin/su
/vendor/bin/cp /data/local/tmp/init.sud.rc /system/etc/init/init.sud.rc
/vendor/bin/chown root /system/etc/init/init.sud.rc
/system/bin/chcon u:object_r:system_file:s0 /system/etc/init/init.sud.rc
/vendor/bin/chmod 644 /system/etc/init/init.sud.rc
/system/bin/reboot

After the devices are rebooted, all applications on the device can utilize `su`.

Please note that this modified su daemon should definitely not be used on any real life devices, as it is a large security risk. It allows anyone, without restrictions, to use root - it could be abused by any application or process. However, you could easily add restrictions back in or log usage. This binary could be quickly leveraged to work as a honeypot for malware, sort of as a poor-mans "taint tracking" of what is being required by malware, etc. The template we've set forth in the `sud` repository can also serve as a quick and easy way to get multiple services up and running on your Corellium devices as well!

Info
Latest NewsChecking Suspicious Links with Corellium

© Corellium 2021

Privacy