X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=fec39d644875e816a11ea1468414dd7638fb47b8;hb=94f7a71442bda7c43191979ea13cc97112745ce4;hp=83bec96cc5cee11c0e732121342c4ef9c8b4583c;hpb=2547bb414c69b7a5b3eb8d7a10768e0cf4114447;p=elogind.git diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 83bec96cc..fec39d644 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -50,6 +50,7 @@ #include "missing.h" #include "cgroup-util.h" #include "strv.h" +#include "path-util.h" #include "loopback-setup.h" static char *arg_directory = NULL; @@ -57,6 +58,7 @@ static char *arg_user = NULL; static char **arg_controllers = NULL; static char *arg_uuid = NULL; static bool arg_private_network = false; +static bool arg_read_only = false; static bool arg_boot = false; static int help(void) { @@ -69,7 +71,8 @@ static int help(void) { " -u --user=USER Run the command under specified user or uid\n" " -C --controllers=LIST Put the container in specified comma-separated cgroup hierarchies\n" " --uuid=UUID Set a specific machine UUID for the container\n" - " --private-network Disable network in container\n", + " --private-network Disable network in container\n" + " --read-only Mount the root directory read-only\n", program_invocation_short_name); return 0; @@ -79,7 +82,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_PRIVATE_NETWORK = 0x100, - ARG_UUID + ARG_UUID, + ARG_READ_ONLY }; static const struct option options[] = { @@ -90,6 +94,7 @@ static int parse_argv(int argc, char *argv[]) { { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, { "boot", no_argument, NULL, 'b' }, { "uuid", required_argument, NULL, ARG_UUID }, + { "read-only", no_argument, NULL, ARG_READ_ONLY }, { NULL, 0, NULL, 0 } }; @@ -148,6 +153,10 @@ static int parse_argv(int argc, char *argv[]) { arg_uuid = optarg; break; + case ARG_READ_ONLY: + arg_read_only = true; + break; + case '?': return -EINVAL; @@ -213,7 +222,7 @@ static int mount_all(const char *dest) { continue; } - mkdir_p(where, 0755); + mkdir_p_label(where, 0755); if (mount(mount_table[k].what, where, @@ -516,7 +525,7 @@ static int setup_hostname(void) { char *hn; int r = 0; - hn = file_name_from_path(arg_directory); + hn = path_get_file_name(arg_directory); if (hn) { hn = strdup(hn); if (!hn) @@ -535,49 +544,31 @@ static int setup_hostname(void) { } static int drop_capabilities(void) { - static const unsigned long retain[] = { - CAP_CHOWN, - CAP_DAC_OVERRIDE, - CAP_DAC_READ_SEARCH, - CAP_FOWNER, - CAP_FSETID, - CAP_IPC_OWNER, - CAP_KILL, - CAP_LEASE, - CAP_LINUX_IMMUTABLE, - CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST, - CAP_NET_RAW, - CAP_SETGID, - CAP_SETFCAP, - CAP_SETPCAP, - CAP_SETUID, - CAP_SYS_ADMIN, - CAP_SYS_CHROOT, - CAP_SYS_NICE, - CAP_SYS_PTRACE, - CAP_SYS_TTY_CONFIG - }; - - unsigned long l; - - for (l = 0; l <= cap_last_cap(); l++) { - unsigned i; - for (i = 0; i < ELEMENTSOF(retain); i++) - if (retain[i] == l) - break; - - if (i < ELEMENTSOF(retain)) - continue; - - if (prctl(PR_CAPBSET_DROP, l) < 0) { - log_error("PR_CAPBSET_DROP failed: %m"); - return -errno; - } - } - - return 0; + static const uint64_t retain = + (1ULL << CAP_CHOWN) | + (1ULL << CAP_DAC_OVERRIDE) | + (1ULL << CAP_DAC_READ_SEARCH) | + (1ULL << CAP_FOWNER) | + (1ULL << CAP_FSETID) | + (1ULL << CAP_IPC_OWNER) | + (1ULL << CAP_KILL) | + (1ULL << CAP_LEASE) | + (1ULL << CAP_LINUX_IMMUTABLE) | + (1ULL << CAP_NET_BIND_SERVICE) | + (1ULL << CAP_NET_BROADCAST) | + (1ULL << CAP_NET_RAW) | + (1ULL << CAP_SETGID) | + (1ULL << CAP_SETFCAP) | + (1ULL << CAP_SETPCAP) | + (1ULL << CAP_SETUID) | + (1ULL << CAP_SYS_ADMIN) | + (1ULL << CAP_SYS_CHROOT) | + (1ULL << CAP_SYS_NICE) | + (1ULL << CAP_SYS_PTRACE) | + (1ULL << CAP_SYS_TTY_CONFIG); + + return capability_bounding_set_drop(~retain, false); } static int is_os_tree(const char *path) { @@ -971,6 +962,18 @@ int main(int argc, char *argv[]) { if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) goto child_fail; + /* Turn directory into bind mount */ + if (mount(arg_directory, arg_directory, "bind", MS_BIND, NULL) < 0) { + log_error("Failed to make bind mount."); + goto child_fail; + } + + if (arg_read_only) + if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) { + log_error("Failed to make read-only."); + goto child_fail; + } + if (mount_all(arg_directory) < 0) goto child_fail; @@ -1001,8 +1004,8 @@ int main(int argc, char *argv[]) { dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) goto child_fail; - if (mount(arg_directory, "/", "bind", MS_BIND, NULL) < 0) { - log_error("mount(MS_MOVE) failed: %m"); + if (mount(arg_directory, "/", "bind", MS_MOVE, NULL) < 0) { + log_error("mount(MS_BIND) failed: %m"); goto child_fail; } @@ -1020,8 +1023,10 @@ int main(int argc, char *argv[]) { loopback_setup(); - if (drop_capabilities() < 0) + if (drop_capabilities() < 0) { + log_error("drop_capabilities() failed: %m"); goto child_fail; + } if (arg_user) { @@ -1030,13 +1035,13 @@ int main(int argc, char *argv[]) { goto child_fail; } - if (mkdir_parents(home, 0775) < 0) { - log_error("mkdir_parents() failed: %m"); + if (mkdir_parents_label(home, 0775) < 0) { + log_error("mkdir_parents_label() failed: %m"); goto child_fail; } - if (safe_mkdir(home, 0775, uid, gid) < 0) { - log_error("safe_mkdir() failed: %m"); + if (mkdir_safe_label(home, 0775, uid, gid) < 0) { + log_error("mkdir_safe_label() failed: %m"); goto child_fail; }