add configs/firefox-with-cloned-net.cfg
authorRobert Swiecki <robert@swiecki.net>
Sun, 28 May 2017 14:56:16 +0000 (16:56 +0200)
committerRobert Swiecki <robert@swiecki.net>
Sun, 28 May 2017 14:56:16 +0000 (16:56 +0200)
cmdline.c
common.h
config.c
config.pb-c.c
config.pb-c.h
config.proto
configs/firefox-with-cloned-net.cfg [new file with mode: 0644]
mount.c
mount.h
util.c
util.h

index cc68354c59d36d31c1e2e6e975f30bbb176e4da3..541a5782575512687eaf1833abfe4387d7429b2c 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -225,10 +225,11 @@ 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 mandatory:%s",
+                           ("Mount point: src:'%s' dst:'%s' type:'%s' flags:%s options:'%s' isDir:%s mandatory:%s src_content:%s (size:%zu)",
                             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->mandatory ? "true" : "false");
+                            p->isDir ? "true" : "false", p->mandatory ? "true" : "false",
+                            p->src_content ? "true" : "false", p->src_content_len);
                }
        }
        {
@@ -606,6 +607,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                case 'R':{
                                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = optarg;
+                               p->src_content = NULL;
+                               p->src_content_len = 0;
                                const char *dst = cmdlineSplitStrByColon(optarg);
                                p->dst = dst ? dst : optarg;
                                p->flags = MS_BIND | MS_REC | MS_RDONLY;
@@ -618,6 +621,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                case 'B':{
                                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = optarg;
+                               p->src_content = NULL;
+                               p->src_content_len = 0;
                                const char *dst = cmdlineSplitStrByColon(optarg);
                                p->dst = dst ? dst : optarg;
                                p->flags = MS_BIND | MS_REC;
@@ -630,6 +635,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                case 'T':{
                                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = NULL;
+                               p->src_content = NULL;
+                               p->src_content_len = 0;
                                p->dst = optarg;
                                p->flags = 0;
                                p->options = cmdlineTmpfsSz;
@@ -713,6 +720,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
        if (nsjconf->mount_proc == true) {
                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                p->src = NULL;
+               p->src_content = NULL;
+               p->src_content_len = 0;
                p->dst = "/proc";
                p->flags = 0;
                if (nsjconf->is_root_rw == false) {
@@ -727,6 +736,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
        if (nsjconf->chroot != NULL) {
                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                p->src = nsjconf->chroot;
+               p->src_content = NULL;
+               p->src_content_len = 0;
                p->dst = "/";
                p->flags = MS_BIND | MS_REC;
                if (nsjconf->is_root_rw == false) {
@@ -740,6 +751,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
        } else {
                struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                p->src = NULL;
+               p->src_content = NULL;
+               p->src_content_len = 0;
                p->dst = "/";
                p->flags = 0;
                if (nsjconf->is_root_rw == false) {
index a03fe5c218ef7351b736e6fbf68c9a7fce325d23..c5c69befd35521c64146e178c2d5137cb175dcca 100644 (file)
--- a/common.h
+++ b/common.h
@@ -66,6 +66,8 @@ struct pids_t {
 
 struct mounts_t {
        const char *src;
+       const uint8_t *src_content;
+       size_t src_content_len;
        const char *dst;
        const char *fs_type;
        const char *options;
index 69721a08f9d32953ceeb93781e35875252f662c3..3028911a0ba877872e3bb549eaf9d17d5be072bb 100644 (file)
--- a/config.c
+++ b/config.c
@@ -187,9 +187,16 @@ static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig
                const bool *isDir =
                    (njc->mount[i]->has_is_dir) ? (const bool *)&njc->mount[i]->is_dir : NULL;
 
+               uint8_t *src_content = NULL;
+               size_t src_content_len = 0;
+               if (njc->mount[i]->has_src_content) {
+                       src_content = njc->mount[i]->src_content.data;
+                       src_content_len = njc->mount[i]->src_content.len;
+               }
+
                if (mountAddMountPt
                    (nsjconf, src, dst, fstype, options, flags, isDir, mandatory, src_env,
-                    dst_env) == false) {
+                    dst_env, src_content, src_content_len) == false) {
                        LOG_E("Couldn't add mountpoint for src:'%s' dst:'%s'", src, dst);
                        return false;
                }
index 53e5e9317d33fcadc8405116978dc19f8825f088..c896cea24d583e839f28ba0c3cd3d52bd4d6cecf 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__rw__default_value = 0;
 static const protobuf_c_boolean nsjail__mount_pt__mandatory__default_value = 1;
-static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] = {
+static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[11] = {
        {
         "src",
         1,
@@ -264,8 +264,20 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         0, NULL, NULL          /* reserved1,reserved2, etc */
         },
        {
-        "dst",
+        "src_content",
         3,
+        PROTOBUF_C_LABEL_OPTIONAL,
+        PROTOBUF_C_TYPE_BYTES,
+        offsetof(Nsjail__MountPt, has_src_content),
+        offsetof(Nsjail__MountPt, src_content),
+        NULL,
+        NULL,
+        0,                     /* flags */
+        0, NULL, NULL          /* reserved1,reserved2, etc */
+        },
+       {
+        "dst",
+        4,
         PROTOBUF_C_LABEL_REQUIRED,
         PROTOBUF_C_TYPE_STRING,
         0,                     /* quantifier_offset */
@@ -277,7 +289,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "prefix_dst_env",
-        4,
+        5,
         PROTOBUF_C_LABEL_OPTIONAL,
         PROTOBUF_C_TYPE_STRING,
         0,                     /* quantifier_offset */
@@ -289,7 +301,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "fstype",
-        5,
+        6,
         PROTOBUF_C_LABEL_OPTIONAL,
         PROTOBUF_C_TYPE_STRING,
         0,                     /* quantifier_offset */
@@ -301,7 +313,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "options",
-        6,
+        7,
         PROTOBUF_C_LABEL_REQUIRED,
         PROTOBUF_C_TYPE_STRING,
         0,                     /* quantifier_offset */
@@ -313,7 +325,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "is_bind",
-        7,
+        8,
         PROTOBUF_C_LABEL_REQUIRED,
         PROTOBUF_C_TYPE_BOOL,
         0,                     /* quantifier_offset */
@@ -325,7 +337,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "rw",
-        8,
+        9,
         PROTOBUF_C_LABEL_REQUIRED,
         PROTOBUF_C_TYPE_BOOL,
         0,                     /* quantifier_offset */
@@ -337,7 +349,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "is_dir",
-        9,
+        10,
         PROTOBUF_C_LABEL_OPTIONAL,
         PROTOBUF_C_TYPE_BOOL,
         offsetof(Nsjail__MountPt, has_is_dir),
@@ -349,7 +361,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
         },
        {
         "mandatory",
-        10,
+        11,
         PROTOBUF_C_LABEL_REQUIRED,
         PROTOBUF_C_TYPE_BOOL,
         0,                     /* quantifier_offset */
@@ -362,21 +374,22 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[10] =
 };
 
 static const unsigned nsjail__mount_pt__field_indices_by_name[] = {
-       2,                      /* field[2] = dst */
-       4,                      /* field[4] = fstype */
-       6,                      /* field[6] = is_bind */
-       8,                      /* field[8] = is_dir */
-       9,                      /* field[9] = mandatory */
-       5,                      /* field[5] = options */
-       3,                      /* field[3] = prefix_dst_env */
+       3,                      /* field[3] = dst */
+       5,                      /* field[5] = fstype */
+       7,                      /* field[7] = is_bind */
+       9,                      /* field[9] = is_dir */
+       10,                     /* field[10] = mandatory */
+       6,                      /* field[6] = options */
+       4,                      /* field[4] = prefix_dst_env */
        1,                      /* field[1] = prefix_src_env */
-       7,                      /* field[7] = rw */
+       8,                      /* field[8] = rw */
        0,                      /* field[0] = src */
+       2,                      /* field[2] = src_content */
 };
 
 static const ProtobufCIntRange nsjail__mount_pt__number_ranges[1 + 1] = {
        {1, 0},
-       {0, 10}
+       {0, 11}
 };
 
 const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = {
@@ -386,7 +399,7 @@ const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = {
        "Nsjail__MountPt",
        "nsjail",
        sizeof(Nsjail__MountPt),
-       10,
+       11,
        nsjail__mount_pt__field_descriptors,
        nsjail__mount_pt__field_indices_by_name,
        1, nsjail__mount_pt__number_ranges,
index 0c9e2152d62e192b291b60c2fd2c10dd94af2297..ef4ede281183f69d163280df4bd93e2309993ea7 100644 (file)
@@ -91,6 +91,11 @@ struct _Nsjail__MountPt {
         * Should 'src' path be prefixed with this envvar? 
         */
        char *prefix_src_env;
+       /*
+        * If specified, contains buffer that will be written to the dst file 
+        */
+       protobuf_c_boolean has_src_content;
+       ProtobufCBinaryData src_content;
        /*
         * Mount point inside jail 
         */
@@ -130,7 +135,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, NULL, NULL, nsjail__mount_pt__fstype__default_value, nsjail__mount_pt__options__default_value, 0, 0, 0,0, 1 }
+    , NULL, NULL, 0,{0,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 29e4aa8191cc0a8d5bef235c6394a240ea784223..e681e15c0bb64c42cda4a4c203e658b5a96fc70e 100644 (file)
@@ -32,23 +32,25 @@ message MountPt
     optional string src = 1;
        /* Should 'src' path be prefixed with this envvar? */
        optional string prefix_src_env = 2;
+       /* If specified, contains buffer that will be written to the dst file */
+       optional bytes src_content = 3;
        /* Mount point inside jail */
-    required string dst = 3;
+    required string dst = 4;
        /* Should 'dst' path be prefixed with this envvar? */
-       optional string prefix_dst_env = 4;
+       optional string prefix_dst_env = 5;
     /* Can be empty for mount --bind mounts */
-    optional string fstype = 5 [ default = "" ];
+    optional string fstype = 6 [ default = "" ];
     /* E.g. size=5000000 for 'tmpfs' */
-    required string options = 6 [ default = "" ];
+    required string options = 7 [ default = "" ];
     /* Is it 'mount --bind src dst' type of mount */
-    required bool is_bind = 7 [ default = false ];
+    required bool is_bind = 8 [ default = false ];
     /* It it R/W mount */
-    required bool rw = 8 [ default = false ];
+    required bool rw = 9 [ default = false ];
     /* Is it directory? If not specified an internal
        heuristics will be used to determine that */
-    optional bool is_dir = 9;
+    optional bool is_dir = 10;
     /* Should the sandboxing fail if we cannot mount this resource? */
-    required bool mandatory = 10 [ default = true ];
+    required bool mandatory = 11 [ default = true ];
 }
 message Exe
 {
diff --git a/configs/firefox-with-cloned-net.cfg b/configs/firefox-with-cloned-net.cfg
new file mode 100644 (file)
index 0000000..58ae9ad
--- /dev/null
@@ -0,0 +1,166 @@
+name: "firefox-with-cloned-net"
+description: "
+This policy allows to run firefox inside a jail on a separate eth interface.
+A separate networking context separates process from the global \"lo\", and
+from global abstract socket namespace.
+
+The only permitted home directory is $HOME/.mozilla and $HOME/Documents.
+The rest of available on the FS files/dires are libs and X-related files/dirs.
+
+As this needs to be run as root, you will have to set-up correct uid&gid
+mappings (here: 'jagger'), name of your local interface (here: 'enp0s31f6'),
+and correct IPv4 addresses.
+
+IPv6 should work out-of-the-box, given that your local IPv6 discovery is set
+up correctly.
+
+Run as:
+
+sudo ./nsjail --config configs/firefox-with-cloned-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.
+"
+
+mode: ONCE
+hostname: "FF-MACVTAP"
+cwd: "/user"
+
+time_limit: 0
+
+envar: "HOME=/user"
+envar: "DISPLAY=:0"
+envar: "TMP=/tmp"
+
+rlimit_as: 4096
+rlimit_cpu: 1000
+rlimit_fsize: 1024
+rlimit_nofile: 128
+
+uidmap {
+       inside_id: "9999999"
+       outside_id: "jagger"
+}
+
+gidmap {
+       inside_id: "9999999"
+       outside_id: "jagger"
+}
+
+mount {
+       dst: "/proc"
+       fstype: "proc"
+}
+
+mount {
+       src: "/lib"
+       dst: "/lib"
+       is_bind: true
+}
+
+mount {
+       src: "/usr/lib"
+       dst: "/usr/lib"
+       is_bind: true
+}
+
+mount {
+       src: "/lib64"
+       dst: "/lib64"
+       is_bind: true
+       mandatory: false
+}
+
+mount {
+       src: "/lib32"
+       dst: "/lib32"
+       is_bind: true
+       mandatory: false
+}
+
+mount {
+       src: "/usr/lib/firefox"
+       dst: "/usr/lib/firefox"
+       is_bind: true
+}
+
+mount {
+       src: "/usr/bin/firefox"
+       dst: "/usr/bin/firefox"
+       is_bind: true
+}
+
+mount {
+       src: "/usr/share"
+       dst: "/usr/share"
+       is_bind: true
+}
+
+mount {
+       src: "/dev/urandom"
+       dst: "/dev/urandom"
+       is_bind: true
+       rw: true
+}
+
+mount {
+       src_content: "nameserver 8.8.8.8"
+       dst: "/etc/resolv.conf"
+}
+
+mount {
+       dst: "/tmp"
+       fstype: "tmpfs"
+       rw: true
+       is_bind: false
+}
+
+mount {
+       dst: "/user"
+       fstype: "tmpfs"
+       rw: true
+}
+
+mount {
+       prefix_src_env: "HOME"
+       src: "/Documents"
+       dst: "/user/Documents"
+       rw: true
+       is_bind: true
+       mandatory: false
+}
+
+mount {
+       prefix_src_env: "HOME"
+       src: "/.mozilla"
+       dst: "/user/.mozilla"
+       is_bind: true
+       rw: true
+       mandatory: false
+}
+
+mount {
+       src: "/tmp/.X11-unix/X0"
+       dst: "/tmp/.X11-unix/X0"
+       is_bind: true
+}
+
+seccomp_string: "
+       POLICY example {
+               KILL {
+                       ptrace,
+                       process_vm_readv,
+                       process_vm_writev
+               }
+       }
+       USE example DEFAULT ALLOW
+"
+
+macvlan_iface: "enp0s31f6"
+macvlan_vs_ip: "192.168.10.223"
+macvlan_vs_nm: "255.255.255.0"
+macvlan_vs_gw: "192.168.10.1"
+
+exec_bin {
+        path: "/usr/lib/firefox/firefox"
+}
diff --git a/mount.c b/mount.c
index cfd2ed275cdceebf60a5a61777afbac9c658dbf7..4c5f6935b0c0264f44836292d2f061854365fdbe 100644 (file)
--- a/mount.c
+++ b/mount.c
@@ -152,6 +152,23 @@ static bool mountMount(struct mounts_t *mpt, const char *oldroot, const char *ds
                }
        }
 
+       if (mpt->src_content) {
+               snprintf(srcpath, sizeof(srcpath), "/file.XXXXXX");
+               int fd = mkostemp(srcpath, O_CLOEXEC);
+               if (fd < 0) {
+                       PLOG_W("mkostemp('%s')", srcpath);
+                       close(fd);
+                       return false;
+               }
+               if (utilWriteToFd(fd, mpt->src_content, mpt->src_content_len) == false) {
+                       LOG_W("Writting %zu bytes to '%s' failed", mpt->src_content_len, srcpath);
+                       close(fd);
+                       return false;
+               }
+               close(fd);
+               mpt->flags |= (MS_BIND | MS_REC);
+       }
+
        /*
         * Initially mount it as RW, it will be remounted later on if needed
         */
@@ -343,7 +360,8 @@ 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)
+                    bool mandatory, const char *src_env, const char *dst_env,
+                    const uint8_t * src_content, size_t src_content_len)
 {
        struct mounts_t *p = utilCalloc(sizeof(struct mounts_t));
 
@@ -393,13 +411,15 @@ bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *ds
        p->fs_type = utilStrDup(fstype);
        p->options = utilStrDup(options);
        p->flags = flags;
-       p->isDir = isDir;
+       p->isDir = true;
        p->mandatory = mandatory;
 
        if (isDir) {
                p->isDir = *isDir;
        } else {
-               if (p->src == NULL) {
+               if (src_content) {
+                       p->isDir = false;
+               } else if (p->src == NULL) {
                        p->isDir = true;
                } else if (p->flags & MS_BIND) {
                        p->isDir = mountIsDir(p->src);
@@ -408,6 +428,9 @@ bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *ds
                }
        }
 
+       p->src_content = utilMemDup(src_content, src_content_len);
+       p->src_content_len = src_content_len;
+
        TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers);
 
        return true;
diff --git a/mount.h b/mount.h
index 993df192770fedbc71c9dd519a090eae17c85285..2cfcc5a80efb4c58bcc5d04ff3fcc9e5f5602483 100644 (file)
--- a/mount.h
+++ b/mount.h
@@ -31,6 +31,7 @@ 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);
+                    bool mandatory, const char *src_env, const char *dst_env,
+                    const uint8_t * src_content, size_t src_content_len);
 
 #endif                         /* NS_MOUNT_H */
diff --git a/util.c b/util.c
index 5e0cc2f2db7cc36d07e5539d9ba7c38b768462a6..a226d1c38cc426177ed8423591bd172d2a87f441 100644 (file)
--- a/util.c
+++ b/util.c
@@ -70,6 +70,16 @@ char *utilStrDupLen(const char *str, size_t len)
        return ret;
 }
 
+uint8_t *utilMemDup(const uint8_t * src, size_t len)
+{
+       if (src == NULL) {
+               return NULL;
+       }
+       uint8_t *ret = utilMalloc(len);
+       memcpy(ret, src, len);
+       return ret;
+}
+
 ssize_t utilReadFromFd(int fd, void *buf, size_t len)
 {
        uint8_t *charbuf = (uint8_t *) buf;
diff --git a/util.h b/util.h
index d438bcd9656ad40ed8d2575b8a91a5de1971e8df..2015f215259314bf5004021e5526327438e3927b 100644 (file)
--- a/util.h
+++ b/util.h
@@ -30,6 +30,7 @@
 void *utilMalloc(size_t sz);
 void *utilCalloc(size_t sz);
 char *utilStrDup(const char *str);
+uint8_t *utilMemDup(const uint8_t * src, size_t len);
 ssize_t utilReadFromFd(int fd, void *buf, size_t len);
 ssize_t utilReadFromFile(const char *fname, void *buf, size_t len);
 ssize_t utilWriteToFd(int fd, const void *buf, size_t len);