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);
}
}
{
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;
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;
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;
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) {
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) {
} 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) {
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;
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;
}
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,
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 */
},
{
"prefix_dst_env",
- 4,
+ 5,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
},
{
"fstype",
- 5,
+ 6,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
},
{
"options",
- 6,
+ 7,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
},
{
"is_bind",
- 7,
+ 8,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
},
{
"rw",
- 8,
+ 9,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
},
{
"is_dir",
- 9,
+ 10,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BOOL,
offsetof(Nsjail__MountPt, has_is_dir),
},
{
"mandatory",
- 10,
+ 11,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
};
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 = {
"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,
* 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
*/
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;
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
{
--- /dev/null
+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"
+}
}
}
+ 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
*/
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));
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);
}
}
+ 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;
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 */
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;
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);