Termux-app: Linux capabilities are not effective

Created on 2 Sep 2017  Â·  13Comments  Â·  Source: termux/termux-app

Hi,
I've compiled setcap and getcap for Android and tried to assign cap_net_bind_service capability to sshd, so I can get it running on port 22 instead of 8022.

The capability gets set and hence it should work as I am running kernel that supports capabilities. However after restarting the sshd process it fails to run without any error message - obviously it won't boot because of the port change (I've tried ports 22, 555). It will start just fine when I return to Port 8022 in sshd_config. I also tried this with SELinux in Permissive mode just in case.

__So the setcap and getcap utils are working just fine, but the kernel is ignoring set capabilities.__ Any ideas?

getcap/setcap static compilation
  • you need appropriate hardware/vm
$ wget https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-2.25.tar.gz
$ tar xvfz libcap-2.25.tar.gz
$ cd libcap-2.25
$ sudo apt-get update
$ sudo apt-get install build-essential
$ sed -i.bak "s/DYNAMIC.*/DYNAMIC := no/" Make.Rules
$ make
installation in termux
# setenforce 0

# chmod +x getcap
# chmod +x setcap
$ mv getcap ../usr/bin
$ mv setcap ../usr/bin
applying the cap_net_bind_service capability
# /data/data/com.termux/files/usr/bin/setcap cap_net_bind_service=+ep /data/data/com.termux/files/usr/bin/sshd
$ getcap /data/data/com.termux/files/usr/bin/sshd
/data/data/com.termux/files/usr/bin/sshd = cap_net_bind_service+ep

$ echo Port 22 >> ../usr/etc/ssh/sshd_config
$ sshd

Most helpful comment

I'm closing this as it doesn't seem to be something that the Termux app can solve.

All 13 comments

You didn't mention but ... do you have "root"?

Even on Linux you can only bind to ports # < 1024 if you are root.

@sessyargc yes, the phone is rooted.

@vovcacik I suspect that this is by design.

You are not trying to run those executables in root terminal, are you? Linux capabilities (and suid-bit) do not have effect when interacted with by ordinary Android apps, because Android JVM process (zygote) uses PR_SET_NO_NEW_PRIVS prctl flag to disable them before running any app code (see man prctl). This means, that ordinary processes (such as Termux UID) can not elevate themselves by using execve (neither with suid, nor with file-caps or SELinux file attributes).

This is the same reason, why rooting Android devices has become a lot harder around KitKat — you can no longer use suid su binary to trivially escape sandbox. Modern Android su binaries are actually non-suid client executables, that connect to separate daemon (google for "daemon-su"), running in background since early boot. Soon after system boot most processes castrate themselves with PR_SET_NO_NEW_PRIVS, so they and their children no longer can escalate privileges.

@Alexander-- that sounds very possible. And I am not running the sshd executable as root, instead I am trying to setcap it (which did require root access).

@vovcacik if you already have root, you are better off just starting non-root su shell with Termux UID. This way you will be able to use Termux normally, but without PR_SET_NO_NEW_PRIVS, seccomp and other similar restrictions, — as explained above, su processes are specifically started in way, that escapes those restrictions. You will be able to view full contents of /proc, use strace and take advantage of file capabilities without switching to UID 0.

If you have rooted device, there is no reason not to do so.

@Alexander-- I think I need to clarify.

The phone is rooted and I used su to set capabilities with setcap on sshd executable. And it worked fine. However I am executing the sshd from Termux shell - which as you say is not subject of Android restrictions (e.g. PR_SET_NO_NEW_PRIVS) and thus the set capabilities should have effect, but they don't.

I've used the debug tool capsh and getpcaps to show what is the problem here. I used the standard Termux shell without root.

-bash-4.4$ getcap `which sshd`
/data/data/com.termux/files/usr/bin/sshd = cap_net_bind_service+ep

-bash-4.4$ ./capsh --supports=cap_net_bind_service && echo supported || echo unsupported
supported

