Support envvars on mount path definitions

This commit is contained in:
Robert Swiecki 2017-05-28 00:15:53 +02:00
parent e020c989de
commit e68acd68eb
9 changed files with 177 additions and 74 deletions

View File

@ -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: 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> <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/evince /user/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/geeqie /user/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/gv //user/Documents/doc.pdf
</pre> </pre>
*** ***

View File

@ -183,27 +183,27 @@ static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig
nsjconf->mount_proc = njc->mount_proc; nsjconf->mount_proc = njc->mount_proc;
for (size_t i = 0; i < njc->n_mount; i++) { for (size_t i = 0; i < njc->n_mount; i++) {
struct mounts_t *p = utilCalloc(sizeof(struct mounts_t)); const char *src = njc->mount[i]->src;
p->src = utilStrDup(njc->mount[i]->src); const char *src_env = njc->mount[i]->prefix_src_env;
p->dst = utilStrDup(njc->mount[i]->dst); const char *dst = njc->mount[i]->dst;
p->fs_type = utilStrDup(njc->mount[i]->fstype); const char *dst_env = njc->mount[i]->prefix_dst_env;
p->options = utilStrDup(njc->mount[i]->options); const char *fstype = njc->mount[i]->fstype;
p->flags |= (njc->mount[i]->is_ro ? MS_RDONLY : 0); const char *options = njc->mount[i]->options;
p->flags |= (njc->mount[i]->is_bind ? (MS_BIND | MS_REC) : 0);
if (njc->mount[i]->has_is_dir) { uintptr_t flags = njc->mount[i]->is_ro ? MS_RDONLY : 0;
p->isDir = njc->mount[i]->is_dir; flags |= njc->mount[i]->is_bind ? (MS_BIND | MS_REC) : 0;
} else { bool mandatory = njc->mount[i]->mandatory;
if (njc->mount[i]->src == NULL) {
p->isDir = true; const bool *isDir =
} else if (njc->mount[i]->is_bind) { (njc->mount[i]->has_is_dir) ? (const bool *)&njc->mount[i]->is_dir : NULL;
p->isDir = mountIsDir(njc->mount[i]->src);
} else { if (mountAddMountPt
p->isDir = true; (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) { if (njc->seccomp_policy_file) {
if ((nsjconf->kafel_file = fopen(njc->seccomp_policy_file, "rb")) == NULL) { if ((nsjconf->kafel_file = fopen(njc->seccomp_policy_file, "rb")) == NULL) {

View 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_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__is_ro__default_value = 0;
static const protobuf_c_boolean nsjail__mount_pt__mandatory__default_value = 1; 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", "src",
1, 1,
@ -252,8 +252,20 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
0, NULL, NULL /* reserved1,reserved2, etc */ 0, NULL, NULL /* reserved1,reserved2, etc */
}, },
{ {
"dst", "prefix_src_env",
2, 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_LABEL_REQUIRED,
PROTOBUF_C_TYPE_STRING, PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */ 0, /* quantifier_offset */
@ -263,9 +275,21 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
0, /* flags */ 0, /* flags */
0, NULL, NULL /* reserved1,reserved2, etc */ 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", "fstype",
3, 5,
PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING, PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */ 0, /* quantifier_offset */
@ -277,7 +301,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
}, },
{ {
"options", "options",
4, 6,
PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_STRING, PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */ 0, /* quantifier_offset */
@ -289,7 +313,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
}, },
{ {
"is_bind", "is_bind",
5, 7,
PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL, PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */ 0, /* quantifier_offset */
@ -301,7 +325,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
}, },
{ {
"is_ro", "is_ro",
6, 8,
PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL, PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */ 0, /* quantifier_offset */
@ -313,7 +337,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
}, },
{ {
"is_dir", "is_dir",
7, 9,
PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BOOL, PROTOBUF_C_TYPE_BOOL,
offsetof(Nsjail__MountPt, has_is_dir), offsetof(Nsjail__MountPt, has_is_dir),
@ -325,7 +349,7 @@ static const ProtobufCFieldDescriptor nsjail__mount_pt__field_descriptors[8] = {
}, },
{ {
"mandatory", "mandatory",
8, 10,
PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_BOOL, PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */ 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[] = { static const unsigned nsjail__mount_pt__field_indices_by_name[] = {
1, /* field[1] = dst */ 2, /* field[2] = dst */
2, /* field[2] = fstype */ 4, /* field[4] = fstype */
4, /* field[4] = is_bind */ 6, /* field[6] = is_bind */
6, /* field[6] = is_dir */ 8, /* field[8] = is_dir */
5, /* field[5] = is_ro */ 7, /* field[7] = is_ro */
7, /* field[7] = mandatory */ 9, /* field[9] = mandatory */
3, /* field[3] = options */ 5, /* field[5] = options */
3, /* field[3] = prefix_dst_env */
1, /* field[1] = prefix_src_env */
0, /* field[0] = src */ 0, /* field[0] = src */
}; };
static const ProtobufCIntRange nsjail__mount_pt__number_ranges[1 + 1] = { static const ProtobufCIntRange nsjail__mount_pt__number_ranges[1 + 1] = {
{1, 0}, {1, 0},
{0, 8} {0, 10}
}; };
const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = { const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = {
@ -360,7 +386,7 @@ const ProtobufCMessageDescriptor nsjail__mount_pt__descriptor = {
"Nsjail__MountPt", "Nsjail__MountPt",
"nsjail", "nsjail",
sizeof(Nsjail__MountPt), sizeof(Nsjail__MountPt),
8, 10,
nsjail__mount_pt__field_descriptors, nsjail__mount_pt__field_descriptors,
nsjail__mount_pt__field_indices_by_name, nsjail__mount_pt__field_indices_by_name,
1, nsjail__mount_pt__number_ranges, 1, nsjail__mount_pt__number_ranges,

View File

@ -87,7 +87,18 @@ struct _Nsjail__MountPt {
* Can be skipped for filesystems like 'proc' * Can be skipped for filesystems like 'proc'
*/ */
char *src; char *src;
/*
* Should 'src' path be prefixed with this envvar?
*/
char *prefix_src_env;
/*
* Mount point inside jail
*/
char *dst; char *dst;
/*
* Should 'dst' path be prefixed with this envvar?
*/
char *prefix_dst_env;
/* /*
* Can be empty for mount --bind mounts * 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[]; extern char nsjail__mount_pt__options__default_value[];
#define NSJAIL__MOUNT_PT__INIT \ #define NSJAIL__MOUNT_PT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&nsjail__mount_pt__descriptor) \ { 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 { struct _Nsjail__Exe {
ProtobufCMessage base; ProtobufCMessage base;

View File

@ -30,20 +30,25 @@ message MountPt
{ {
/* Can be skipped for filesystems like 'proc' */ /* Can be skipped for filesystems like 'proc' */
optional string src = 1; 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 */ /* Can be empty for mount --bind mounts */
optional string fstype = 3 [ default = "" ]; optional string fstype = 5 [ default = "" ];
/* E.g. size=5000000 for 'tmpfs' */ /* 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 */ /* 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 */ /* 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 /* Is it directory? If not specified an internal
heuristics will be used to determine that */ 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? */ /* Should the sandboxing fail if we cannot mount this resource? */
required bool mandatory = 8 [ default = true ]; required bool mandatory = 10 [ default = true ];
} }
message Exe message Exe
{ {

View File

@ -1,28 +1,26 @@
name: "firefox-with-net" name: "firefox-with-net"
description: " description: "
This policy allows to run firefox inside a jail. Access to the This policy allows to run firefox inside a jail. Access to networking is
networking is permitted. permitted with thise setup (disable clone_newnet).
The only permitted home directory is $HOME/.mozilla and $HOME/Documents. 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. The rest of available FS-resources are system and X-related files/dirs.
You'll also have to change all references to /home/jagger to make them point
to your local home directory.
Run it as: Run as:
./nsjail --config configs/firefox-with-net.cfg ./nsjail --config configs/firefox-with-net.cfg
You can then go to https://uploadfiles.io/ and try to upload a file in order 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 mode: ONCE
hostname: "FIREFOX" hostname: "FIREFOX"
cwd: "/home/jagger" cwd: "/user"
time_limit: 0 time_limit: 0
envar: "HOME=/home/jagger" envar: "HOME=/user"
envar: "DISPLAY=:0" envar: "DISPLAY=:0"
rlimit_as: 4096 rlimit_as: 4096
@ -110,29 +108,31 @@ mount {
} }
mount { mount {
dst: "/home/jagger/" dst: "/user"
fstype: "tmpfs" fstype: "tmpfs"
is_ro: false is_ro: false
} }
mount { mount {
src: "/home/jagger/Documents" prefix_src_env: "HOME"
dst: "/home/jagger/Documents" src: "/Documents"
dst: "/user/Documents"
is_ro: false is_ro: false
is_bind: true is_bind: true
mandatory: false mandatory: false
} }
mount { mount {
src: "/home/jagger/.mozilla" prefix_src_env: "HOME"
dst: "/home/jagger/.mozilla" src: "/.mozilla"
dst: "/user/.mozilla"
is_bind: true is_bind: true
is_ro: false is_ro: false
mandatory: false mandatory: false
} }
mount { mount {
dst: "/home/jagger/.cache" dst: "/user/.cache"
fstype: "tmpfs" fstype: "tmpfs"
is_ro: false is_ro: false
} }

View File

@ -1,14 +1,13 @@
name: "documents-with-xorg" name: "documents-with-xorg"
description: " description: "
This policy allows to run many Xorg based tool, which are allowed This policy allows to run many X-org based tool, which are allowed
to access $HOME/Documents directory only. Example of use would be: to access $HOME/Documents directory only. An example of use is:
./nsjail --config configs/documents-with-xorg.cfg -- \\ ./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 What is more, this policy doesn't allow to access networking.
to modify paths referring to '/home/jagger' to whatever your home "
directory is. Also, this policy doesn't allow to access networking"
mode: ONCE mode: ONCE
hostname: "NSJAIL" hostname: "NSJAIL"
@ -17,6 +16,7 @@ cwd: "/"
time_limit: 1000 time_limit: 1000
envar: "DISPLAY=:0" envar: "DISPLAY=:0"
envar: "HOME=/user"
rlimit_as: 512 rlimit_as: 512
rlimit_cpu: 1000 rlimit_cpu: 1000
@ -68,15 +68,16 @@ mount {
} }
mount { mount {
src: "/home/jagger/Documents" dst: "/user"
dst: "/home/jagger/Documents" fstype: "tmpfs"
is_bind: true is_ro: false
} }
mount { mount {
dst: "/home/jagger/.cache" prefix_src_env: "HOME"
fstype: "tmpfs" src: "/Documents"
is_ro: false dst: "/user/Documents"
is_bind: true
} }
mount { mount {

57
mount.c
View File

@ -334,3 +334,60 @@ bool mountInitNs(struct nsjconf_t * nsjconf)
} }
return false; 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;
}

View File

@ -29,5 +29,8 @@
const char *mountFlagsToStr(uintptr_t flags); const char *mountFlagsToStr(uintptr_t flags);
bool mountIsDir(const char *path); bool mountIsDir(const char *path);
bool mountInitNs(struct nsjconf_t *nsjconf); 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 */ #endif /* NS_MOUNT_H */