[Piuparts-devel] [Git][debian/piuparts][helmutg/feature-nonroot] 7 commits: piuparts: reexecute via unshare when run as non-root
Nicolas Dandrimont (@olasd)
gitlab at salsa.debian.org
Thu Nov 14 10:09:11 GMT 2024
Nicolas Dandrimont pushed to branch helmutg/feature-nonroot at Debian / piuparts
Commits:
37eb3270 by Helmut Grohne at 2024-11-14T11:09:01+01:00
piuparts: reexecute via unshare when run as non-root
When piuparts is run as root, it currently errors out and exits. Rather
than doing that, we now try reexecuting it inside an unshared namespace
since we recently made piuparts work when run in an unprivileged user
namespace. This enables running piuparts as non-root out of the box.
- - - - -
c6cbcebc by Helmut Grohne at 2024-11-14T11:09:01+01:00
install piuparts to /usr/bin
Since we can now run piuparts as a regular user, install it in a place
where a user can run it.
- - - - -
6fff741b by Helmut Grohne at 2024-11-14T11:09:01+01:00
suggest installing uidmap
Unprivileged piuparts only works when uidmap is installed.
- - - - -
504c8654 by Helmut Grohne at 2024-11-14T11:09:01+01:00
piuparts.1: document what it takes run piuparts as non-root
Reported-by: Holger Levsen <holger at layer-acht.org>
- - - - -
4dad8cbe by Nicolas Dandrimont at 2024-11-14T11:09:01+01:00
Add autopkgtest for unshared piuparts
- - - - -
1e373449 by Helmut Grohne at 2024-11-14T11:09:01+01:00
attempt to fix unshared piuparts on gitlab runners
We get "Permission denied" while debootstrap tries to mount its proc
filesystem. I guess that we somehow fail the mnt_already_visible test in
fs/namespace.c. If that holds true, mounting an initial proc should
help.
- - - - -
bb303dd7 by Nicolas Dandrimont at 2024-11-14T11:09:01+01:00
skip unshare autopkgtest if --mount-proc is unavailable
The salsaci runners are running on docker, which shadows enough parts of
/proc that unshare is unable to remount it in the new namespace. Skip
the test if that's the case.
- - - - -
14 changed files:
- Makefile
- conf/piuparts-slave.sudoers
- debian/control
- debian/piuparts.install
- debian/piuparts.lintian-overrides
- debian/tests/all-python-versions
- debian/tests/control
- + debian/tests/unshare
- docs/README_pejacevic.txt
- docs/piuparts/piuparts.1.txt
- instances/piuparts.conf-template.pejacevic
- instances/piuparts.conf.anbe
- piuparts.py
- slave-bin/slave_stop.in
Changes:
=====================================
Makefile
=====================================
@@ -1,5 +1,5 @@
prefix = /usr/local
-sbindir = $(prefix)/sbin
+bindir = $(prefix)/bin
sharedir = $(prefix)/share
mandir = $(sharedir)/man
man1dir = $(mandir)/man1
@@ -30,7 +30,7 @@ define placeholder_substitution
-e 's/__PIUPARTS_VERSION__/$(version)/g' \
-e 's%@libdir@%$(libdir)%g' \
-e 's%@sharedir@%$(sharedir)%g' \
- -e 's%@sbindir@%$(sbindir)%g' \
+ -e 's%@bindir@%$(bindir)%g' \
$< > $@
endef
@@ -147,8 +147,8 @@ install-master: build-master-stamp install-common
#install -m 0644 known_problems/*.conf $(DESTDIR)$(etcdir)/piuparts/known_problems/
install-slave: install-common
- install -d $(DESTDIR)$(sbindir)
- install -m 0755 piuparts $(DESTDIR)$(sbindir)/
+ install -d $(DESTDIR)$(bindir)
+ install -m 0755 piuparts $(DESTDIR)$(bindir)/
install -d $(DESTDIR)$(sharedir)/piuparts
install -m 0755 piuparts-slave $(DESTDIR)$(sharedir)/piuparts/
=====================================
conf/piuparts-slave.sudoers
=====================================
@@ -3,7 +3,7 @@
#
# The piuparts slave needs to handle chroots.
-piupartss ALL = NOPASSWD: /usr/sbin/piuparts *, \
+piupartss ALL = NOPASSWD: /usr/bin/piuparts *, \
/bin/umount /srv/piuparts.debian.org/tmp/tmp*, \
/usr/bin/test -f /srv/piuparts.debian.org/tmp/tmp*, \
/usr/bin/rm -rf --one-file-system /srv/piuparts.debian.org/tmp/tmp*
=====================================
debian/control
=====================================
@@ -45,6 +45,7 @@ Recommends:
Suggests:
schroot,
docker.io,
+ uidmap,
Description: .deb package installation, upgrading, and removal testing tool
piuparts tests that .deb packages (as used by Debian) handle
installation, upgrading, and removal correctly. It does this by
=====================================
debian/piuparts.install
=====================================
@@ -1,2 +1,2 @@
-/usr/sbin/piuparts
+/usr/bin/piuparts
/etc/piuparts/scripts*
=====================================
debian/piuparts.lintian-overrides
=====================================
@@ -3,5 +3,5 @@ uses-dpkg-database-directly [etc/piuparts/scripts-debug-purge/post_remove_postrm
uses-dpkg-database-directly [etc/piuparts/scripts-debug-remove/pre_remove_prerm_postrm_set-x]
uses-dpkg-database-directly [etc/piuparts/scripts/post_remove_exceptions]
uses-dpkg-database-directly [etc/piuparts/scripts/pre_remove_40_find_missing_md5sums]
-uses-dpkg-database-directly [usr/sbin/piuparts]
+uses-dpkg-database-directly [usr/bin/piuparts]
debian-news-entry-has-unknown-version 0.45 [usr/share/doc/piuparts/NEWS.Debian.gz:1]
=====================================
debian/tests/all-python-versions
=====================================
@@ -13,7 +13,7 @@ cd "$AUTOPKGTEST_TMP"
create_packages
for pyvers in $(py3versions -vi); do
- test_this "python$pyvers" -X dev /usr/sbin/piuparts t.deb
+ test_this "python$pyvers" -X dev /usr/bin/piuparts t.deb
done
exit 0
=====================================
debian/tests/control
=====================================
@@ -5,3 +5,7 @@ Restrictions: needs-root
Tests: all-python-versions
Depends: piuparts, python3-all, debootstrap
Restrictions: needs-root
+
+Tests: unshare
+Depends: piuparts, uidmap, debootstrap
+Restrictions: needs-root, skippable
=====================================
debian/tests/unshare
=====================================
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+set -eu
+
+if [ -z "$AUTOPKGTEST_NORMAL_USER" ]; then
+ echo "No normal user available, test cannot be run"
+ exit 77
+fi
+
+AUTOPKGTEST_NORMAL_UID="$(id -u "$AUTOPKGTEST_NORMAL_USER")"
+AUTOPKGTEST_NORMAL_GID="$(id -g "$AUTOPKGTEST_NORMAL_USER")"
+
+if ! grep -qx "$AUTOPKGTEST_NORMAL_UID:.*" /etc/subuid; then
+ echo "Adding a subuid allocation for $AUTOPKGTEST_NORMAL_USER"
+ echo "$AUTOPKGTEST_NORMAL_UID:1000000:65536" >> /etc/subuid
+fi
+
+if ! grep -qx "$AUTOPKGTEST_NORMAL_GID:.*" /etc/subgid; then
+ echo "Adding a subgid allocation for $AUTOPKGTEST_NORMAL_USER's group"
+ echo "$AUTOPKGTEST_NORMAL_GID:1000000:65536" >> /etc/subgid
+fi
+
+if ! unshare --user --map-auto --setuid 0 --setgid 0 --mount --pid --fork --mount-proc true; then
+ echo "Unshare failed, bailing"
+ exit 77
+fi
+
+. "$(dirname "$0")/common.sh"
+
+echo running "$0"
+
+test_this piuparts --version
+
+cd "$AUTOPKGTEST_TMP"
+
+create_packages
+
+chown "$AUTOPKGTEST_NORMAL_USER:" t.deb f.deb
+
+test_this runuser -u "$AUTOPKGTEST_NORMAL_USER" -- piuparts t.deb
=====================================
docs/README_pejacevic.txt
=====================================
@@ -103,7 +103,7 @@ This is actually done by DSA:
.. code-block:: text
# The piuparts slave needs to handle chroots.
- piupartss ALL = NOPASSWD: /usr/sbin/piuparts *, \
+ piupartss ALL = NOPASSWD: /usr/bin/piuparts *, \
/bin/umount /srv/piuparts.debian.org/tmp/tmp*, \
/usr/bin/test -f /srv/piuparts.debian.org/tmp/tmp*, \
/usr/bin/rm -rf --one-file-system /srv/piuparts.debian.org/tmp/tmp*
=====================================
docs/piuparts/piuparts.1.txt
=====================================
@@ -33,7 +33,7 @@ When processing changes files, by default, all packages in a changes file will b
:program:`piuparts` outputs to the standard output some log messages to show what is going on. If a log file is used, the messages go there as well.
-:program:`piuparts` needs to be run as root.
+:program:`piuparts` requires root rights to test packages. It does not have to be run in the initial namespace though. When running it as non-root, it'll create a new Linux namespace and rerun itself as root inside said namespace. For this to work, your user needs have an subuid range (which happens by default since a few years) and you need to install the `uidmap` package to provide setuid helpers :program:`newuidmap` and :program:`newgidmap`.
OPTIONS
-------
=====================================
instances/piuparts.conf-template.pejacevic
=====================================
@@ -220,7 +220,7 @@ piuparts-command =
sudo
env PYTHONPATH=%(PYTHONPATH)s
timeout -s INT -k 5m 80m
- /srv/piuparts.debian.org/sbin/piuparts
+ /srv/piuparts.debian.org/bin/piuparts
PYTHONPATH = /srv/piuparts.debian.org/lib/python3/dist-packages
master-directory = /srv/piuparts.debian.org/master
slave-directory = /srv/piuparts.debian.org/slave
=====================================
instances/piuparts.conf.anbe
=====================================
@@ -450,7 +450,7 @@ piuparts-command =
nice
env PYTHONPATH=%(PYTHONPATH)s
timeout -s INT -k 5m 110m
- /srv/piuparts/sbin/piuparts
+ /srv/piuparts/bin/piuparts
PYTHONPATH = /srv/piuparts/lib/python3/dist-packages
master-directory = /srv/piuparts/master
slave-directory = /srv/piuparts/slave
=====================================
piuparts.py
=====================================
@@ -3630,7 +3630,31 @@ def main():
# check if user has root privileges
if os.getuid():
- print("You need to be root to use piuparts.")
+ path_env = os.environ["PATH"].split(":")
+ for d in ("/usr/sbin", "/sbin"):
+ if d not in path_env:
+ path_env.append(d)
+ os.environ["PATH"] = ":".join(path_env)
+ # Make debootstrap (<< 1.0.134) happy when it cannot do mknod.
+ os.environ.setdefault("container", "lxc")
+ logging.info("Running non-root. Reexecuting in a usernamespace.")
+ os.execvp(
+ "unshare",
+ [
+ "unshare",
+ "--user",
+ "--map-auto",
+ "--setuid",
+ "0",
+ "--setgid",
+ "0",
+ "--mount",
+ "--pid",
+ "--fork",
+ "--mount-proc",
+ *sys.argv,
+ ],
+ )
sys.exit(1)
logging.info("-" * 78)
=====================================
slave-bin/slave_stop.in
=====================================
@@ -45,7 +45,7 @@ while pgrep --full '/usr/bin/python3 @sharedir@/piuparts/piuparts-slave' > /dev/
echo -n "$(date -u +%T) - "
pgrep --full '/usr/bin/python3 @sharedir@/piuparts/piuparts-slave' | xargs -r echo -n "slaves running: "
SLEEP=$(( $i * $i ))
- BUSY=$(ps fax | grep -v grep | grep '/usr/bin/python3 @sbindir@/piuparts' | awk '{print $NF}')
+ BUSY=$(ps fax | grep -v grep | grep '/usr/bin/python3 @bindir@/piuparts' | awk '{print $NF}')
if [ -n "$BUSY" ] ; then
# really/meaningful busy
echo
View it on GitLab: https://salsa.debian.org/debian/piuparts/-/compare/2e8af6a885c43f71fb11a3fd182608e750588f3f...bb303dd73aa486473d70341bc1fe2281d2b703d2
--
View it on GitLab: https://salsa.debian.org/debian/piuparts/-/compare/2e8af6a885c43f71fb11a3fd182608e750588f3f...bb303dd73aa486473d70341bc1fe2281d2b703d2
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/piuparts-devel/attachments/20241114/986cb73e/attachment-0001.htm>
More information about the Piuparts-devel
mailing list