Support envvars on mount path definitions
authorRobert Swiecki <robert@swiecki.net>
Sat, 27 May 2017 22:15:53 +0000 (00:15 +0200)
committerRobert Swiecki <robert@swiecki.net>
Sat, 27 May 2017 22:15:53 +0000 (00:15 +0200)
README.md
config.c
config.pb-c.c
config.pb-c.h
config.proto
configs/firefox-with-net.cfg
configs/home-documents-with-xorg-no-net.cfg
mount.c
mount.h

index 3cd8e9c314ec6bf777b1703e7cd7a9bed2bfd2c7..9540ed5646d3203ebbad8af179b991c6f5dbbcc8 100644 (file)
--- 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:
 
 <pre>
-$ ./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
 </pre>
 
 ***
index ea8cd6f6cce3f5589b100dfee4d9a05addfaf7bf..28b6a6c1c335c10a577da8efd6fb354cfa93ef40 100644 (file)
--- 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) {
index 8ce734a04df4addc626ba9899ebd7ba395ba6a8d..88a677f108c7e55eeff66db9e1a0c43c946a9e90 100644 (file)
@@ -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,
index d5a4efe39ad234205897b9deb049e8c0f166a5d5..808e283b4a51f7b9d06718fb8fd11fb83a71827d 100644 (file)
@@ -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;
index 66a4c89705ce5fec4b2e30eaf245735c255064c3..d04abe5417905572e929621a50748b5668358b0d 100644 (file)
@@ -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
 {
index 793f2a543b8bf05e5283fded50095fd69e9929f9..429a20d7713bea9780369de47710d946ebf48e75 100644 (file)
@@ -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
 }
index aabc1fc3204e9959107a0525ba10d103bc8a221b..39a5b1d1899f1fbe4c7dbe972f2f2bab64497754 100644 (file)
@@ -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 79f13a6655b295901a602a3ca6e36c3d8a9632e1..3a5663859550f14c962ac6a5fb6dff54c1e19a40 100644 (file)
--- 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 46da8f095b8a19bd860d56f4b43d4a6b5959826f..993df192770fedbc71c9dd519a090eae17c85285 100644 (file)
--- 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 */