Hi,I've send an updated version of autopkgtest-virt-unshare as a merge request:
https://salsa.debian.org/ci-team/autopkgtest/-/merge_requests/138 Cheers Jochen * Jochen Sprickerhof <jspri...@debian.org> [2022-04-17 22:10]:
Hi, * Martin Pitt <mp...@debian.org> [2016-11-16 13:37]:Johannes Schauer [2016-11-16 1:12 +0100]:in the context of #833407 I told you about my plan of adding a virtualization backend which would allow completely unprivileged chroot operation by using linux user namespaces.Nice!In contrast to what I thought was required back then, I now managed to write that backend using just lxc-usernsexec and lxc-unshare. Thus, I was able to get it to work using the existing Python modules. You can find the script attached. As you can see, it is extremely simple, which I find makes the beauty of it all. All you need is:- the lxc package installed for lxc-usernsexec and lxc-unshareI'd like to eliminate this even. util-linux' unshare has known about --user/-U for a while now, and thus replaces lxc-unshare and lxc-usernsexec: $ unshare -rmU sh -c 'whoami; mount -t tmpfs foo /mnt; touch /mnt/foo; ls -l /mnt/foo' root -rw-r--r-- 1 root root 0 Nov 16 12:59 /mnt/foo And you can use util-linux' nsenter to enter an existing namespace. These lxc-* tools were written before util-linux learned about those, and I'm not sure if they are going to stick around forever as they are basically obsolete. It would also avoid the lxc dependency. Would you be willing to try this?I have implemented this in autopkgtest-virt-unshare (attached). Would be great to get it into the autopkgtest package.$ sbuild --chroot-mode=autopkgtest --autopkgtest-virt-server=uchroot \ --autopkgtest-virt-server-opts="-- /srv/chroot/%r-%a-sbuild.tar.gz /tmp/rootfs" The path /tmp/rootfs is the path that the rootfs will be extracted to and can be at any location that the user has access to.I think it would be more comfortable to use mkdtemp() by default, and provide --unpack-dir as an option?I implemented this as well.It would be great if this backend could be added to autopkgtest itself. If you think that it is not a good fit for autopkgtest, then I can maintain it in a separate package.I think it would be a great fit, but in order to accept it I have some stricter requirements: * tests/autopkgtest should run at least the standard DebTestsVirtContainer tests. Look at classes LxcRunner and LxdRunner, should be a fairly simple extension. This will show the limits of what the backend can do, uncover possible encoding/locale/whatever issues, and ensure that this will keep working over time. * It should get a manpage, probably starting from virt/autopkgtest-virt-chroot.1.I can look into this if you are fine with the script in general.As building such a chroot tarball doesn't require new tools, that should be it (the manpage should just explain how to build them, with sbuild-createchroot or mk-sbuild). I actually have wanted to deprecate the "chroot" backend for a long time, as it's inherently insecure and I never use it myself any more. I wonder if uschroot could completely replace that? At first sight it should have the same isolation and robustness capabilities like lxc/lxd (at least wrt. the file system and mounting), except with a lot fewer dependencies. | tarball = None | rootdir = None | | | def parse_args(): | global tarball, rootdir | | parser = argparse.ArgumentParser() | parser.add_argument('-d', '--debug', action='store_true', | help='Enable debugging output') | parser.add_argument('tarball', help='path to rootfs tarball') | | def hook_open(): | global tarball, rootdir | | # We want to find out our user and group id inside the chroot but we want | # to avoid having to parse /etc/subuid and /etc/subgid. We solve the | # situation by creating a temporary file from inside the user namespace | # and then checking its user and group ids from outside the user namespace. | probe = VirtSubproc.check_exec(['lxc-usernsexec', 'mktemp', | '/tmp/uchroot.XXXXXX'], outp=True) | inner_uid = os.stat(probe)[stat.ST_UID] | inner_gid = os.stat(probe)[stat.ST_GID] | VirtSubproc.check_exec(['lxc-usernsexec', 'rm', probe]) | outer_uid = os.getuid() | outer_gid = os.getgid() This dance wouldn't even be necessary with unshare -rU -- you know that the outside uid/gid is just the normal user, and the inside one is root/root.done.I'm not sure if there is something to be gained from the UID shift -- that isolates the chroot test better, but also makes it much harder to clean up after a failed tests, as your normal user cannot touch/rm the temporary directories? But if you want this, there's newuidmap(1). | # Unpack the tarball into the new directory. | # Make sure not to extract any character special files because we cannot | # mknod. | VirtSubproc.check_exec(['lxc-usernsexec', '--', 'tar', | '--exclude=./dev/urandom', Eek, do chroot tarballs regularly have /dev in them? Might be easier and safer to exclude /dev/ wholesale, as you provide a minimal /dev later on anyway?done.| # A shell script that prepares the environment by bind-mounting all the | # important things. | # The chmod is done such that somebody accidentally using the chroot | # without the right bind-mounts will not fill up their disk. | shellcommand = """ | mkdir -p {rootdir}/dev | touch {rootdir}/dev/null | chmod -rwx {rootdir}/dev/null | mount -o bind /dev/null {rootdir}/dev/null | touch {rootdir}/dev/zero | chmod -rwx {rootdir}/dev/zero | mount -o bind /dev/zero {rootdir}/dev/zero | touch {rootdir}/dev/full | chmod -rwx {rootdir}/dev/full | mount -o bind /dev/full {rootdir}/dev/full | touch {rootdir}/dev/random | chmod -rwx {rootdir}/dev/random | mount -o bind /dev/random {rootdir}/dev/random | touch {rootdir}/dev/urandom | chmod -rwx {rootdir}/dev/urandom | mount -o bind /dev/urandom {rootdir}/dev/urandom | touch {rootdir}/dev/tty | chmod -rwx {rootdir}/dev/tty | mount -o bind /dev/tty {rootdir}/dev/tty Would you mind putting this into a loop?done.| # Test whether the auxverb is able to successfully run /bin/true | status = VirtSubproc.execute_timeout(None, 5, | VirtSubproc.auxverb + ['true'])[0] | if status != 0: | VirtSubproc.bomb('failed to connect to VM') s/connect to VM/enter user chroot/?done.| def hook_capabilities(): | return ['revert', 'root-on-testbed'] Please arrange for downtmp-host= to be set (like in virt-chroot). A shared directory should be fairly simple to do for this runner, and it's much more efficient than squeezing everything through tar and a pipe.done. Cheers Jochen
signature.asc
Description: PGP signature