#include <sys/sysmacros.h>
#include <sys/types.h>
-// libmount
-#include <libmount/libmount.h>
-
#include <pakfire/arch.h>
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
+#include <pakfire/parse.h>
#include <pakfire/path.h>
#include <pakfire/mount.h>
#include <pakfire/string.h>
#include <pakfire/util.h>
static const struct pakfire_mountpoint {
+ pakfire_mntns_t ns;
const char* source;
const char* target;
const char* fstype;
const char* options;
} mountpoints[] = {
// Mount a new instance of /proc
- { "pakfire_proc", "proc", "proc",
- MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL, },
+ {
+ PAKFIRE_MNTNS_INNER|PAKFIRE_MNTNS_OUTER,
+ "pakfire_proc",
+ "proc",
+ "proc",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL,
+ },
+
+ /*
+ XXX it is kind of problematic to mount /proc twice as a process inside the
+ jail can umount /proc and will then see the host's /proc.
+ */
// Make /proc/sys read-only (except /proc/sys/net)
- { "/proc/sys", "proc/sys", "bind", MS_BIND|MS_REC, NULL, },
- { "/proc/sys/net", "proc/sys/net", "bind", MS_BIND|MS_REC, NULL, },
- { "/proc/sys", "proc/sys", "bind",
- MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL, },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/sys",
+ "proc/sys",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/sys/net",
+ "proc/sys/net",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/sys",
+ "proc/sys",
+ "bind",
+ MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ NULL,
+ },
// Deny write access to /proc/sysrq-trigger (can be used to restart the host)
- { "/proc/sysrq-trigger", "proc/sysrq-trigger", "bind", MS_BIND|MS_REC, NULL, },
- { "/proc/sysrq-trigger", "proc/sysrq-trigger", "bind",
- MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL, },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/sysrq-trigger",
+ "proc/sysrq-trigger",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/sysrq-trigger",
+ "proc/sysrq-trigger",
+ "bind",
+ MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ NULL,
+ },
// Make /proc/irq read-only
- { "/proc/irq", "proc/irq", "bind", MS_BIND|MS_REC, NULL, },
- { "/proc/irq", "proc/irq", "bind",
- MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL, },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/irq",
+ "proc/irq",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/irq",
+ "proc/irq",
+ "bind",
+ MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ NULL,
+ },
// Make /proc/bus read-only
- { "/proc/bus", "proc/bus", "bind", MS_BIND|MS_REC, NULL, },
- { "/proc/bus", "proc/bus", "bind",
- MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL, },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/bus",
+ "proc/bus",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "/proc/bus",
+ "proc/bus",
+ "bind",
+ MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ NULL,
+ },
// Bind-Mount /sys ready-only
- { "/sys", "sys", "bind", MS_BIND|MS_REC, NULL, },
- { "/sys", "sys", "bind",
- MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL, },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "/sys",
+ "sys",
+ "bind",
+ MS_BIND|MS_REC,
+ NULL,
+ },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "/sys",
+ "sys",
+ "bind",
+ MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ NULL,
+ },
// Create a new /dev
- { "pakfire_dev", "dev", "tmpfs", MS_NOSUID|MS_NOEXEC,
- "mode=0755,size=4m,nr_inodes=64k", },
- { "pakfire_dev_pts", "dev/pts", "devpts", MS_NOSUID|MS_NOEXEC,
- "newinstance,ptmxmode=0666,mode=620", },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "pakfire_dev",
+ "dev",
+ "tmpfs",
+ MS_NOSUID|MS_NOEXEC,
+ "mode=0755,size=4m,nr_inodes=64k",
+ },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "pakfire_dev_pts",
+ "dev/pts",
+ "devpts",
+ MS_NOSUID|MS_NOEXEC,
+ "newinstance,ptmxmode=0666,mode=620",
+ },
// Create a new /dev/shm
- { "pakfire_dev_shm", "dev/shm", "tmpfs",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME, "mode=1777,size=1024m", },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "pakfire_dev_shm",
+ "dev/shm",
+ "tmpfs",
+ MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ "mode=1777,size=1024m",
+ },
// Mount /dev/mqueue
- { "mqueue", "dev/mqueue", "mqueue",
- MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL },
+ {
+ PAKFIRE_MNTNS_INNER,
+ "mqueue",
+ "dev/mqueue",
+ "mqueue",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL,
+ },
// Create a new /run
- { "pakfire_run", "run", "tmpfs", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- "mode=755,size=256m,nr_inodes=1k", },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "pakfire_run",
+ "run",
+ "tmpfs",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ "mode=755,size=256m,nr_inodes=1k",
+ },
// Create a new /tmp
- { "pakfire_tmp", "tmp", "tmpfs",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME, "mode=1777,size=4096m", },
+ {
+ PAKFIRE_MNTNS_OUTER,
+ "pakfire_tmp",
+ "tmp",
+ "tmpfs",
+ MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ "mode=1777,size=4096m",
+ },
// The end
- { NULL },
+ {},
};
static const struct pakfire_devnode {
{ "/dev/urandom", 1, 9, S_IFCHR|S_IRUSR|S_IRGRP|S_IROTH, 0 },
{ "/dev/kmsg", 1, 11, S_IFCHR|S_IRUSR|S_IRGRP|S_IROTH, 0 },
{ "/dev/tty", 5, 0, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0 },
- { "/dev/console", 5, 1, S_IFCHR|S_IRUSR|S_IWUSR, 0 },
{ "/dev/rtc0", 252, 0, S_IFCHR|S_IRUSR|S_IWUSR, 0 },
// Loop Devices
{ NULL },
};
-int pakfire_mount_change_propagation(struct pakfire* pakfire, int propagation, const char* path) {
- DEBUG(pakfire, "Changing mount propagation on %s\n", path);
+int pakfire_mount_change_propagation(struct pakfire_ctx* ctx, const char* path, int propagation) {
+ CTX_DEBUG(ctx, "Changing mount propagation on %s\n", path);
int r = mount(NULL, path, NULL, propagation|MS_REC, NULL);
if (r)
- ERROR(pakfire, "Failed to change mount propagation on %s: %m\n", path);
+ CTX_ERROR(ctx, "Failed to change mount propagation on %s: %m\n", path);
return r;
}
return 1;
}
-int pakfire_mount_make_mounpoint(struct pakfire* pakfire, const char* path) {
+int pakfire_mount_make_mounpoint(struct pakfire_ctx* ctx, struct pakfire* pakfire,
+ const char* path) {
int r;
// Check if path already is a mountpoint
break;
default:
- ERROR(pakfire, "Could not determine whether %s is a mountpoint: %m\n", path);
+ CTX_ERROR(ctx, "Could not determine whether %s is a mountpoint: %m\n", path);
return r;
}
// Bind-mount to self
r = mount(path, path, NULL, MS_BIND|MS_REC, NULL);
if (r) {
- ERROR(pakfire, "Could not make %s a mountpoint: %m\n", path);
+ CTX_ERROR(ctx, "Could not make %s a mountpoint: %m\n", path);
return r;
}
return 0;
}
-/*
- Easy way to iterate through all mountpoints
-*/
-static int pakfire_mount_foreach(struct pakfire* pakfire, int direction,
- int (*callback)(struct pakfire* pakfire, struct libmnt_fs* fs, const void* data),
- const void* data) {
- const char* root = pakfire_get_path(pakfire);
- int r = 0;
-
- struct libmnt_iter* iterator = NULL;
- struct libmnt_table* tab = NULL;
- struct libmnt_fs* fs = NULL;
-
- // Create an iterator
- iterator = mnt_new_iter(direction);
- if (!iterator) {
- ERROR(pakfire, "Could not setup iterator: %m\n");
- goto ERROR;
- }
-
- // Read /proc/mounts
- tab = mnt_new_table_from_file("/proc/mounts");
- if (!tab) {
- ERROR(pakfire, "Could not open /proc/mounts: %m\n");
- goto ERROR;
- }
-
- while (mnt_table_next_fs(tab, iterator, &fs) == 0) {
- const char* target = mnt_fs_get_target(fs);
-
- // Ignore any mointpoints that don't belong to us
- if (!pakfire_string_startswith(target, root))
- continue;
-
- // Call the callback for each relevant mountpoint
- r = callback(pakfire, fs, data);
- if (r)
- break;
- }
-
-ERROR:
- // Tidy up
- if (fs)
- mnt_unref_fs(fs);
- if (tab)
- mnt_unref_table(tab);
- if (iterator)
- mnt_free_iter(iterator);
-
- return r;
-}
-
-static int __pakfire_is_mountpoint(struct pakfire* pakfire,
- struct libmnt_fs* fs, const void* data) {
- const char* path = (const char*)data;
-
- return mnt_fs_streq_target(fs, path);
-}
-
-int pakfire_is_mountpoint(struct pakfire* pakfire, const char* path) {
- return pakfire_mount_foreach(pakfire, MNT_ITER_FORWARD,
- __pakfire_is_mountpoint, path);
-}
-
-static int pakfire_mount(struct pakfire* pakfire, const char* source, const char* target,
- const char* fstype, unsigned long mflags, const void* data) {
+static int pakfire_mount(struct pakfire_ctx* ctx, struct pakfire* pakfire, const char* source,
+ const char* target, const char* fstype, unsigned long mflags, const void* data) {
const char* options = (const char*)data;
// Check for some basic inputs
return 1;
}
- DEBUG(pakfire, "Mounting %s from %s (%s - %s)\n", target, source, fstype, options);
+ CTX_DEBUG(ctx, "Mounting %s from %s (%s - %s)\n", target, source, fstype, options);
// Perform mount()
int r = mount(source, target, fstype, mflags, data);
if (r) {
- ERROR(pakfire, "Could not mount %s: %m\n", target);
+ CTX_ERROR(ctx, "Could not mount %s: %m\n", target);
}
return r;
}
-static int __pakfire_mount_print(struct pakfire* pakfire,
- struct libmnt_fs* fs, const void* data) {
- DEBUG(pakfire,
- " %s %s %s %s\n",
- mnt_fs_get_source(fs),
- mnt_fs_get_target(fs),
- mnt_fs_get_fstype(fs),
- mnt_fs_get_fs_options(fs)
- );
+static int __pakfire_mount_list(char* line, size_t length, void* data) {
+ struct pakfire_ctx* ctx = data;
+
+ // Send the line to the logger
+ CTX_DEBUG(ctx, " %.*s", (int)length, line);
return 0;
}
-int pakfire_mount_list(struct pakfire* pakfire) {
- DEBUG(pakfire, "Mountpoints:\n");
+int pakfire_mount_list(struct pakfire_ctx* ctx) {
+ CTX_DEBUG(ctx, "Mountpoints:\n");
- return pakfire_mount_foreach(pakfire, MNT_ITER_FORWARD,
- __pakfire_mount_print, NULL);
+ return pakfire_parse_file("/proc/self/mounts", __pakfire_mount_list, ctx);
}
-static int pakfire_populate_dev(struct pakfire* pakfire, int flags) {
+int pakfire_populate_dev(struct pakfire_ctx* ctx, struct pakfire* pakfire, int flags) {
char path[PATH_MAX];
// Create device nodes
for (const struct pakfire_devnode* devnode = devnodes; devnode->path; devnode++) {
- DEBUG(pakfire, "Creating device node %s\n", devnode->path);
+ CTX_DEBUG(ctx, "Creating device node %s\n", devnode->path);
// Check if flags match
if (devnode->flags && !(flags & devnode->flags))
goto MOUNT;
// Otherwise log an error and end
- ERROR(pakfire, "Could not create %s: %m\n", devnode->path);
+ CTX_ERROR(ctx, "Could not create %s: %m\n", devnode->path);
return r;
MOUNT:
// Create an empty file
r = pakfire_touch(path, 0444);
if (r) {
- ERROR(pakfire, "Could not create %s: %m\n", path);
+ CTX_ERROR(ctx, "Could not create %s: %m\n", path);
return r;
}
// Create a bind-mount over the file
- r = pakfire_mount(pakfire, devnode->path, path, "bind", MS_BIND, NULL);
+ r = pakfire_mount(ctx, pakfire, devnode->path, path, "bind", MS_BIND, NULL);
if (r)
return r;
}
// Create symlinks
for (const struct pakfire_symlink* s = symlinks; s->target; s++) {
- DEBUG(pakfire, "Creating symlink %s -> %s\n", s->path, s->target);
+ CTX_DEBUG(ctx, "Creating symlink %s -> %s\n", s->path, s->target);
int r = pakfire_path(pakfire, path, "%s", s->path);
if (r)
r = symlink(s->target, path);
if (r) {
- ERROR(pakfire, "Could not create symlink %s: %m\n", s->path);
+ CTX_ERROR(ctx, "Could not create symlink %s: %m\n", s->path);
return r;
}
}
return 0;
}
-static int pakfire_mount_interpreter(struct pakfire* pakfire) {
+int pakfire_mount_interpreter(struct pakfire_ctx* ctx, struct pakfire* pakfire) {
char target[PATH_MAX];
// Fetch the target architecture
if (!interpreter)
return 0;
- DEBUG(pakfire, "Mounting interpreter %s for %s\n", interpreter, arch);
+ CTX_DEBUG(ctx, "Mounting interpreter %s for %s\n", interpreter, arch);
// Where to mount this?
int r = pakfire_path(pakfire, target, "%s", interpreter);
return 1;
fclose(f);
- r = pakfire_mount(pakfire, interpreter, target, NULL, MS_BIND|MS_RDONLY, NULL);
+ r = pakfire_mount(ctx, pakfire, interpreter, target, NULL, MS_BIND|MS_RDONLY, NULL);
if (r)
- ERROR(pakfire, "Could not mount interpreter %s to %s: %m\n", interpreter, target);
+ CTX_ERROR(ctx, "Could not mount interpreter %s to %s: %m\n", interpreter, target);
return r;
}
-int pakfire_mount_all(struct pakfire* pakfire, int flags) {
+int pakfire_mount_all(struct pakfire_ctx* ctx, struct pakfire* pakfire, pakfire_mntns_t ns, int flags) {
char target[PATH_MAX];
int r;
+ const char* root = "/";
+
// Fetch Pakfire's root directory
- const char* root = pakfire_get_path(pakfire);
+ if (ns == PAKFIRE_MNTNS_OUTER)
+ root = pakfire_get_path(pakfire);
for (const struct pakfire_mountpoint* mp = mountpoints; mp->source; mp++) {
+ if (!(mp->ns & ns))
+ continue;
+
// Figure out where to mount
- r = pakfire_path_join(target, root, mp->target);
+ r = pakfire_path_append(target, root, mp->target);
if (r)
return r;
if (!pakfire_path_exists(target)) {
r = pakfire_mkdir(target, 0755);
if (r) {
- ERROR(pakfire, "Could not create %s: %m\n", target);
+ CTX_ERROR(ctx, "Could not create %s: %m\n", target);
return r;
}
}
// Perform mount()
- r = pakfire_mount(pakfire, mp->source, target, mp->fstype, mp->flags, mp->options);
+ r = pakfire_mount(ctx, pakfire, mp->source, target,
+ mp->fstype, mp->flags, mp->options);
if (r)
return r;
}
- // Populate /dev
- r = pakfire_populate_dev(pakfire, flags);
- if (r)
- return r;
-
- // Mount the interpreter (if needed)
- r = pakfire_mount_interpreter(pakfire);
- if (r)
- return r;
-
return 0;
}
-int pakfire_make_ramdisk(struct pakfire* pakfire, char* path, const char* args) {
+int pakfire_make_ramdisk(struct pakfire_ctx* ctx, struct pakfire* pakfire,
+ char* path, const char* args) {
int r;
// Create a new temporary directory
return -errno;
// Mount the ramdisk
- r = pakfire_mount(pakfire, "pakfire_ramdisk", p, "tmpfs", 0, args);
+ r = pakfire_mount(ctx, pakfire, "pakfire_ramdisk", p, "tmpfs", 0, args);
if (r) {
- ERROR_ERRNO(pakfire, r, "Could not mount ramdisk at %s (%s): %m\n", p, args);
+ CTX_ERROR(ctx, "Could not mount ramdisk at %s (%s): %s\n",
+ p, args, strerror(errno));
return r;
}
- DEBUG(pakfire, "Ramdisk mounted at %s (%s)\n", p, args);
+ CTX_DEBUG(ctx, "Ramdisk mounted at %s (%s)\n", p, args);
return 0;
}
-int pakfire_bind(struct pakfire* pakfire, const char* src, const char* dst, int flags) {
+int pakfire_bind(struct pakfire_ctx* ctx, struct pakfire* pakfire,
+ const char* src, const char* dst, int flags) {
struct stat st;
char mountpoint[PATH_MAX];
if (r)
return r;
- DEBUG(pakfire, "Bind-mounting %s to %s\n", src, mountpoint);
+ CTX_DEBUG(ctx, "Bind-mounting %s to %s\n", src, mountpoint);
r = stat(src, &st);
if (r < 0) {
- ERROR(pakfire, "Could not stat %s: %m\n", src);
+ CTX_ERROR(ctx, "Could not stat %s: %m\n", src);
return 1;
}
// as read-only and requires us to mount the source first, and then remount it
// again using MS_RDONLY.
if (flags & MS_RDONLY) {
- r = pakfire_mount(pakfire, src, mountpoint, "bind", MS_BIND|MS_REC, NULL);
+ r = pakfire_mount(ctx, pakfire, src, mountpoint, "bind", MS_BIND|MS_REC, NULL);
if (r)
return r;
}
// Perform mount
- return pakfire_mount(pakfire, src, mountpoint, "bind", flags|MS_BIND|MS_REC, NULL);
+ return pakfire_mount(ctx, pakfire, src, mountpoint, "bind", flags|MS_BIND|MS_REC, NULL);
}