-bash-4.4$ sshd
-bash-4.4$ ps
PID   USER     TIME   COMMAND
 6078 u0_a83     0:00 /data/data/com.termux/files/usr/bin/bash -l
12811 u0_a83     0:00 /data/data/com.termux/files/usr/bin/sshd -R
12812 u0_a83     0:00 -bash
12843 u0_a83     0:00 sshd
12851 u0_a83     0:00 ps

-bash-4.4$ ./getpcaps 12843
Capabilities for `12843': =

-bash-4.4$
  • you can see that getcap returns expected capability cap_net_bind_service+ep, so setcap and getcap work fine
  • capsh can test if particular capability is supported, and it reports cap_net_bind_service is supported
  • running sshd from unprivileged shell
  • getpcaps should return capabilities set on a process, but as you can see it is empty
  • note that sshd was configured for port 8022 in this session, if it was set to port 22 it would failed to run

Also

-bash-4.4$ ./capsh --caps=cap_net_bind_service+ep
Unable to set capabilities [--caps=cap_net_bind_service+ep]
  • this works on Debian, but fails on Android (same binaries used!)

@vovcacik I believe, that I understood you perfectly.

As I said, try to use su to switch to Termux user:

  1. Get UID of Termux package:

````

stat /data/data/com.termux/

File: /data/data/com.termux/
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 10300h/66304d Inode: 621526 Links: 5
Access: (0751/drwxr-x--x) Uid: (10146/ u0_a146) Gid: (10146/ u0_a146)
Access: 2017-09-08 17:05:27.000000000
Modify: 2017-09-08 17:10:32.000000000
Change: 2017-09-08 17:10:32.000000000
````

^ Note the value of "Uid" column: 10146

  1. Use su to switch to that UID:

````

su --preserve-environment -cn u:r:untrusted_app:s0 -- 10146

$ id
uid=10146(u0_a146) gid=10146(u0_a146) context=u:r:untrusted_app:s0
````

File capabilities should work in that shell.

This is what I've got:

-bash-4.4$ stat /data/data/com.termux/
  File: /data/data/com.termux/
  Size: 4096            Blocks: 16         IO Block: 4096   directory
Device: b31ch/45852d    Inode: 245769      Links: 6
Access: (0700/drwx------)  Uid: (10083/  u0_a83)   Gid: (10083/  u0_a83)
Access: 2017-07-23 17:09:53.215999793 +0200
Modify: 2017-09-02 14:39:49.684999997 +0200
Change: 2017-09-02 14:39:49.684999997 +0200
 Birth: -

-bash-4.4$ su -cn u:r:untrusted_app:s0 -- 10083

bacon:/data/data/com.termux/files/home $ ../usr/bin/getcap ../usr/bin/sshd
../usr/bin/sshd = cap_net_bind_service+ep

bacon:/data/data/com.termux/files/home $ ./capsh --supports=cap_net_bind_service && echo supported || echo unsupported
supported

bacon:/data/data/com.termux/files/home $ ./capsh --caps=cap_net_bind_service+ep
Unable to set capabilities [--caps=cap_net_bind_service+ep]

bacon:/data/data/com.termux/files/home $ id
uid=10083(u0_a83) gid=10083(u0_a83) groups=10083(u0_a83) context=u:r:supersu:s0
  • I haven't really tried sshd since it reports missing library, but the ./capsh --caps=cap_net_bind_service+ep should be enough to test capabilities

All the binaries I compiled to run capabilities are static. Is it possible linux is missing a library and hence can't detect capabilities set on files?

@vovcacik

Is it possible linux is missing a library and hence can't detect capabilities set on files?

This can not happen, — file capabilities are kernel feature

I haven't really tried sshd since it reports missing library

My bad, I have forgotten, that su resets environment variables. It is likely failing because su has cleared LD_LIBRARY_PATH.

Try to use su --preserve-environment -cn u:r:untrusted_app:s0 -- 10083. Don't bother with capsh, just run the actual binaries with capabilities to test.

I'm closing this as it doesn't seem to be something that the Termux app can solve.

Was this page helpful?
0 / 5 - 0 ratings