xbps-uchroot: replace -D/-H/-S with -b src/dest and switch to getopt(3).

This commit is contained in:
Juan RP 2015-05-06 11:24:47 +02:00
parent e9b8ff7360
commit 7d6d1805f3
3 changed files with 96 additions and 75 deletions

3
NEWS
View File

@ -1,5 +1,8 @@
xbps-0.45 (???): xbps-0.45 (???):
* xbps-uchroot(8): replaced -D, -H and -S with -b src:dest. This bind mounts
src into dir/dest and allows unlimited mounts.
* configure: added --dbdir to customize path to pkgdb. * configure: added --dbdir to customize path to pkgdb.
* xbps-uchroot(8): added -o option to pass arguments to the tmpfs mount, * xbps-uchroot(8): added -o option to pass arguments to the tmpfs mount,

View File

@ -27,7 +27,6 @@
* This is based on linux-user-chroot by Colin Walters, but has been adapted * This is based on linux-user-chroot by Colin Walters, but has been adapted
* specifically for xbps-src use: * specifically for xbps-src use:
* *
* - This bind mounts exactly what we need, no support for additional mounts.
* - This uses IPC/PID/UTS namespaces, nothing more. * - This uses IPC/PID/UTS namespaces, nothing more.
* - Disables namespace features if running in OpenVZ containers. * - Disables namespace features if running in OpenVZ containers.
* - Supports overlayfs on a temporary directory or a tmpfs mount. * - Supports overlayfs on a temporary directory or a tmpfs mount.
@ -53,6 +52,7 @@
#include <ftw.h> #include <ftw.h>
#include <xbps.h> #include <xbps.h>
#include "queue.h"
#ifndef SECBIT_NOROOT #ifndef SECBIT_NOROOT
#define SECBIT_NOROOT (1 << 0) #define SECBIT_NOROOT (1 << 0)
@ -70,8 +70,27 @@
#pragma clang diagnostic ignored "-Wformat-nonliteral" #pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif #endif
struct bindmnt {
SIMPLEQ_ENTRY(bindmnt) entries;
char *src;
const char *dest;
};
static char *tmpdir; static char *tmpdir;
static bool overlayfs_on_tmpfs; static bool overlayfs_on_tmpfs;
static SIMPLEQ_HEAD(bindmnt_head, bindmnt) bindmnt_queue =
SIMPLEQ_HEAD_INITIALIZER(bindmnt_queue);
static void __attribute__((noreturn))
usage(const char *p)
{
printf("Usage: %s [-b src:dest] [-O -t -o <opts>] <dir> <cmd> [<cmdargs>]\n\n"
"-b src:dest Bind mounts <src> into <dir>/<dest> (may be specified multiple times)\n"
"-O Creates a tempdir and mounts <dir> read-only via overlayfs\n"
"-t Creates tempdir and mounts it on tmpfs (for use with -O)\n"
"-o opts Options to be passed to the tmpfs mount (for use with -t)\n", p);
exit(EXIT_FAILURE);
}
static void __attribute__((noreturn)) static void __attribute__((noreturn))
die(const char *fmt, ...) die(const char *fmt, ...)
@ -80,7 +99,7 @@ die(const char *fmt, ...)
int save_errno = errno; int save_errno = errno;
va_start(ap, fmt); va_start(ap, fmt);
fprintf(stderr, "ERROR "); fprintf(stderr, "ERROR: ");
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
fprintf(stderr, " (%s)\n", strerror(save_errno)); fprintf(stderr, " (%s)\n", strerror(save_errno));
va_end(ap); va_end(ap);
@ -125,14 +144,30 @@ cleanup_overlayfs(void)
rmdir(tmpdir); rmdir(tmpdir);
} }
static void __attribute__((noreturn)) static void
usage(const char *p) add_bindmount(char *bm)
{ {
printf("Usage: %s [-D dir] [-H dir] [-S dir] [-O -t -o <opts>] <chrootdir> <command>\n\n" struct bindmnt *bmnt;
"-D <distdir> Directory to be bind mounted at <chrootdir>/void-packages\n" char *b, *src, *dest;
"-H <hostdir> Directory to be bind mounted at <chrootdir>/host\n" size_t len;
"-S <shmdir> Directory to be bind mounted at <chrootdir>/<shmdir>\n", p);
exit(EXIT_FAILURE); src = strdup(bm);
dest = strchr(bm, ':');
if (dest == NULL || *dest == '\0') {
errno = EINVAL;
die("invalid argument for bindmount: %s", bm);
}
dest++;
b = strchr(bm, ':');
len = strlen(bm) - strlen(b);
src[len] = '\0';
bmnt = malloc(sizeof(struct bindmnt));
assert(bmnt);
bmnt->src = src;
bmnt->dest = dest;
SIMPLEQ_INSERT_TAIL(&bindmnt_queue, bmnt, entries);
} }
static int static int
@ -227,55 +262,48 @@ main(int argc, char **argv)
{ {
uid_t ruid, euid, suid; uid_t ruid, euid, suid;
gid_t rgid, egid, sgid; gid_t rgid, egid, sgid;
const char *chrootdir, *distdir, *hostdir, *shmdir, *tmpfs_opts, *cmd, *argv0; const char *chrootdir, *tmpfs_opts, *cmd, *argv0;
char **cmdargs, *b, mountdir[PATH_MAX-1]; char **cmdargs, *b, mountdir[PATH_MAX-1];
int aidx = 0, clone_flags, child_status = 0; int c, clone_flags, child_status = 0;
pid_t child; pid_t child;
bool overlayfs = false; bool overlayfs = false;
tmpfs_opts = chrootdir = distdir = hostdir = shmdir = cmd = NULL; tmpfs_opts = chrootdir = cmd = NULL;
argv0 = argv[0]; argv0 = argv[0];
argc--;
argv++; while ((c = getopt(argc, argv, "Oto:b:V")) != -1) {
switch (c) {
case 'O':
overlayfs = true;
break;
case 't':
overlayfs_on_tmpfs = true;
break;
case 'o':
tmpfs_opts = optarg;
break;
case 'b':
if (optarg == NULL || *optarg == '\0')
break;
add_bindmount(optarg);
break;
case 'V':
printf("%s\n", XBPS_RELVER);
exit(EXIT_SUCCESS);
case '?':
default:
usage(argv0);
}
}
argc -= optind;
argv += optind;
if (argc < 2) if (argc < 2)
usage(argv0); usage(argv0);
while (aidx < argc) { chrootdir = argv[0];
if (strcmp(argv[aidx], "-O") == 0) { cmd = argv[1];
/* use overlayfs */ cmdargs = argv + 1;
overlayfs = true;
aidx++;
} else if (strcmp(argv[aidx], "-t") == 0) {
/* overlayfs on tmpfs */
overlayfs_on_tmpfs = true;
aidx++;
} else if (strcmp(argv[aidx], "-o") == 0) {
/* tmpfs args with overlayfs */
tmpfs_opts = argv[aidx+1];
aidx += 2;
} else if (strcmp(argv[aidx], "-D") == 0) {
/* distdir */
distdir = argv[aidx+1];
aidx += 2;
} else if (strcmp(argv[aidx], "-H") == 0) {
/* hostdir */
hostdir = argv[aidx+1];
aidx += 2;
} else if (strcmp(argv[aidx], "-S") == 0) {
/* shmdir */
shmdir = argv[aidx+1];
aidx += 2;
} else {
break;
}
}
if ((argc - aidx) < 2)
usage(argv0);
chrootdir = argv[aidx];
cmd = argv[aidx+1];
cmdargs = argv + aidx + 1;
/* Never allow chrootdir == / */ /* Never allow chrootdir == / */
if (strcmp(chrootdir, "/") == 0) if (strcmp(chrootdir, "/") == 0)
@ -312,6 +340,7 @@ main(int argc, char **argv)
die("clone"); die("clone");
if (child == 0) { if (child == 0) {
struct bindmnt *bmnt;
/* /*
* Restrict privileges on the child. * Restrict privileges on the child.
*/ */
@ -339,17 +368,9 @@ main(int argc, char **argv)
/* bind mount /dev */ /* bind mount /dev */
bindmount(ruid, chrootdir, "/dev", NULL); bindmount(ruid, chrootdir, "/dev", NULL);
/* bind mount hostdir if set */ /* bind mount all user specified mnts */
if (hostdir) SIMPLEQ_FOREACH(bmnt, &bindmnt_queue, entries)
bindmount(ruid, chrootdir, hostdir, "/host"); bindmount(ruid, chrootdir, bmnt->src, bmnt->dest);
/* bind mount distdir (if set) */
if (distdir)
bindmount(ruid, chrootdir, distdir, "/void-packages");
/* bind mount shmdir (if set) */
if (shmdir)
bindmount(ruid, chrootdir, shmdir, NULL);
/* move chrootdir to / and chroot to it */ /* move chrootdir to / and chroot to it */
if (fsuid_chdir(ruid, chrootdir) == -1) if (fsuid_chdir(ruid, chrootdir) == -1)

View File

@ -1,4 +1,4 @@
.Dd April 27, 2014 .Dd May 6, 2014
.Dt XBPS-UCHROOT 8 .Dt XBPS-UCHROOT 8
.Sh NAME .Sh NAME
.Nm xbps-uchroot .Nm xbps-uchroot
@ -24,20 +24,17 @@ the calling process. If running in a OpenVZ container, these namespace features
are simply disabled. are simply disabled.
.Sh OPTIONS .Sh OPTIONS
.Bl -tag -width -x .Bl -tag -width -x
.It Fl D Ar dir .It Fl b Ar src:dest
Specifies a full path to a directory that will be bind mounted at Bind mounts
.Ar CHROOTDIR/void-packages . .Ar src
.It Fl H Ar dir into
Specifies a full path to a directory that will be bind mounted at .Ar CHROOTDIR/dest .
.Ar CHROOTDIR/host . This option may be specified multiple times.
.It Fl S Ar dir Please note that both
Specifies a full path to a directory to allow shm functionality to be used .Ar src
in the target and
.Ar CHROOTDIR/dir . .Ar dest
If your system uses must be absolute paths and must exist.
.Sy /dev/shm
use it, otherwise use
.Sy /run/shm .
.It Fl O .It Fl O
Setups a temporary directory and then creates an overlay layer (via overlayfs) Setups a temporary directory and then creates an overlay layer (via overlayfs)
with the lowerdir set to CHROOTDIR. Useful to create a temporary tree that does not with the lowerdir set to CHROOTDIR. Useful to create a temporary tree that does not