fix: drop privileges with a helper of our own, not setpriv
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 1m26s

Ubuntu 18.04 does not ship setpriv. The program exists in util-linux 2.31,
but Debian only began installing it at 2.32, and this image is on bionic
because PyBitmessage is Python 2. The build assertion added in the last
commit caught it, which is what it is for: `/bin/sh: 1: setpriv: not found`,
exit 127, no image pushed.

drop_privs.py does the same work with what the image already has. It sets
no_new_privs, drops the bounding set with PR_CAPBSET_DROP while CAP_SETPCAP
is still held, then optionally becomes the daemon's user. Two shapes, both in
run.sh: keep four capabilities and stay root, for the supervisor; keep none
and become uid 2000, for the daemon and everything run on its behalf.

It is better than setpriv would have been in one respect. The bounding set is
walked up to the kernel's own cap_last_cap instead of a list of names, so a
capability this image has never heard of goes too -- and the "-all" spelling
that bionic's setpriv refuses under a newer kernel is not needed at all.

Verified in a user namespace, in the arrangement run.sh uses: the outer drop
leaves 00000000000001e0, the inner leaves every capability set at zero with
no_new_privs set. The build assertion checks the same two things.
This commit is contained in:
2026-09-09 12:33:18 +00:00
parent c66cea2009
commit 2f1b2afcb4
6 changed files with 186 additions and 61 deletions
+2 -2
View File
@@ -167,8 +167,8 @@ Container images are configured using parameters passed at runtime.
before anything else. The moment that is done the script re-executes itself
with a bounding set of four capabilities -- `SETUID` and `SETGID` to start the
daemon as its own user, `KILL` for the fallback stop, `SETPCAP` to drop the
rest -- and every start of the daemon goes through `setpriv`, at uid 2000,
with all four capability sets empty and `no_new_privs` on. No file in the
rest -- and every start of the daemon goes through `drop_privs.py`, at uid
2000, with all four capability sets empty and `no_new_privs` on. No file in the
image carries a setuid or setgid bit, so a daemon that has been taken over has
nothing left to climb.