From ec50c1346d6581ad1824a161d6f7563e0295a7c3 Mon Sep 17 00:00:00 2001 From: Robert Swiecki Date: Sat, 27 May 2017 15:17:11 +0200 Subject: [PATCH] mount: nonmandatory mounts --- cmdline.c | 22 +++++++----- common.h | 1 + config.c | 4 +-- config.pb-c.c | 80 +++++++++++++++++++++++++++++------------ config.pb-c.h | 7 +++- config.proto | 8 +++-- configs/config1.example | 20 +++++++++-- mount.c | 17 +++++---- 8 files changed, 114 insertions(+), 45 deletions(-) diff --git a/cmdline.c b/cmdline.c index 85bca46..0b6bbaa 100644 --- a/cmdline.c +++ b/cmdline.c @@ -226,10 +226,10 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf) struct mounts_t *p; TAILQ_FOREACH(p, &nsjconf->mountpts, pointers) { LOG_I - ("Mount point: src:'%s' dst:'%s' type:'%s' flags:%s options:'%s' isDir:%s", + ("Mount point: src:'%s' dst:'%s' type:'%s' flags:%s options:'%s' isDir:%s mandatory:%s", p->src ? p->src : "[NULL]", p->dst, p->fs_type ? p->fs_type : "[NULL]", mountFlagsToStr(p->flags), p->options ? p->options : "[NULL]", - p->isDir ? "True" : "False"); + p->isDir ? "true" : "false", p->mandatory ? "true" : "false"); } } { @@ -644,6 +644,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) p->options = ""; p->fs_type = ""; p->isDir = mountIsDir(optarg); + p->mandatory = true; TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); } break; case 'B':{ @@ -654,6 +655,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) p->options = ""; p->fs_type = ""; p->isDir = mountIsDir(optarg); + p->mandatory = true; TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); } break; case 'T':{ @@ -664,6 +666,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) p->options = cmdlineTmpfsSz; p->fs_type = "tmpfs"; p->isDir = true; + p->mandatory = true; TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); } break; case 'M': @@ -749,6 +752,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) p->options = ""; p->fs_type = "proc"; p->isDir = true; + p->mandatory = true; TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers); } if (nsjconf->chroot != NULL) { @@ -756,24 +760,26 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) p->src = nsjconf->chroot; p->dst = "/"; p->flags = MS_BIND | MS_REC; - p->options = ""; - p->fs_type = ""; - p->isDir = true; if (nsjconf->is_root_rw == false) { p->flags |= MS_RDONLY; } + p->options = ""; + p->fs_type = ""; + p->isDir = true; + p->mandatory = true; TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers); } else { struct mounts_t *p = utilMalloc(sizeof(struct mounts_t)); p->src = NULL; p->dst = "/"; p->flags = 0; - p->options = ""; - p->fs_type = "tmpfs"; - p->isDir = true; if (nsjconf->is_root_rw == false) { p->flags |= MS_RDONLY; } + p->options = ""; + p->fs_type = "tmpfs"; + p->isDir = true; + p->mandatory = true; TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers); } diff --git a/common.h b/common.h index 3ab86ed..6fb1ab2 100644 --- a/common.h +++ b/common.h @@ -71,6 +71,7 @@ struct mounts_t { const char *options; uintptr_t flags; bool isDir; + bool mandatory; TAILQ_ENTRY(mounts_t) pointers; }; diff --git a/config.c b/config.c index c6932be..ea8cd6f 100644 --- a/config.c +++ b/config.c @@ -181,6 +181,7 @@ static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig } } + nsjconf->mount_proc = njc->mount_proc; for (size_t i = 0; i < njc->n_mount; i++) { struct mounts_t *p = utilCalloc(sizeof(struct mounts_t)); p->src = utilStrDup(njc->mount[i]->src); @@ -200,11 +201,10 @@ static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig p->isDir = true; } } + p->mandatory = njc->mount[i]->mandatory; TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); } - nsjconf->mount_proc = njc->mount_proc; - if (njc->seccomp_policy_file) { if ((nsjconf->kafel_file = fopen(njc->seccomp_policy_file, "rb")) == NULL) { PLOG_W("Couldn't open file with seccomp policy '%s'", diff --git a/config.pb-c.c b/config.pb-c.c index 26fba15..2fe2fe6 100644 --- a/config.pb-c.c +++ b/config.pb-c.c @@ -7,22 +7,26 @@ #endif #include "config.pb-c.h" -void nsjail__id_map__init(Nsjail__IdMap * message) { +void nsjail__id_map__init(Nsjail__IdMap * message) +{ static Nsjail__IdMap init_value = NSJAIL__ID_MAP__INIT; *message = init_value; } -size_t nsjail__id_map__get_packed_size(const Nsjail__IdMap * message) { +size_t nsjail__id_map__get_packed_size(const Nsjail__IdMap * message) +{ assert(message->base.descriptor == &nsjail__id_map__descriptor); return protobuf_c_message_get_packed_size((const ProtobufCMessage *)(message)); } -size_t nsjail__id_map__pack(const Nsjail__IdMap * message, uint8_t * out) { +size_t nsjail__id_map__pack(const Nsjail__IdMap * message, uint8_t * out) +{ assert(message->base.descriptor == &nsjail__id_map__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *)message, out); } -size_t nsjail__id_map__pack_to_buffer(const Nsjail__IdMap * message, ProtobufCBuffer * buffer) { +size_t nsjail__id_map__pack_to_buffer(const Nsjail__IdMap * message, ProtobufCBuffer * buffer) +{ assert(message->base.descriptor == &nsjail__id_map__descriptor); return protobuf_c_message_pack_to_buffer((const ProtobufCMessage *)message, buffer); } @@ -33,27 +37,32 @@ Nsjail__IdMap *nsjail__id_map__unpack protobuf_c_message_unpack(&nsjail__id_map__descriptor, allocator, len, data); } -void nsjail__id_map__free_unpacked(Nsjail__IdMap * message, ProtobufCAllocator * allocator) { +void nsjail__id_map__free_unpacked(Nsjail__IdMap * message, ProtobufCAllocator * allocator) +{ assert(message->base.descriptor == &nsjail__id_map__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } -void nsjail__mount_pt__init(Nsjail__MountPt * message) { +void nsjail__mount_pt__init(Nsjail__MountPt * message) +{ static Nsjail__MountPt init_value = NSJAIL__MOUNT_PT__INIT; *message = init_value; } -size_t nsjail__mount_pt__get_packed_size(const Nsjail__MountPt * message) { +size_t nsjail__mount_pt__get_packed_size(const Nsjail__MountPt * message) +{ assert(message->base.descriptor == &nsjail__mount_pt__descriptor); return protobuf_c_message_get_packed_size((const ProtobufCMessage *)(message)); } -size_t nsjail__mount_pt__pack(const Nsjail__MountPt * message, uint8_t * out) { +size_t nsjail__mount_pt__pack(const Nsjail__MountPt * message, uint8_t * out) +{ assert(message->base.descriptor == &nsjail__mount_pt__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *)message, out); } -size_t nsjail__mount_pt__pack_to_buffer(const Nsjail__MountPt * message, ProtobufCBuffer * buffer) { +size_t nsjail__mount_pt__pack_to_buffer(const Nsjail__MountPt * message, ProtobufCBuffer * buffer) +{ assert(message->base.descriptor == &nsjail__mount_pt__descriptor); return protobuf_c_message_pack_to_buffer((const ProtobufCMessage *)message, buffer); } @@ -64,52 +73,62 @@ Nsjail__MountPt *nsjail__mount_pt__unpack protobuf_c_message_unpack(&nsjail__mount_pt__descriptor, allocator, len, data); } -void nsjail__mount_pt__free_unpacked(Nsjail__MountPt * message, ProtobufCAllocator * allocator) { +void nsjail__mount_pt__free_unpacked(Nsjail__MountPt * message, ProtobufCAllocator * allocator) +{ assert(message->base.descriptor == &nsjail__mount_pt__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } -void nsjail__exe__init(Nsjail__Exe * message) { +void nsjail__exe__init(Nsjail__Exe * message) +{ static Nsjail__Exe init_value = NSJAIL__EXE__INIT; *message = init_value; } -size_t nsjail__exe__get_packed_size(const Nsjail__Exe * message) { +size_t nsjail__exe__get_packed_size(const Nsjail__Exe * message) +{ assert(message->base.descriptor == &nsjail__exe__descriptor); return protobuf_c_message_get_packed_size((const ProtobufCMessage *)(message)); } -size_t nsjail__exe__pack(const Nsjail__Exe * message, uint8_t * out) { +size_t nsjail__exe__pack(const Nsjail__Exe * message, uint8_t * out) +{ assert(message->base.descriptor == &nsjail__exe__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *)message, out); } -size_t nsjail__exe__pack_to_buffer(const Nsjail__Exe * message, ProtobufCBuffer * buffer) { +size_t nsjail__exe__pack_to_buffer(const Nsjail__Exe * message, ProtobufCBuffer * buffer) +{ assert(message->base.descriptor == &nsjail__exe__descriptor); return protobuf_c_message_pack_to_buffer((const ProtobufCMessage *)message, buffer); } -Nsjail__Exe *nsjail__exe__unpack(ProtobufCAllocator * allocator, size_t len, const uint8_t * data) { +Nsjail__Exe *nsjail__exe__unpack(ProtobufCAllocator * allocator, size_t len, const uint8_t * data) +{ return (Nsjail__Exe *) protobuf_c_message_unpack(&nsjail__exe__descriptor, allocator, len, data); } -void nsjail__exe__free_unpacked(Nsjail__Exe * message, ProtobufCAllocator * allocator) { +void nsjail__exe__free_unpacked(Nsjail__Exe * message, ProtobufCAllocator * allocator) +{ assert(message->base.descriptor == &nsjail__exe__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } -void nsjail__ns_jail_config__init(Nsjail__NsJailConfig * message) { +void nsjail__ns_jail_config__init(Nsjail__NsJailConfig * message) +{ static Nsjail__NsJailConfig init_value = NSJAIL__NS_JAIL_CONFIG__INIT; *message = init_value; } -size_t nsjail__ns_jail_config__get_packed_size(const Nsjail__NsJailConfig * message) { +size_t nsjail__ns_jail_config__get_packed_size(const Nsjail__NsJailConfig * message) +{ assert(message->base.descriptor == &nsjail__ns_jail_config__descriptor); return protobuf_c_message_get_packed_size((const ProtobufCMessage *)(message)); } -size_t nsjail__ns_jail_config__pack(const Nsjail__NsJailConfig * message, uint8_t * out) { +size_t nsjail__ns_jail_config__pack(const Nsjail__NsJailConfig * message, uint8_t * out) +{ assert(message->base.descriptor == &nsjail__ns_jail_config__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *)message, out); } @@ -214,10 +233,12 @@ const ProtobufCMessageDescriptor nsjail__id_map__descriptor = { NULL, NULL, NULL /* reserved[123] */ }; +char nsjail__mount_pt__fstype__default_value[] = ""; char nsjail__mount_pt__options__default_value[] = ""; static const protobuf_c_boolean nsjail__mount_pt__is_bind__default_value = 0; static const protobuf_c_boolean nsjail__mount_pt__is_ro__default_value = 0; -static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[7] = { +static const protobuf_c_boolean nsjail__mount_pt__mandatory__default_value = 1; +static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { { "src", 1, @@ -250,7 +271,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[7] = { 0, /* quantifier_offset */ offsetof(Nsjail__MountPt, fstype), NULL, - NULL, + &nsjail__mount_pt__fstype__default_value, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, @@ -302,6 +323,18 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[7] = { 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, + { + "mandatory", + 8, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(Nsjail__MountPt, mandatory), + NULL, + &nsjail__mount_pt__mandatory__default_value, + 0, /* flags */ + 0, NULL, NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned nsjail__mount_pt__field_indices_by_name[] = { @@ -310,13 +343,14 @@ static const unsigned nsjail__mount_pt__field_indices_by_name[] = { 4, /* field[4] = is_bind */ 6, /* field[6] = is_dir */ 5, /* field[5] = is_ro */ + 7, /* field[7] = mandatory */ 3, /* field[3] = options */ 0, /* field[0] = src */ }; static const ProtobufCIntRange nsjail__mount_pt__number_ranges[1 + 1] = { {1, 0}, - {0, 7} + {0, 8} }; const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = { @@ -326,7 +360,7 @@ const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = { "Nsjail__MountPt", "nsjail", sizeof(Nsjail__MountPt), - 7, + 8, nsjail__mount_pt__field_descriptors, nsjail__mount_pt__field_indices_by_name, 1, nsjail__mount_pt__number_ranges, diff --git a/config.pb-c.h b/config.pb-c.h index 302aa38..35a549e 100644 --- a/config.pb-c.h +++ b/config.pb-c.h @@ -101,11 +101,16 @@ struct _Nsjail__MountPt { */ protobuf_c_boolean has_is_dir; protobuf_c_boolean is_dir; + /* + * Should the sandboxing fail if we cannot mount this resource? + */ + protobuf_c_boolean mandatory; }; +extern char nsjail__mount_pt__fstype__default_value[]; extern char nsjail__mount_pt__options__default_value[]; #define NSJAIL__MOUNT_PT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&nsjail__mount_pt__descriptor) \ - , NULL, NULL, NULL, nsjail__mount_pt__options__default_value, 0, 0, 0,0 } + , NULL, NULL, nsjail__mount_pt__fstype__default_value, nsjail__mount_pt__options__default_value, 0, 0, 0,0, 1 } struct _Nsjail__Exe { ProtobufCMessage base; diff --git a/config.proto b/config.proto index 6f92867..53d6a89 100644 --- a/config.proto +++ b/config.proto @@ -41,6 +41,8 @@ message MountPt /* Is it directory? If not specified an internal * heuristics will be used to determine that */ optional bool is_dir = 7; + /* Should the sandboxing fail if we cannot mount this resource? */ + required bool mandatory = 8 [default = true]; } message Exe { @@ -132,11 +134,11 @@ message NsJailConfig repeated IdMap uidmap = 41; repeated IdMap gidmap = 42; + /* Should /proc be mounted? One can also force this in the 'mount' */ + required bool mount_proc = 43 [ default = true ]; /* Mount points inside the jail. See the description for 'msg MountPt' for more */ - repeated MountPt mount = 43; - /* Should /proc be mounted? One can also force this in the 'mount' */ - required bool mount_proc = 44 [ default = true ]; + repeated MountPt mount = 44; /* Kafel seccomp policy file or string. Homepage of the project: https://github.com/google/kafel */ diff --git a/configs/config1.example b/configs/config1.example index 096b29b..5077ddb 100644 --- a/configs/config1.example +++ b/configs/config1.example @@ -25,7 +25,7 @@ rlimit_as: 128 rlimit_core: 0 rlimit_cpu: 10 rlimit_fsize: 0 -rlimit_nofile: 5 +rlimit_nofile: 32 rlimit_stack: 1 persona_addr_compat_layout: false @@ -54,6 +54,8 @@ gidmap { count: 1 } +mount_proc: false + mount { src: "/lib" dst: "/lib" @@ -94,6 +96,15 @@ mount { dst: "/lib64" is_bind: true is_ro: true + mandatory: false +} + +mount { + src: "/lib32" + dst: "/lib32" + is_bind: true + is_ro: true + mandatory: false } mount { @@ -124,7 +135,12 @@ mount { is_ro: true } -mount_proc: false +mount { + src: "/nonexistent_777" + dst: "/nonexistent_777" + is_bind: true + mandatory: false +} seccomp_string: " POLICY example { diff --git a/mount.c b/mount.c index 2fe5891..6421fdb 100644 --- a/mount.c +++ b/mount.c @@ -159,13 +159,16 @@ static bool mountMount(struct nsjconf_t *nsjconf, struct mounts_t *mpt, const ch unsigned long flags = mpt->flags & ~(MS_RDONLY); if (mount(srcpath, dst, mpt->fs_type, flags, mpt->options) == -1) { if (errno == EACCES) { - PLOG_E + PLOG_W ("mount('%s', '%s', type='%s') failed. Try fixing this problem by applying 'chmod o+x' to the '%s' directory and its ancestors", - srcpath, dst, mpt->fs_type, nsjconf->chroot); + srcpath, dst, mpt->fs_type ? mpt->fs_type : "[NULL]", nsjconf->chroot); } else { - PLOG_E("mount('%s', '%s', type='%s') failed", srcpath, dst, mpt->fs_type); + PLOG_W("mount('%s', '%s', type='%s') failed", srcpath, dst, + mpt->fs_type ? mpt->fs_type : "[NULL]"); + } + if (mpt->mandatory) { + return false; } - return false; } return true; } @@ -193,8 +196,10 @@ static bool mountRemountRO(struct mounts_t *mpt) mountFlagsToStr(vfs.f_flag), mountFlagsToStr(new_flags)); if (mount(mpt->dst, mpt->dst, NULL, new_flags, 0) == -1) { - PLOG_E("mount('%s', flags:%s)", mpt->dst, mountFlagsToStr(new_flags)); - return false; + PLOG_W("mount('%s', flags:%s)", mpt->dst, mountFlagsToStr(new_flags)); + if (mpt->mandatory) { + return false; + } } return true;