diff --git a/README.md b/README.md index 3cd8e9c..9540ed5 100644 --- a/README.md +++ b/README.md @@ -276,9 +276,9 @@ uid=999999 gid=999998 euid=4294965959 groups=999998,65534 You might also want to try using [configs/home-documents-with-xorg-no-net.cfg](https://github.com/google/nsjail/blob/master/configs/home-documents-with-xorg-no-net.cfg). You'll have to modify all referrences to _/home/jagger_ to whatever your home directory is, though. After that, you can use it as follows:
-$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/evince /home/jagger/Documents/doc.pdf
-$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/geeqie /home/jagger/Documents/
-$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/gv /home/jagger/Documents/doc.pdf
+$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/evince /user/Documents/doc.pdf
+$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/geeqie /user/Documents/
+$ ./nsjail --config configs/home-documents-with-xorg-no-net.cfg -- /usr/bin/gv //user/Documents/doc.pdf
 
*** diff --git a/config.c b/config.c index ea8cd6f..28b6a6c 100644 --- a/config.c +++ b/config.c @@ -183,26 +183,26 @@ 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); - p->dst = utilStrDup(njc->mount[i]->dst); - p->fs_type = utilStrDup(njc->mount[i]->fstype); - p->options = utilStrDup(njc->mount[i]->options); - p->flags |= (njc->mount[i]->is_ro ? MS_RDONLY : 0); - p->flags |= (njc->mount[i]->is_bind ? (MS_BIND | MS_REC) : 0); - if (njc->mount[i]->has_is_dir) { - p->isDir = njc->mount[i]->is_dir; - } else { - if (njc->mount[i]->src == NULL) { - p->isDir = true; - } else if (njc->mount[i]->is_bind) { - p->isDir = mountIsDir(njc->mount[i]->src); - } else { - p->isDir = true; - } + const char *src = njc->mount[i]->src; + const char *src_env = njc->mount[i]->prefix_src_env; + const char *dst = njc->mount[i]->dst; + const char *dst_env = njc->mount[i]->prefix_dst_env; + const char *fstype = njc->mount[i]->fstype; + const char *options = njc->mount[i]->options; + + uintptr_t flags = njc->mount[i]->is_ro ? MS_RDONLY : 0; + flags |= njc->mount[i]->is_bind ? (MS_BIND | MS_REC) : 0; + bool mandatory = njc->mount[i]->mandatory; + + const bool *isDir = + (njc->mount[i]->has_is_dir) ? (const bool *)&njc->mount[i]->is_dir : NULL; + + if (mountAddMountPt + (nsjconf, src, dst, fstype, options, flags, isDir, mandatory, src_env, + dst_env) == false) { + LOG_E("Couldn't add mountpoint for src:'%s' dst:'%s'", src, dst); + return false; } - p->mandatory = njc->mount[i]->mandatory; - TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); } if (njc->seccomp_policy_file) { diff --git a/config.pb-c.c b/config.pb-c.c index 8ce734a..88a677f 100644 --- a/config.pb-c.c +++ b/config.pb-c.c @@ -238,7 +238,7 @@ 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 protobuf_c_boolean nsjail__mount_pt__mandatory__default_value = 1; -static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { +static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] = { { "src", 1, @@ -252,8 +252,20 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { 0, NULL, NULL /* reserved1,reserved2, etc */ }, { - "dst", + "prefix_src_env", 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Nsjail__MountPt, prefix_src_env), + NULL, + NULL, + 0, /* flags */ + 0, NULL, NULL /* reserved1,reserved2, etc */ + }, + { + "dst", + 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ @@ -263,9 +275,21 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, + { + "prefix_dst_env", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Nsjail__MountPt, prefix_dst_env), + NULL, + NULL, + 0, /* flags */ + 0, NULL, NULL /* reserved1,reserved2, etc */ + }, { "fstype", - 3, + 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ @@ -277,7 +301,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }, { "options", - 4, + 6, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ @@ -289,7 +313,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }, { "is_bind", - 5, + 7, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BOOL, 0, /* quantifier_offset */ @@ -301,7 +325,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }, { "is_ro", - 6, + 8, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BOOL, 0, /* quantifier_offset */ @@ -313,7 +337,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }, { "is_dir", - 7, + 9, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BOOL, offsetof(Nsjail__MountPt, has_is_dir), @@ -325,7 +349,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }, { "mandatory", - 8, + 10, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BOOL, 0, /* quantifier_offset */ @@ -338,19 +362,21 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = { }; static const unsigned nsjail__mount_pt__field_indices_by_name[] = { - 1, /* field[1] = dst */ - 2, /* field[2] = fstype */ - 4, /* field[4] = is_bind */ - 6, /* field[6] = is_dir */ - 5, /* field[5] = is_ro */ - 7, /* field[7] = mandatory */ - 3, /* field[3] = options */ + 2, /* field[2] = dst */ + 4, /* field[4] = fstype */ + 6, /* field[6] = is_bind */ + 8, /* field[8] = is_dir */ + 7, /* field[7] = is_ro */ + 9, /* field[9] = mandatory */ + 5, /* field[5] = options */ + 3, /* field[3] = prefix_dst_env */ + 1, /* field[1] = prefix_src_env */ 0, /* field[0] = src */ }; static const ProtobufCIntRange nsjail__mount_pt__number_ranges[1 + 1] = { {1, 0}, - {0, 8} + {0, 10} }; const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = { @@ -360,7 +386,7 @@ const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = { "Nsjail__MountPt", "nsjail", sizeof(Nsjail__MountPt), - 8, + 10, 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 d5a4efe..808e283 100644 --- a/config.pb-c.h +++ b/config.pb-c.h @@ -87,7 +87,18 @@ struct _Nsjail__MountPt { * Can be skipped for filesystems like 'proc' */ char *src; + /* + * Should 'src' path be prefixed with this envvar? + */ + char *prefix_src_env; + /* + * Mount point inside jail + */ char *dst; + /* + * Should 'dst' path be prefixed with this envvar? + */ + char *prefix_dst_env; /* * Can be empty for mount --bind mounts */ @@ -119,7 +130,7 @@ 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, nsjail__mount_pt__fstype__default_value, nsjail__mount_pt__options__default_value, 0, 0, 0,0, 1 } + , NULL, NULL, 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 66a4c89..d04abe5 100644 --- a/config.proto +++ b/config.proto @@ -30,20 +30,25 @@ message MountPt { /* Can be skipped for filesystems like 'proc' */ optional string src = 1; - required string dst = 2; + /* Should 'src' path be prefixed with this envvar? */ + optional string prefix_src_env = 2; + /* Mount point inside jail */ + required string dst = 3; + /* Should 'dst' path be prefixed with this envvar? */ + optional string prefix_dst_env = 4; /* Can be empty for mount --bind mounts */ - optional string fstype = 3 [ default = "" ]; + optional string fstype = 5 [ default = "" ]; /* E.g. size=5000000 for 'tmpfs' */ - required string options = 4 [ default = "" ]; + required string options = 6 [ default = "" ]; /* Is it 'mount --bind src dst' type of mount */ - required bool is_bind = 5 [ default = false ]; + required bool is_bind = 7 [ default = false ]; /* It it RO mount */ - required bool is_ro = 6 [ default = false ]; + required bool is_ro = 8 [ default = false ]; /* Is it directory? If not specified an internal heuristics will be used to determine that */ - optional bool is_dir = 7; + optional bool is_dir = 9; /* Should the sandboxing fail if we cannot mount this resource? */ - required bool mandatory = 8 [ default = true ]; + required bool mandatory = 10 [ default = true ]; } message Exe { diff --git a/configs/firefox-with-net.cfg b/configs/firefox-with-net.cfg index 793f2a5..429a20d 100644 --- a/configs/firefox-with-net.cfg +++ b/configs/firefox-with-net.cfg @@ -1,28 +1,26 @@ name: "firefox-with-net" description: " -This policy allows to run firefox inside a jail. Access to the -networking is permitted. +This policy allows to run firefox inside a jail. Access to networking is +permitted with thise setup (disable clone_newnet). The only permitted home directory is $HOME/.mozilla and $HOME/Documents. -The rest of available FS-resources are are system and X-related files.dires. -You'll also have to change all references to /home/jagger to make them point -to your local home directory. +The rest of available FS-resources are system and X-related files/dirs. -Run it as: +Run as: ./nsjail --config configs/firefox-with-net.cfg You can then go to https://uploadfiles.io/ and try to upload a file in order -to see how your local directory (also, all system directories) look like +to see how your local directory (also, all system directories) look like. " mode: ONCE hostname: "FIREFOX" -cwd: "/home/jagger" +cwd: "/user" time_limit: 0 -envar: "HOME=/home/jagger" +envar: "HOME=/user" envar: "DISPLAY=:0" rlimit_as: 4096 @@ -110,29 +108,31 @@ mount { } mount { - dst: "/home/jagger/" + dst: "/user" fstype: "tmpfs" is_ro: false } mount { - src: "/home/jagger/Documents" - dst: "/home/jagger/Documents" + prefix_src_env: "HOME" + src: "/Documents" + dst: "/user/Documents" is_ro: false is_bind: true mandatory: false } mount { - src: "/home/jagger/.mozilla" - dst: "/home/jagger/.mozilla" + prefix_src_env: "HOME" + src: "/.mozilla" + dst: "/user/.mozilla" is_bind: true is_ro: false mandatory: false } mount { - dst: "/home/jagger/.cache" + dst: "/user/.cache" fstype: "tmpfs" is_ro: false } diff --git a/configs/home-documents-with-xorg-no-net.cfg b/configs/home-documents-with-xorg-no-net.cfg index aabc1fc..39a5b1d 100644 --- a/configs/home-documents-with-xorg-no-net.cfg +++ b/configs/home-documents-with-xorg-no-net.cfg @@ -1,14 +1,13 @@ name: "documents-with-xorg" description: " -This policy allows to run many Xorg based tool, which are allowed -to access $HOME/Documents directory only. Example of use would be: +This policy allows to run many X-org based tool, which are allowed +to access $HOME/Documents directory only. An example of use is: ./nsjail --config configs/documents-with-xorg.cfg -- \\ - /usr/bin/geeqie /home/jagger/Documents/ + /usr/bin/geeqie /user/Documents/ -As nsjail configs don't allow to use variables or envvars, you'll have -to modify paths referring to '/home/jagger' to whatever your home -directory is. Also, this policy doesn't allow to access networking" +What is more, this policy doesn't allow to access networking. +" mode: ONCE hostname: "NSJAIL" @@ -17,6 +16,7 @@ cwd: "/" time_limit: 1000 envar: "DISPLAY=:0" +envar: "HOME=/user" rlimit_as: 512 rlimit_cpu: 1000 @@ -68,15 +68,16 @@ mount { } mount { - src: "/home/jagger/Documents" - dst: "/home/jagger/Documents" - is_bind: true + dst: "/user" + fstype: "tmpfs" + is_ro: false } mount { - dst: "/home/jagger/.cache" - fstype: "tmpfs" - is_ro: false + prefix_src_env: "HOME" + src: "/Documents" + dst: "/user/Documents" + is_bind: true } mount { diff --git a/mount.c b/mount.c index 79f13a6..3a56638 100644 --- a/mount.c +++ b/mount.c @@ -334,3 +334,60 @@ bool mountInitNs(struct nsjconf_t * nsjconf) } return false; } + +bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *dst, + const char *fstype, const char *options, uintptr_t flags, const bool * isDir, + bool mandatory, const char *src_env, const char *dst_env) +{ + struct mounts_t *p = utilCalloc(sizeof(struct mounts_t)); + + if (src_env) { + const char *e = getenv(src_env); + if (e == NULL) { + LOG_W("No such envvar:'%s'", src_env); + return false; + } + if (asprintf((char **)&p->src, "%s%s", e, src ? src : "") == -1) { + PLOG_W("asprintf() failed"); + return false; + } + } else { + p->src = utilStrDup(src); + } + + if (dst_env) { + const char *e = getenv(dst_env); + if (e == NULL) { + LOG_W("No such envvar:'%s'", dst_env); + return false; + } + if (asprintf((char **)&p->dst, "%s%s", e, dst ? dst : "") == -1) { + PLOG_W("asprintf() failed"); + return false; + } + } else { + p->dst = utilStrDup(dst); + } + + p->fs_type = utilStrDup(fstype); + p->options = utilStrDup(options); + p->flags = flags; + p->isDir = isDir; + p->mandatory = mandatory; + + if (isDir) { + p->isDir = *isDir; + } else { + if (p->src == NULL) { + p->isDir = true; + } else if (p->flags & MS_BIND) { + p->isDir = mountIsDir(p->src); + } else { + p->isDir = true; + } + } + + TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); + + return true; +} diff --git a/mount.h b/mount.h index 46da8f0..993df19 100644 --- a/mount.h +++ b/mount.h @@ -29,5 +29,8 @@ const char *mountFlagsToStr(uintptr_t flags); bool mountIsDir(const char *path); bool mountInitNs(struct nsjconf_t *nsjconf); +bool mountAddMountPt(struct nsjconf_t *nsjconf, const char *src, const char *dst, + const char *fstype, const char *options, uintptr_t flags, const bool * isDir, + bool mandatory, const char *src_env, const char *dst_env); #endif /* NS_MOUNT_H */