In a minimal Busybox-based Linux system with access to the root user, how can one launch a process with a specific limited set of Linux capabilities(7) without requiring any tools beyond busybox?
1 Answer
So, up front, this does require some libcap tools built from sources in a non-default way - so I admit it isn't the answer you were hoping for (just busybox)... However, the binaries are small and here is a way to explore:
The libcap distribution has a sub-directory that uses busybox to test against built-from-source kernels. I've used it to triage a few kernel bugs and fixes/features for libcap over the years. You can explore it here:
https://git.kernel.org/pub/scm/libs/libcap/libcap.git/tree/kdebug
One of the things that does is run the quicktest.sh libcap compatibility test suite at start up inside a busybox target. It assumes you have some kernel sources at this relative location kdebug/../../linux/ in order to build the system to test. The basic idea is you untar/git clone the libcap sources and do this:
$ git clone git://git.kernel.org/pub/scm/libs/libcap/libcap.git $ cd libcap/kdebug $ make The first time you try this, it will likely fail to build because it has a whole bunch of dependencies, qemu etc. to launch this busybox target (enumerating those should really be explained in a README). But the binaries once inside the busybox setup are pretty minimal.
If you can get the above to work, with this command line you can also interact with the qemu hosted system after the tests have completed:
$ make shell [exit and Ctrl-d will both exit qemu].
If you are trying to do something subtle, quicktest.sh has a lot of examples demonstrating how to use the custom built ./capsh and ./setcap etc binaries to run things with privilege inside a busbox based system. Built from sources, if you have a static glibc on your host system to link against, capsh and setcap are both fully static binaries.
All that being said, within that system, you can do something like:
# ./capsh --iab="^cap_net_raw" --secbits=15 == --print Current: cap_net_raw=eip Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,cap_perfmon,cap_bpf,cap_checkpoint_restore Ambient set =cap_net_raw Current IAB: ^cap_net_raw Securebits: 017/0xf/4'b1111 (no-new-privs=0) secure-noroot: yes (locked) secure-no-suid-fixup: yes (locked) secure-keep-caps: no (unlocked) secure-no-ambient-raise: no (unlocked) uid=0(root) euid=0(root) gid=0(root) groups=0(root) Guessed mode: UNCERTAIN (0) Which demonstrates how to place limits on root privileges to the single cap_net_raw capability. For whatever task you want to run you have two choices:
- put some file capabilities on a binary and change user (from root) to run it:
# ./setcap cap_net_raw=ep ./yourbinary # ./capsh --user=nobody -- -c "./yourbinary" - or use the above
capshmechanism to droprootprivilege and use ambient capabilities to limit a privilegednobodyuser while running your program:
# ./capsh --user=nobody --iab="^cap_net_raw" -- -c "./yourbinary"
setfattrone of them?