Last modified on

With the official announcement of Android L during the keynote of the Google I/O conference on June 25 and the release of a developer preview the day after, long-foreseen restrictions for root apps became more real.

Note: This article is intended for developers only. The Android L developer preview is also only intended for developers. The information in this article is provided „as-is“ without any guarantees. Use it at your own risk and only use it if you know what you are doing.

Please check Additions for recent additions to this article.

About Android L and SELinux

The developer preview of Android L hints at which restrictions for root apps, mainly with regard to SELinux, can be expected in future. Chainfire provides a very helpful, developer-aimed explanation of the impact of SELinux and thus I won’t dive into more details here. Fact is: most root apps don’t work on the Android L developer preview. At least, not yet. Development of root apps becomes more difficult. As a developer of a root app myself, I’m highly interested in understanding the reasons and fixing them as soon as possible. The restrictions present in the developer preview will most-likely be included in the official release of Android L and later versions. Further restrictions must be expected. Thus, even although the results I describe in this article show that superuser access can still be achieved (at least for some apps) it’s very well possible that these methods won’t work in a few months.

Setup

The following experiments were done on a Nexus 5 running the Android L developer preview. The device was rooted using the steps shown by XDA user savoca here. Thanks, savoca! Additionally, SuperSU 2.00 by Chainfire was used. Thanks, Chainfire!

After setting up the device and rooting it, I tried to run my Android app RepetiTouch Pro. As expected, it did not work. Like many root apps, RepetiTouch uses an executable stored in its private app directory (under /data, e.g., /data/data/com.example.myapp/files/myexecutable) to handle the tasks which require superuser privileges. Trying to run this executable, called eventserver in this app, in a su shell results in

tmp-mksh: ./eventserver: can't execute: Permission denied

SELinux context experiments

Following this test, I experimented with various SELinux file contexts and additionally changed the file owner of this executable to root (the default file owner is similar to u0_a123). The file contexts can be listed via ls -Z and changed via the chcon command which is part of Android’s toolbox. Example:

#



#

#



ls -Z eventserver

-rwx------ u0_a88 u0_a88 u:object_r:app_data_file:s0 eventserver

chcon u:object_r:system_file:s0 eventserver

ls -Z eventserver

-rwx------ u0_a88 u0_a88 u:object_r:system_file:s0 eventserver

SuperSU supports the -cn/–context argument to set the SELinux context, e.g.,

$

su --context u:r:untrusted_app:s0

The default context is u:r:init:s0.

There were different results/errors:

„./eventserver: can’t execute: Permission denied“ with error code 126 and different shells prepended, e.g., „tmp-mksh: ./eventserver: can’t execute: Permission denied“. For this error, exec error is used in the following.

„error: only position independent executables (PIE) are supported.“ with error code 1. For this error, PIE error is used in the following.

success (which only means that the file could be executed, it still might not get access to other files or resources)

Default file context (u:object_r:app_data_file:s0)

su context default owner root owner u:r:init:s0 tmp-mksh: exec error tmp-mksh: exec error u:r:untrusted_app:s0 sh: <stdin>[1]: exec error PIE error u:r:system_app:s0 sh: exec error sh: exec error u:r:system_server:s0 sh: exec error sh: exec error

System file context (u:object_r:system_file:s0)

su context default owner root owner u:r:init:s0 PIE error PIE error u:r:untrusted_app:s0 sh: <stdin>[1]: exec error PIE error u:r:system_app:s0 PIE error PIE error u:r:system_server:s0 PIE error PIE error

Position Independent Executables (PIE)

Information about this kind of executables can be found, e.g., on Wikipedia. Important at this point is that support for PIE was introduced in Android 4.1 (API level 16). However, non-PIE are supported in apparently all Android versions prior to the Android L developer release. When building native binaries for my apps I use the NDK. Because I’m trying to support many versions of Android, I define an API/platform level of 9 in the Application.mk file using

APP_PLATFORM := android-9

However, the resulting executables are then not PIEs. To build PIEs, I changed this to

APP_PLATFORM := android-16

Note: Just changing the platform level this way can result in binaries which don’t work on Android versions previous to Android 4.1. Therefore, in my app, I built the binaries twice, once for API level 9 (to 15) and once for API level 16 and up.

Another note: I assume that this will be useful to most if not all developers of root apps which will run into this PIE error with a very high probability. Thus, check your binaries and build configurations.

After building the eventserver using the updated platform level I repeated the same tests.

Default file context (u:object_r:app_data_file:s0)

su context default owner root owner u:r:init:s0 tmp-mksh: exec error tmp-mksh: exec error u:r:untrusted_app:s0 sh: <stdin>[1]: exec error success (*) u:r:system_app:s0 sh: exec error sh: exec error u:r:system_server:s0 sh: exec error sh: exec error

System file context (u:object_r:system_file:s0)

Important: Please check the addition from July 9 at the end of this post. Changing the file context to u:object_r:system_file:s0 most probably won’t be possible outside of the recovery context in future Android versions.

su context default owner root owner u:r:init:s0 success success u:r:untrusted_app:s0 sh: <stdin>[1]: exec error success (*) u:r:system_app:s0 success success u:r:system_server:s0 success success

Although these results show that it is possible to use the u:r:untrusted_app:s0 context an executable might hit other restrictions as indicated by the two tests with the (*). The eventserver of my app accesses device files in /dev/input/ which can’t be accessed using the u:r:untrusted_app:s0 context. Thus, I’m using u:r:init:s0. At least as long as it works.

Bottom line

Be prepared for the new restrictions and any new restrictions which will be added in future. Although there are probably still ways to operate for many root apps it’s becoming more and more difficult.

Make sure to update your build configurations to create position independent executables. However, also make sure to not break compatibility on older Android versions.

Chainfire suggests to use the u:r:untrusted_app:s0 context wherever possible. I had no luck with this context with my app but generally agree to his advice. You might have to test and use different context for different tasks.

There are many more cases where changes might be required, e.g., sockets. Again, I recommend the explanations by Chainfire which are linked at the beginning of this article.

Additions

June 29: Changing the file context might result in the file being not removed if the app it belongs to is uninstalled. A possible approach to avoid this in most but not all cases is to change the file context when the app is launched and to reset it when the app is closed. However, an app might still be killed by the system leaving the file context changed.

July 4: Please star this issue which Joël Bourquard opened on the issue tracker for the Android L developer preview. Thanks, Joël!

July 9: A Google employee left a discouraging comment and closed the issue Joël Bourquard opened on the Android L developer preview’s issue tracker about the problem mentioned in the addition from June 29. Basically, the issue that files whose contexts were changed could prevent re-installations of the app they belong to is considered to be an application bug. However, much more important is this excerpt from the comment:

3) chcon u:object_r:system_file:s0 outside of recovery is no longer supported as of https://android-review.googlesource.com/95216 . The example provided in the initial bug report will now return EPERM.

Although other root apps might be able to work without using the u:object_r:system_file:s0 context this commit will certainly affect a lot of root apps, including RepetiTouch.

July 10: As far as I can see a possible solution for this issue could be to change the file context via a custom recovery using an appropriate update zip file. As Chainfire points out in this post this would result in further issues with different/outdated custom recoveries etc. This approach would also require a similar update file to reset the file context before uninstalling the app (which makes the issue even a bit more worse). Please post any ideas on this in the comments or contact me.

August 1: Chainfire told me that „the system_file context will be restricted to /system.“ Thus, binaries which require this file context will have to be placed under /system (unless another solution or workaround will be implemented).

October 23: Commenting on the issue on the bug tracker has been disabled. Additionally, a possible solution to the issue is described in comments 12 and 13.

November 4: Chainfire posted a new beta of SuperSU which solves the issue of left behind files by clearing the data directories when an app is fully uninstalled. Thanks a lot!

November 13: I’ve quickly tested RepetiTouch on the final release of Android 5.0 (LRX21O) on my Nexus 5. Recording and replaying touch input works. Thus, I don’t expect any issues but will check and update this post in case any issue occurs. Without having investigated this further, the system_file context apparently is not restricted to /system (yet).