-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No more exec from data folder on targetAPI >= Android Q #1072
Comments
I brought up that this was forbidden and would likely become part of the SELinux policy last year (9 Apr 2018): #655. As I stated then,
It doesn't fundamentally break Termux, but rather Termux would need to switch to an alternative approach for distributing packages. Using apt within the app sandbox to install code isn't going to be viable anymore. The restrictions are no doubt going to be tightened up in the future too, and it can be expected that libraries will need to be mapped from the read-only app data directory or apk too, rather than the read-write home directory working. It wouldn't be necessary to split absolutely everything into assorted apks, but rather there could be apks for groups of related packages based on size. Termux can initiate the apk installs itself too, after prompting the user to allow it as an unknown source. It's an inconvenience for sure, but not a deal breaker. Someone there accused me of concern trolling, but I was genuinely giving an insider heads up about likely changes on the horizon bringing w^x enforcement for data in storage. I use Termux and also work on Android OS security, so I wanted to have a conversation about how this could be addressed long before it was going to become a problem. I provided enforcement of the same kind of restrictions in my own downstream work, but with a toggle to turn it off for apps like Termux. I would have loved to have an alternate option for installing packages compatible with the security feature, and that would have prepared Termux for the eventual enforcement of this feature upstream. It's worth noting that there are still holes in the SELinux policy, which can be used to bypass it by jumping through some hoops, but the intention is clearly to move towards enforcing w^x and enforcing the official rules via the implementation. See https://play.google.com/about/privacy-security-deception/malicious-behavior/.
Termux could also ship the necessary scripting for generating a Termux package apk from executables/libraries so that users could create their own and continue running their own code, albeit less conveniently. |
@xeffyr This only applies to apps targeting API > 28. Termux will continue to work indefinitely as long as it continues to target API 28. However, there's a timeline for phasing out old API targets on the Play Store about a year after they're introduced. It then becomes impossible to upload a new version of the app without updating the target API level. https://developer.android.com/distribute/best-practices/develop/target-sdk Distributing the app outside the Play Store would still be possible, but the OS has the concept of a minimum supported target API level already (ro.build.version.min_supported_target_sdk). It's currently 17 in Android P and is being increased to 23 in Android Q. It currently only produces a warning, but it won't necessarily remain that way. They don't want targeting an old API level or distributing outside the Play Store to be a loophole for bypassing privacy and security restrictions tied to API level. |
I apologize for how issue #655 was received, I guess people freaked out and decided to shoot the messenger. We should have moderated it better.
I guess we have a year or two (at least) to figure out how to deal with this then |
You can probably stay at API 28 until around November 2020 for the Play Store assuming the timeline at https://developer.android.com/distribute/best-practices/develop/target-sdk is followed again for API 29. It would be even longer until using API 28 broke outside the Play Store via a stricter future version of ro.build.version.min_supported_target_sdk doing more than warning. Probably at least 2 years and likely significantly longer. So, it's not like it's going to suddenly break when Android Q comes out, since it's only for API 29+. |
That is horrible in terms of usability. Also wouldn't the apks need to be signed with original apk key? |
Not only signed with original key. It seems that executables will have to be placed to native lib directory:
|
Python, Ruby, Perl, etc. written by users will still work without a hassle because it's not native code. They won't be able to execute it as In the future, native libraries will likely all need to be in the native library directory to work but for API 29 they're only enforcing it for executables. I expect the enforcement will happen for native libraries next year, since they already added an
Yes, that's what I was saying would need to happen: bundling groups of related packages inside of shared uid apks signed with the same key. For users to be able to extend it with their own native code, they would need to have their own build of Termux signed with their own key, along with scripting for generating new extension apks out of their code. There might be a better approach than my suggestion. It was just intended as a starting point. It will also still be possible to interpret native code from the app data directory. For example, I think |
Is this a potential use case for Dynamic Delivery using App Bundles? A dynamic feature module could be either a bundled group of related packages, or, if still feasible, each separate package. The submitted app bundle would include all available packages, where the base installation is only core packages, and This would likely require a pretty robust build system to keep the Google Play listing's packages in parity with termux-packages, perhaps as a separate listing from termux-core. I see this as a way to comply with Google Play while still allowing a package manager-like function, potentially with another mechanism for installations outside of Google Play or from source that more closely resembles the current mechanism. |
It could work, if dynamic feature modules are able to ship additional executables / libraries to be extracted into the native libraries directory. It's not clear if that's possible. It appears the limit is 500MB via an app bundle, rather than 100MB, so it's a limited solution:
I don't think it's going to be able to be much different outside the Play Store, since the SELinux policy restrictions on executing only read-only native code still apply for apps outside the Play Store and Android variants without the Play Store or Play Services. It would make sense to work around this issue at the same time as coming into compliance with the Play Store policy on downloading executable code, but they don't necessarily need to be solved at the same time. I think it would be best to choose a path that will work both inside and outside the Play Store. I don't know how realistic it is to support the app bundle and dynamic feature modules outside Play, since there isn't an existing distribution option with support for it and it's not clear how much is available without Play Services, etc. |
Sure--I supposed my suggestion was intended more as a solution to the SELinux policy restrictions by using Google Play, but it does hinge on 1) the ability to ship additional executables (I suspect their example of games would make that true, but it is still a question) and 2) reliance on Google Play as a complete distribution system and being subject to their rules and whims. It's a difficult problem, no doubt. I suspect that the timing of App Bundles and the native executable restriction policy are not entirely unrelated, and a solution to downloading and executing arbitrary native code without going through Google Play isn't immediately obvious.
Seems to be the quickest and simplest solution at this point, with the above mentioned restrictions which may annihilate realistic usability. |
What if you bundled PRoot (and busybox and a bare minimum of what is required to get a PRooted system setup and running) with the app itself and then had everything run through PRoot. Could PRoot be modified to allow executing outside of the This is the most recent example of how PRoot can defeat Notice what is not blocked here: https://android-review.googlesource.com/c/platform/system/sepolicy/+/804149 There would be a performance impact of course, but maybe it allows the party to go on. I work on UserLAnd and we always use PRoot. This is where my mind went when I heard of this limitation. Thought I would share. |
If proot works, this means that we can left packages as-is. Proot also means that Termux will no longer be prefixed which is good as a lot of patches can be dropped + less headache with compiling software by user. Will try to package proot into Termux APK and run on Android Q AVD to test this. |
I think that proot (or other theoretically possible packages like this) will be broken no earlier than Google forbids any kind of JIT in 3rd-party applications, so this is a very nice idea. I'm still not sure if Google will ever dare to do such thing. |
If Google do this, it has to forbid javascript in browsers too. |
PRoot will certainly execute from the apps |
@corbinlc Original proot worked. Even this anti-noexec extension not needed. So under proot everything works fine: No need to distribute packages in APKs or bundles. Everything that is needed is to launch shell under proot. |
Note that execute for app_data_file (mapping as PROT_EXEC) had an auditallow rule added after this commit as they're planning on removing that in the near future, perhaps next year. It will currently log audit warnings leading up to the likely eventual removal. The remaining holes in the SELinux policy are tied to the ART JIT and other JIT compilers: ashmem execute (an implementation detail that could change) and execmem (in-memory rwx code and rw -> rx transitions). ART supports using full AOT compilation instead of the JIT compiler, but it's not their current choice. Chromium-based browsers including the WebView use execmem in the isolated_app domain, not untrusted_app, so even without an Apple-like approach only permitting the bundled browser and WebView for other apps to use, that wouldn't be a direct blocker. I would be surprised if they removed execmem for untrusted_app in the near future, but it could happen over the longer term, especially if they simply restrict it to a variant of isolated_app. The original issue that I filed (#655) was about the general problem of this being in violation of their policy, before there was a partial implementation of a technical mechanism enforcing it for native code. There can never be full enforcement at a technical level since interpreters will continue to work even once native code execution is forbidden.
They permit JavaScript via the exception in the policy for isolated virtual machines:
https://play.google.com/about/privacy-security-deception/malicious-behavior/ The result at a technical level would be that they need to keep around execmem for a variant of the isolated_app SELinux domain used by browsers, but not untrusted_app. At the moment, both isolated_app and untrusted_app permit execmem, but Chromium doesn't use it in untrusted_app. ART uses the untrusted_app execmem when configured to do JIT compilation via the relevant system properties. It's fully optional though, and still supports full AOT compilation as was done in Android 6. |
@xeffyr I guess that makes sense, since PRoot already deals with |
@thestinger interesting comment about them potentially removing the ability to Do you know if they are planning on preventing |
Files in the app home directory are labelled as app_data_file and this is the audit rule generating warnings for mapping the data as executable: They add auditallow rules leading up to eventually removing it from the policy. You can try loading a library from app data with API 29 and you'll see an audit warning in the logs. In-memory code generation via rwx pages or rw -> rx transitions is classified as execmem, which is something they'd like to remove in the long-term but it's currently used by the ART JIT. It's not used by Chromium within untrusted_app domains, since it only does that within the sandboxed renderers which use isolated_app domains. They could remove it from the main isolated_app and require that apps opt-in to having it available via a special domain. It should be expected that it will be eventually happen, since this is a very standard form of security hardening and they've been slowly moving towards it. They already removed execmem for some of the base system including system_server. Their security team would obviously like to remove it everywhere, but for now the performance vs. memory vs. storage usage characteristics of mixed AOT and JIT compilation for ART are winning out over the security advantages of pure AOT compilation with execmem disallowed. |
The only reason they're starting with requiring executables to be in the native library directory rather than native libraries (which is the main purpose of the directory) is because that will impact more apps, so the transition will be more painful. Apps can also disable native library extraction and map native libraries from the apk directly, since the linker supports mapping libraries from zips directly as long as they meet the requirements (page aligned and not compressed). They have a pass for properly aligning them in the apk build system. |
It will actually log the warning about native libraries in the data directory for all API levels. Here's where they continue to allow running executables from app_data_file for API < 28: Even though it's allowed, they do still log audit warnings about it for API < 29. Also you can see that for API < 26, even more is permitted, since they've tightened up these policies for API 26+ in the past too: For example, API 26+ forbid execmod which means things like rx -> rw -> rx transitions for files mapped from storage. You can only do those kinds of transitions in-memory via execmem now. They've removed execmem for a lot of the base system but not yet apps, which is as I mentioned primarily due to the ART JIT and it'd also be a major backwards incompatible change. Finishing this up by removing the remaining 3 or so holes in the policy is definitely on their radar. It's just hard to get it done due to compatibility issues and performance/memory/storage vs. security tradeoffs made elsewhere that they'd need to decide are less important (and I definitely think they will, eventually). |
This is great info @thestinger |
One more thing to mention Google is planning to deny any type of exec, read here: https://issuetracker.google.com/issues/128554619
The steps they took:
So any solution implemented here will probably not work next year or even earlier. Essentially they will kill apps like Termux, server apps, ... unless you build everything using jni / ndk. |
Not kill, if we switch to QEMU (system mode). It should be possible to turn QEMU into shared library (Limbo PC app did this) and attach serial consoles as terminals. Performance will be worse, but still usable. That is, of course, if QEMU doesn't use mmap(PROT_EXEC), execmem or other similar things which may be blacklisted. |
That's not backed up by what you're linking and I don't think it's true.
Executing downloaded code was denied by policy for a long time too. I only opened an issue when the wording became substantially stronger and considered malicious regardless of why it's done. I think Termux has been in violation of the policy as long as it has existed, but it became more clear that it was serious a year ago.
Spawning processes with exec based on the native library directory is fully allowed by their app policy and documented as a supported feature. A random Google engineer on the bug tracker urging you to be cautious about using exec is good advice and doesn't imply there's any plan to remove it. Mapping code from outside the native library directory and apk as exec is definitely on the way out, and class loading is probably on their radar. There is not much they could do about third party interpreters beyond forbidding it in policy. The general policy is that executing arbitrary code not included with the apk is only allowed if it runs in a well sandboxed virtual machine, with the Chromium web sandbox as a baseline to compare since it's allowed through that exception. They have no security reason to remove it now that they enforce w^x for it. Relying on executing system executables is a bad idea and it'd make sense for them to continue stripping down what is allowed. By saying it's problematic, they are not saying that it's going to be forbidden, but rather that it doesn't fit well into a model where apps are often killed at any time and then respawned with the expectation that they saved all of their state to be restored, etc. That model can be more aggressive on some devices, which is what makes it problematic. Switching away from the app can result in all these native processes getting killed, potentially losing data. In practice, it's fine, especially with a foreground service to prioritize keeping the app alive. It also applies to a lot more than native processes. A long-running foreground service doesn't conform to the activity life cycle either. Essentially the same potential for problems there.
I also don't think it's true.
I think QEMU does rely on execmem. I'm not sure that it can be used without it. So, while that will currently work, it may not in the long term. I do think executing files from the native library directory is going to continue working in the long term. Using an emulator is certainly a viable approach though, but obviously slow, especially without execmem at some future point. The viable long-term approach is using documented ways of doing things, and they have documentation showing how to execute something from the native library directory, along with that being fully supported for native libraries. |
It's an issue tracker thread aimed at productively finding solutions to future compatibility issues starting with API 29. There's no point of being hysterical / dramatic and treating understandable security changes as an unpredictable, draconian crackdown on apps. The compatibility issue is unfortunate. There are trade-offs to changes like this, and this is the downside to it. The upside is making apps more secure against exploitation, while not hurting the vast majority of them.
It was the policy that all code was signed and must come from Google Play for a long time. It was stated in multiple locations in different ways, and reworded into stronger wording over time. For example, here's one case that the policy is stated in 2013:
The intent is all apps don't execute code that was signed and delivered through Google Play, other than outside of a sandboxed virtual machine environment (such as web content). Yes, it has been possible to play semantic games with all variants of the wording, including the very aggressively worded version introduced in the malicious apps policy. It's best to understand the intent of the policy and comply with that, rather than trying to find loopholes. It has been worded different ways even at the same time, on different policy pages.
That's not what I said and I don't know where you're getting that. I said relying on system executables is a bad idea rather than shipping them with the app. For example, using the system toolbox / toybox would be a bad idea even if the SELinux policy allows it. It's not part of the official API. It remains possible to execute native code, but the implementation permits fewer violations of the policy than it did before, not as an attempt to enforce the policy but to mitigate vulnerabilities in apps. It's expected that code is shipped in the apk, and either executed from the apk or the native library directory. You aren't supposed to execute Java code from outside an installed apk / app bundle component either. That isn't impacted by SELinux policy right now. They could teach the class loader to enforce rules, but as I mentioned, they fundamentally cannot prevent people from breaking the rules with interpreters via a technical approach. As I explained above, this has nothing to do with protecting the system from apps or protecting user data from apps but rather improving security for apps themselves. That's certainly something important and is a real world problem. There have been many cases of apps exploited due to them executing code from app data. They introduced a partial mitigation for it, in a way that only truly breaks compatibility with apps they'd already defined as violating their policies. That's why it made sense for them to do this. Yes, it's unfortunate for Termux, but they aren't doing it to be evil.
I mean exactly what I said. Apps executing system executables are relying on a non-public API and can definitely expect problems, just like using private APIs elsewhere. You're reading something and twisting the meaning into what you want to see based on your already negative outlook. You view these security improvements as something bad. It's a balance between different needs, and the balance is moving towards security. That will make some people upset, but it's what most people want. There has always been this balance in place, and most people think Android was way too permissive with apps and needs to continue changing.
Fuchsia is not Linux and is effectively a different platform. They may end up implementing a very complete layer for Linux binary compatibility. The CTS requires Linux compatibility so if they want full Android support they need to provide it. That's their problem to figure out. Executing native code is still possible there, but it's not Linux and currently isn't compatible with Linux at the ABI or API level. ChromeOS simply ships Android as a whole in a container and provides an Android compatible Linux kernel. It's just another kind of Android device and is CTS compatible. The low-level portions of Android like Bionic and SELinux policy are entirely developed in the open rather than having code dumps. I also talk with members of their security team fairly regularly. It's not a mystery what they are working on and where they are planning on taking it in the future. It's not surprising that they partially implemented a very standard security mitigation used across other operating systems in various forms (not just iOS), and it's in line with their existing policy. You can look through the SELinux policy repository and see commit messages and code comments describing many of the future breaking changes. They released the v2 sandbox (targetSandboxVersion) with Nougat and among other things it disabled app_data_file execution as a whole. That was essentially a preview of future changes. There are a few long-term options. One is figuring out a way to ship code as part of apks and a way to offer users the option of generating an apk wrapping their native code in a usable way. Another is using a virtual machine to run everything, which would also work on non-Linux platforms, but supporting those is probably never going to be necessary. Those platforms would need to implement Linux compatibility to be Android compatible. This would be slower, especially if support for using a JIT compiler in untrusted_app goes away. It could be moved to isolated_app, but that would be hard. |
Also, regarding shared libraries in $PREFIX, --> https://support.google.com/googleplay/android-developer/answer/9888379?hl=en&ref_topic=9877467
|
Shared libraries seems like under SELinux restrictions too. (have
Probably because SELinux does not restrict So placing shared libraries into $PREFIX are out of scope in any way. UPD: test without termux-exec for clean results:
|
Got it. |
OK, so here's the final proposal, extended from what I wrote above, which I believe would work under Play Store restrictions as laid out by @xeffyr above: Build all Termux packages and ship only the top 50-100 (ie how many ever fit under the apk size limit) most popular packages' native executables from the old com.termux/files/usr/bin/ folder and shared libraries from the old com.termux/files/usr/lib/ with the apk, but preinstalled in the SELinux-safe com.termux/lib/ directory instead. The Termux apk also comes with those popular packages' compressed .deb files, but the .debs no longer contain executables or shared libraries, and only these are uncompressed by apt/dpkg into $PREFIX when When a .deb package is installed, modify apt to simply stick a symbolic link in Next, create Termux package set apks, similar to the current addon apks like Termux API, that install all executables and shared libraries from that package set in com.termux/lib/ and ship the executable/library-free .deb packages for apt/dpkg/pkg to install, and distribute these apks from the Play Store. If addon apks signed by com.termux are allowed to install executables and shared libraries in com.termux/lib/, this scheme should work and allow us to keep using apt/pkg for much of package management, while offloading the current high distribution costs to google. 😄 |
Not installs, but symlinks. See above why. Userspace Don't forget that we need to keep $PREFIX structure. Probably won't be easier than current full in-APK variant. |
As in Termux addon apks cannot place executables in com.termux/lib (or whatever that directory is really symlinked to), but can place symlinks in com.termux/lib to those executables in their own separate addon apk's storage, which can then be
Shouldn't be a problem if a symlink invoked in
That all depends on how much packaging and file verification logic in apt/dpkg would need to be duplicated for "full in-APK" installation to work as well. My guess is that this apt/dpkg approach would be a lot less work. |
That's actually how Termux branch Symbolic link is only a pointer and is not subject for SELinux restriction. |
@buttaface I am not sure whether you have already installed this 29 Artifact on your device (preferably with Android>9). If not, I recommend doing this to make the discussion more practical. |
No, I don't have any Android 10 or 11 devices right now, nor do I ever pop into an emulator, but I will be replacing my main Android device within the next couple months and I don't root my devices, so these new Android restrictions will soon affect my use of Termux. |
That's good! The Artifact of the Termux branch |
I'm not sure if this has been mentioned before, but I don't think that the My code:
|
@zacharee Accepted solution is only one that meets following criteria:
Any solution that DO NOT meet these criteria will not be better than sticking to target API 28 and continuing to use |
Using It doesn't help with the Play Store policy violation, but it's another way to execute code with minimal hacks. |
@kdrag0n It is not documented as application data storage at https://developer.android.com/training/data-storage/. Your link is about different things. Finally, it is very likely that
Thanks, but Termux currently has its own solution which takes much less hassle - stay with API 28. Jumping from one hack to another is not a solution for Android 10 execve problem. |
There seems to be an obvious problem for Termux users here- shared directories are difficult, and shared executable directories are impossible except for this one case. This case seems intentional on Google's part. If you look at the folder ownership in /Android/data you see all the bizarre auto-generated user names for every installed package from play store, and you know why your Termux user name is some ugly random characters. The big problem is none of the work in Termux can be exposed to the rest of Android or used or even seen by the operator outside the locked down command line sandbox. I have to copy every file manually from Termux to a shared folder, and the shared folder is then owned by root and is noexec, and when I copy a folder in Termux to shared storage, the ownership and all permissions are wiped out without warning and cannot be reset without copying it back and reconstructing manually, which is rude. It would be nice to run some nicer Android code editor on a source file or script in Termux, and compile and run it in Termux. Currently, impossible except maybe in /Android/com.termux. I can't comment on the security situation, but Termux needs to have working folders owned by Termux, executable in Termux, also visible to other applications (and the system owner). /Android/com.termux could be such a sandbox or dmz. |
There was some talk about trying some alternatives last week by the lead Termux dev on gitter, let us see what he decides to do. There's only so much we can do about new OS restrictions though. |
this is a LONGSHOT... but could it be possible to implement each package as an in-app purchase? (free, obviously) I don't have any real experience implementing IAPs so apologies if this is a completely bogus idea! I am also (blindly) assuming that IAP data can be downloaded remotely. I doubt this will be helpful, but I figure I mine as well mention it (on the small chance it is a "good" idea... =] ) |
Executable code must come within the APK file. Mentioned countless times in this thread, since this is the only way to avoid SELinux issue. |
Sorry... figured that was the case (I almost canceled my post because of that exact thought). I'll leave this thread alone now as I'm sure your incredibly tired of getting alerts from it Lol... |
@xeffyr Can we get exectuable permission in |
I'm pretty sure apps can't write to that anymore. |
@iCodeShit No, apps can't write to Even if it is possible to put files here by regular app, that won't be a proper solution to the problem since this is still W^X violation. We already have chosen in-APK packaging as the most correct solution and some work already done in https://github.com/termux/termux-app/tree/android-10 - it works, but needs some UX-related fixes. Other solutions posted here are either non-viable (like |
I hope I'm not jumping into the koolaid without knowing the flavor, but in case it hasn't been mentioned yet: what's preventing you from just shipping a linker in userspace? You'd put the linker executable in the apk, so it works with api29, and then hijack execve calls to actually load the userspace linker path. Glibc's linker actually supports this directly, for example: zx2c4@thinkpad ~ $ /lib64/ld-linux-x86-64.so.2 /bin/echo hello userspace linker
hello userspace linker
zx2c4@thinkpad ~ $ strace -e execve /lib64/ld-linux-x86-64.so.2 /bin/echo hello userspace linker
execve("/lib64/ld-linux-x86-64.so.2", ["/lib64/ld-linux-x86-64.so.2", "/bin/echo", "hello", "userspace", "linker"], 0x7fff1273cd60 /* 65 vars */) = 0
hello userspace linker
+++ exited with 0 +++
zx2c4@thinkpad ~ $ As you can see, there's only one call to execve, not two. On the other hand, if those selinux rules are actually preventing the creation of executable mappings or something, maybe the problem is trickier than this, hence hundreds of comments above. |
Same case as with proot - W^X violation. Code must be stored within the APK file, so will be managed by Android OS, be read-only and do not conflict with SELinux. Okay, I see no one bother to understand where exactly the problem and more important that solution is already in development - https://github.com/termux/termux-app/tree/android-10. I'm locking this issue permanently now because discussion already went to the dead end. Proper solution must comply with Android OS security features and not attempt to use any holes. |
The ability to run execve() on files within an application's home directory will be removed in target API > 28.
Here is the issue on Google bug tracker:
https://issuetracker.google.com/issues/128554619
As expected it is yet another "working-as-intended", furthermore, as commented in the issue,
This seems to completely break Termux in a long-term, as all its packages contain executables.
The text was updated successfully, but these errors were encountered: