[Toybox] Android API 29 and custom Toybox upgrades
Rob Landley
rob at landley.net
Tue Sep 10 15:45:47 PDT 2019
> On 9/10/19 12:46 PM, Denys Nykula wrote:
> Hi Elliott, maintainers of Android apps with native executables are tweeting to
>> Rob but Android is your area of work so please comment:
>> https://twitter.com/topjohnwu/status/1171308880904646656
When I did https://twitter.com/landley/status/1171354910291628033 it had 38
likes, now it's up to 79. But the guy who forwarded the question here is a
regular, nobody emailed the moderation queue that I can tell...
>>> I'm curious about @landley's (author of toybox) thoughts on the direction
>>> Android is heading. He had mentioned the goal to make Android fully self
>>> hosting, however ever since Android 10 it is not even possible to run
>>> downloaded executables if an app is targeting API 29.
>>>
>>> Magisk Manager is hit by this restriction, and my current workaround is to
>>> simply target API 28. However someday in the future Google *will* eventually
>>> force all apps on Play Store to target 29 or higher, making apps such as
>>> @termux very hard to survive.
>>>
>>> If even harmless apps like @termux that provides an isolated shell and a
>>> package manager aren't allowed, I think it's clear that making Android a self
>>> hosting platform is pretty much a pipe dream at this point.
>>>
>>> P.S. I'm aware of the tool PRoot, however the technique it uses comes with
>>> significant overhead. It is fine in the case of running a few executables as
>>> in Magisk Manager, however I don't think it counts as a feasible solution for
>>> a so-called "self hosting platform".
The embedded Linux community has been doing this at me since the busybox days,
wanting me to ask the kernel guys what they were thinking/smoking rather than
THEM asking directly. Now I'm getting it along a different axis. Wheee!
Done it forever: https://landley.net/notes-2013.html#28-02-2013
Still doing it: https://landley.net/notes-2017.html#13-09-2017
(Open source: where shy people or those who just don't want to deal with a
community's politics or barriers to entry tug the shirt of someone who's
previously dealt with them and asks 'em to pass on a message. There's probably
an anthropology dissertation in that.)
>> What's new in API 29 for user's executables? If I adb shell and wget new builds
>> of Toybox and Dropbear, a) will they run in adb, b) will terminal emulators on
>> phone continue giving access to Android's builtin mksh and toybox and let me
>> run my own builds without root, c) will GNU/overlays such as Termux work that
>> give way to shell-scripting Android APIs for sound playback, camera etc?
_My_ concern is if I make a development container, can the binaries the build
makes run inside that container?
Because that's a pretty common pattern even in dedicated build machines (any
build that has $HOSTCC, like the linux kernel), and running the binaries you
build is pretty much what a development workstation is _for_. (If nothing else,
the test part of the "edit/compile/test" cycle.)
That said, I haven't got the pieces in place yet, and assumed the permissions
would involve a container anyway. (We talked about that in 2016.)
On 9/10/19 2:12 PM, enh via Toybox wrote:
> the official security answer was given on
> https://b.corp.google.com/issues/128554619#comment4
Which is a login screen wanting an @google.com account.
> with the most relevant bits being:
>
> """
> The change to block exec() on application data files for targetAPI >=
> Q is working-as-intended. Please see
> https://android-review.googlesource.com/c/platform/system/sepolicy/+/804149
> for background on this change. Calling exec() on writable application
> files is a W^X (https://en.wikipedia.org/wiki/W%5EX) violation and
> represents an unsafe application practice. Executable code should
> always be loaded from the application APK.
Does chmod -w fix it, or did they basically reinvent mount(MS_NOEXEC) with
selinux rules? Read read... they reinvented MS_NOEXEC with selinux rules.
The above link mentions ways to get around it that could be hooked up to
binfmt_misc as a loader (heck, people could ship qemu and do it that way with
non-native binaries), but I'm still wondering about development containers. Is
there a way for an app to say "I'm going to put executable crap here, I know
it's unsafe" other than sticking to API 28 until you abandon it and then
sticking with old android versions? (Which seems like something to avoid
encouraging. So does "you need to root your phone to do this"...)
What this sounds like is an extra permission a user would have to manually grant
an app (like camera access and local storage access), which would ONLY be
available on a phone that had developer mode enabled (tab under there to enable
the option to give it to apps, maybe even with an "Are you sure, this is virus
city, if this app is not a developer tool the person who wrote it is an idiot"
second prompt...
(The problem with "this is only available via ADB" is that requires a second
machine; my goal is to make standalone self-hosting android workstations someday.)
> While exec() no longer works on files within the application home
> directory, it continues to be supported for files within the read-only
> /data/app directory.
mount -t tmpfs /walrus /home/myapp/thingy as a stopgap, maybe? Then your
potentially compromised executables at least go away when you reboot the phone
(and/or swipe up kill the app if it's in a container).
Hmmm... actually to avoid resource exhaustion, "mount -t tmpfs /run /run" or
similar, then mkdir /run/users/uid if and only if they have the "run stuff"
permission. (That way they all share a tmpfs with a common size= constraint.)
But that still doesn't make the kernel build work because kconfig couldn't run
when you ran "make allnoconfig KCONFIG_ALLCONFIG=mini.conf"... Hmmm.
> In particular, it should be possible to package
> the binaries into your application's native libs directory and enable
> android:extractNativeLibs=true, and then call exec() on the /data/app
> artifacts. A similar approach is done with the wrap.sh functionality,
> documented at https://developer.android.com/ndk/guides/wrap-script#packaging_wrapsh
> .
> """
>
> that link to the specific sepolicy change is worth following for the
> commit message there too.
Still a login screen.
>> If I adb shell and wget new builds
>> of Toybox and Dropbear, a) will they run in adb,
>
> yes. (at least to the extent they have in previous releases.) the
> shell uid and selinux domain are unrelated to app uids and untrusted
> app selinux domains, which is why a lot of toybox commands work via
> `adb shell` but don't if you're doing fork/exec from an app.
wget them to where? It sounds like they won't run out of most writeable space?
(Where is the home directory of adb shell?)
>> c) will GNU/overlays such as Termux work that
>> give way to shell-scripting Android APIs for sound playback, camera etc?
>
> probably not... downloading arbitrary code that you then execute is
> more challenging. (which was the point of the security change.) the
> workaround would be to include everything in your apk. but obviously
> if your goal is to be "basically apt-get" and pull stuff in on demand,
> that's not going to work...
My understanding of the intersection of your needs and the people complaining's
needs is that doing this would A) need the phone to be in developer mode, B)
allowing a specific permission granted to the terminal app similar to
camera/microphone/location/access, C) and _then_ it should probably get a single
writeable+executable directory (which only that UID can write into _and_ only
that UID can run from), D) and even then probably run in some kind of container.
(Although you're already restricting things like network access per app, so
really the top level directory being chmod 007 probably covers it?)
Sigh, the problem with "my executable directory is tmpfs" is you'll run out of
memory doing a kernel build... Well, not necessarily. The symlink trick would
still work just fine. :)
$ mkdir sub
$ sudo mount -t tmpfs sub sub
$ cp -sfR "$PWD"/linux sub
$ cd sub
$ make allnoconfig KCONFIG_ALLCONFIG=~/mkroot/output/x86_64/x86_64.miniconf
$ make -j 4
$ du -s .
115812 .
116 megs is large, but not unusably large on a phone with a gig of ram. (And
yes, this works with every package I tried in LFS and BLFS. I sent patches to
fix the two that wound up installing a symlink to target. :) At least it might
be a decent stopgap until container stuff grows up.
Speaking of which, way back when (2016?) we talked about a container that could
have multiple UIDs in it. (The hard part of which was teaching an app to have
its own UID/GID range instead of its own UID/GID.) Creating a conventional
posix-ish container requires maybe a half-dozen UIDs if android workstations are
to replace/emulate/host conventional-ish Linux userspace someday...
Rob
P.S. Every time somebody says "it's ok, just cross-compile from a big machine
and dial in from that to test it", I think of vax administrators circa 1986 and
their ironclad surety that the PC wasn't a _real_ computer. A billion units/year
means _all_ the R&D money has gone to phone chipsets instead of PC chipsets for
the past decade, and then raspberry pi gets built out of phone hardware the way
"blade servers" were made out of laptop hardware when that got all the R&D money
after 2004, but the _problem_ is even pi sales are measured in low millions, it
took them 5 years to reach 14 million units sold, that's 1/1000th of phone
volume. The open source studies generally say about 2% of your users are
developers (mostly of the drive-by-patch variety, but we all start somewhere),
but that's when all of them have the _opportunity_ to be, without barriers to
entry like "buy dedicated hardware to even try it out"...
More information about the Toybox
mailing list