Isolation: mounting of procfs by default when using "rootfs".
This commit is contained in:
@@ -326,11 +326,10 @@ cat << END > $NXT_BUILD_DIR/$NXT_JAVA_MOUNTS_HEADER
|
|||||||
|
|
||||||
|
|
||||||
static const nxt_fs_mount_t nxt_java_mounts[] = {
|
static const nxt_fs_mount_t nxt_java_mounts[] = {
|
||||||
{(u_char *) "proc", (u_char *) "/proc", (u_char *) "proc", 0, NULL, 1},
|
|
||||||
{(u_char *) "$NXT_JAVA_LIBC_DIR", (u_char *) "$NXT_JAVA_LIBC_DIR",
|
{(u_char *) "$NXT_JAVA_LIBC_DIR", (u_char *) "$NXT_JAVA_LIBC_DIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_JAVA_HOME", (u_char *) "$NXT_JAVA_HOME",
|
{(u_char *) "$NXT_JAVA_HOME", (u_char *) "$NXT_JAVA_HOME",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ pyver = "python" + str(sys.version_info[0]) + "." + str(sys.version_info[1])
|
|||||||
|
|
||||||
print("static const nxt_fs_mount_t nxt_python_mounts[] = {")
|
print("static const nxt_fs_mount_t nxt_python_mounts[] = {")
|
||||||
|
|
||||||
pattern = "{(u_char *) \"%s\", (u_char *) \"%s\", (u_char *) \"bind\", NXT_MS_BIND|NXT_MS_REC, NULL, 1},"
|
pattern = "{(u_char *) \"%s\", (u_char *) \"%s\", NXT_FS_BIND, (u_char *) \"bind\", 0, NULL, 1, 1},"
|
||||||
base = None
|
base = None
|
||||||
for p in sys.path:
|
for p in sys.path:
|
||||||
if len(p) > 0:
|
if len(p) > 0:
|
||||||
|
|||||||
@@ -156,23 +156,23 @@ cat << END > $NXT_RUBY_MOUNTS_PATH
|
|||||||
|
|
||||||
static const nxt_fs_mount_t nxt_ruby_mounts[] = {
|
static const nxt_fs_mount_t nxt_ruby_mounts[] = {
|
||||||
{(u_char *) "$NXT_RUBY_RUBYHDRDIR", (u_char *) "$NXT_RUBY_RUBYHDRDIR",
|
{(u_char *) "$NXT_RUBY_RUBYHDRDIR", (u_char *) "$NXT_RUBY_RUBYHDRDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_RUBY_ARCHHDRDIR", (u_char *) "$NXT_RUBY_ARCHHDRDIR",
|
{(u_char *) "$NXT_RUBY_ARCHHDRDIR", (u_char *) "$NXT_RUBY_ARCHHDRDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_RUBY_SITEDIR", (u_char *) "$NXT_RUBY_SITEDIR",
|
{(u_char *) "$NXT_RUBY_SITEDIR", (u_char *) "$NXT_RUBY_SITEDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_RUBY_LIBDIR", (u_char *) "$NXT_RUBY_LIBDIR",
|
{(u_char *) "$NXT_RUBY_LIBDIR", (u_char *) "$NXT_RUBY_LIBDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_RUBY_TOPDIR", (u_char *) "$NXT_RUBY_TOPDIR",
|
{(u_char *) "$NXT_RUBY_TOPDIR", (u_char *) "$NXT_RUBY_TOPDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
{(u_char *) "$NXT_RUBY_PREFIXDIR", (u_char *) "$NXT_RUBY_PREFIXDIR",
|
{(u_char *) "$NXT_RUBY_PREFIXDIR", (u_char *) "$NXT_RUBY_PREFIXDIR",
|
||||||
(u_char *) "bind", NXT_MS_BIND | NXT_MS_REC, NULL, 1},
|
NXT_FS_BIND, (u_char *) "bind", 0, NULL, 1, 1},
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
||||||
for path in `echo $NXT_RUBY_GEMPATH | tr ':' '\n'`; do
|
for path in `echo $NXT_RUBY_GEMPATH | tr ':' '\n'`; do
|
||||||
$echo "{(u_char *) \"$path\", (u_char *) \"$path\"," >> $NXT_RUBY_MOUNTS_PATH
|
$echo "{(u_char *) \"$path\", (u_char *) \"$path\"," >> $NXT_RUBY_MOUNTS_PATH
|
||||||
$echo "(u_char *) \"bind\", NXT_MS_BIND | NXT_MS_REC, NULL, 1}," >> $NXT_RUBY_MOUNTS_PATH
|
$echo "NXT_FS_BIND, (u_char *) \"bind\", 0, NULL, 1, 1}," >> $NXT_RUBY_MOUNTS_PATH
|
||||||
done
|
done
|
||||||
|
|
||||||
$echo "};" >> $NXT_RUBY_MOUNTS_PATH
|
$echo "};" >> $NXT_RUBY_MOUNTS_PATH
|
||||||
|
|||||||
@@ -208,14 +208,14 @@ nxt_discovery_modules(nxt_task_t *task, const char *path)
|
|||||||
mounts = module[i].mounts;
|
mounts = module[i].mounts;
|
||||||
|
|
||||||
size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", "
|
size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", "
|
||||||
"\"fstype\": \"\", \"flags\": , "
|
"\"type\": , \"name\": \"\", "
|
||||||
"\"data\": \"\"},");
|
"\"flags\": , \"data\": \"\"},");
|
||||||
|
|
||||||
mnt = mounts->elts;
|
mnt = mounts->elts;
|
||||||
|
|
||||||
for (j = 0; j < mounts->nelts; j++) {
|
for (j = 0; j < mounts->nelts; j++) {
|
||||||
size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst)
|
size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst)
|
||||||
+ nxt_strlen(mnt[j].fstype) + NXT_INT_T_LEN
|
+ nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN)
|
||||||
+ (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data));
|
+ (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,9 +242,10 @@ nxt_discovery_modules(nxt_task_t *task, const char *path)
|
|||||||
for (j = 0; j < mounts->nelts; j++) {
|
for (j = 0; j < mounts->nelts; j++) {
|
||||||
p = nxt_sprintf(p, end,
|
p = nxt_sprintf(p, end,
|
||||||
"{\"src\": \"%s\", \"dst\": \"%s\", "
|
"{\"src\": \"%s\", \"dst\": \"%s\", "
|
||||||
"\"fstype\": \"%s\", \"flags\": %d, "
|
"\"name\": \"%s\", \"type\": %d, \"flags\": %d, "
|
||||||
"\"data\": \"%s\"},",
|
"\"data\": \"%s\"},",
|
||||||
mnt[j].src, mnt[j].dst, mnt[j].fstype, mnt[j].flags,
|
mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type,
|
||||||
|
mnt[j].flags,
|
||||||
mnt[j].data == NULL ? (u_char *) "" : mnt[j].data);
|
mnt[j].data == NULL ? (u_char *) "" : mnt[j].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,11 +387,13 @@ nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
to->fstype = nxt_cstr_dup(mp, to->fstype, from->fstype);
|
to->name = nxt_cstr_dup(mp, to->name, from->name);
|
||||||
if (nxt_slow_path(to->fstype == NULL)) {
|
if (nxt_slow_path(to->name == NULL)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to->type = from->type;
|
||||||
|
|
||||||
if (from->data != NULL) {
|
if (from->data != NULL) {
|
||||||
to->data = nxt_cstr_dup(mp, to->data, from->data);
|
to->data = nxt_cstr_dup(mp, to->data, from->data);
|
||||||
if (nxt_slow_path(to->data == NULL)) {
|
if (nxt_slow_path(to->data == NULL)) {
|
||||||
|
|||||||
113
src/nxt_fs.c
113
src/nxt_fs.c
@@ -19,14 +19,58 @@ nxt_int_t
|
|||||||
nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
const char *fsname;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
rc = mount((const char *) mnt->src, (const char *) mnt->dst,
|
flags = 0;
|
||||||
(const char *) mnt->fstype, mnt->flags, mnt->data);
|
|
||||||
|
switch (mnt->type) {
|
||||||
|
case NXT_FS_BIND:
|
||||||
|
if (nxt_slow_path(mnt->flags != 0)) {
|
||||||
|
nxt_log(task, NXT_LOG_WARN,
|
||||||
|
"bind mount ignores additional flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
fsname = "bind";
|
||||||
|
flags = MS_BIND | MS_REC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NXT_FS_PROC:
|
||||||
|
fsname = "proc";
|
||||||
|
goto getflags;
|
||||||
|
|
||||||
|
case NXT_FS_TMP:
|
||||||
|
fsname = "tmpfs";
|
||||||
|
goto getflags;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fsname = (const char *) mnt->name;
|
||||||
|
|
||||||
|
getflags:
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NODEV) {
|
||||||
|
flags |= MS_NODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NOEXEC) {
|
||||||
|
flags |= MS_NOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NOSUID) {
|
||||||
|
flags |= MS_NOSUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mnt->flags & NXT_FS_FLAGS_NOTIME)) {
|
||||||
|
flags |= MS_RELATIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = mount((const char *) mnt->src, (const char *) mnt->dst, fsname, flags,
|
||||||
|
mnt->data);
|
||||||
|
|
||||||
if (nxt_slow_path(rc < 0)) {
|
if (nxt_slow_path(rc < 0)) {
|
||||||
nxt_alert(task, "mount(\"%s\", \"%s\", \"%s\", %d, \"%s\") %E",
|
nxt_alert(task, "mount(\"%s\", \"%s\", \"%s\", %ul, \"%s\") %E",
|
||||||
mnt->src, mnt->dst, mnt->fstype, mnt->flags, mnt->data,
|
mnt->src, mnt->dst, fsname, flags, mnt->data, nxt_errno);
|
||||||
nxt_errno);
|
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
}
|
}
|
||||||
@@ -34,37 +78,66 @@ nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
|||||||
return NXT_OK;
|
return NXT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif (NXT_HAVE_FREEBSD_NMOUNT)
|
#elif (NXT_HAVE_FREEBSD_NMOUNT)
|
||||||
|
|
||||||
nxt_int_t
|
nxt_int_t
|
||||||
nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
||||||
{
|
{
|
||||||
|
int flags;
|
||||||
u_char *data, *p, *end;
|
u_char *data, *p, *end;
|
||||||
size_t iovlen;
|
size_t iovlen;
|
||||||
nxt_int_t ret;
|
nxt_int_t ret;
|
||||||
const char *fstype;
|
const char *fsname;
|
||||||
struct iovec iov[128];
|
struct iovec iov[128];
|
||||||
char errmsg[256];
|
char errmsg[256];
|
||||||
|
|
||||||
if (nxt_strncmp(mnt->fstype, "bind", 4) == 0) {
|
if (nxt_slow_path((mnt->flags & NXT_FS_FLAGS_NODEV) && !mnt->builtin)) {
|
||||||
fstype = "nullfs";
|
nxt_alert(task, "nmount(2) doesn't support \"nodev\" option");
|
||||||
|
|
||||||
} else if (nxt_strncmp(mnt->fstype, "proc", 4) == 0) {
|
|
||||||
fstype = "procfs";
|
|
||||||
|
|
||||||
} else if (nxt_strncmp(mnt->fstype, "tmpfs", 5) == 0) {
|
|
||||||
fstype = "tmpfs";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
nxt_alert(task, "mount type \"%s\" not implemented.", mnt->fstype);
|
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
switch (mnt->type) {
|
||||||
|
case NXT_FS_BIND:
|
||||||
|
fsname = "nullfs";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NXT_FS_PROC:
|
||||||
|
fsname = "procfs";
|
||||||
|
goto getflags;
|
||||||
|
|
||||||
|
case NXT_FS_TMP:
|
||||||
|
fsname = "tmpfs";
|
||||||
|
goto getflags;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fsname = (const char *) mnt->name;
|
||||||
|
|
||||||
|
getflags:
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NOEXEC) {
|
||||||
|
flags |= MNT_NOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NOSUID) {
|
||||||
|
flags |= MNT_NOSUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_NOTIME) {
|
||||||
|
flags |= MNT_NOATIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnt->flags & NXT_FS_FLAGS_RDONLY) {
|
||||||
|
flags |= MNT_RDONLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iov[0].iov_base = (void *) "fstype";
|
iov[0].iov_base = (void *) "fstype";
|
||||||
iov[0].iov_len = 7;
|
iov[0].iov_len = 7;
|
||||||
iov[1].iov_base = (void *) fstype;
|
iov[1].iov_base = (void *) fsname;
|
||||||
iov[1].iov_len = nxt_strlen(fstype) + 1;
|
iov[1].iov_len = nxt_strlen(fsname) + 1;
|
||||||
iov[2].iov_base = (void *) "fspath";
|
iov[2].iov_base = (void *) "fspath";
|
||||||
iov[2].iov_len = 7;
|
iov[2].iov_len = 7;
|
||||||
iov[3].iov_base = (void *) mnt->dst;
|
iov[3].iov_base = (void *) mnt->dst;
|
||||||
@@ -117,7 +190,7 @@ nxt_fs_mount(nxt_task_t *task, nxt_fs_mount_t *mnt)
|
|||||||
|
|
||||||
ret = NXT_OK;
|
ret = NXT_OK;
|
||||||
|
|
||||||
if (nxt_slow_path(nmount(iov, iovlen, 0) < 0)) {
|
if (nxt_slow_path(nmount(iov, iovlen, flags) < 0)) {
|
||||||
nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg);
|
nxt_alert(task, "nmount(%p, %d, 0) %s", iov, iovlen, errmsg);
|
||||||
ret = NXT_ERROR;
|
ret = NXT_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
53
src/nxt_fs.h
53
src/nxt_fs.h
@@ -6,50 +6,33 @@
|
|||||||
#define _NXT_FS_H_INCLUDED_
|
#define _NXT_FS_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
#ifdef MS_BIND
|
typedef enum {
|
||||||
#define NXT_MS_BIND MS_BIND
|
NXT_FS_UNKNOWN = 0,
|
||||||
#else
|
NXT_FS_BIND,
|
||||||
#define NXT_MS_BIND 0
|
NXT_FS_TMP,
|
||||||
#endif
|
NXT_FS_PROC,
|
||||||
|
NXT_FS_LAST,
|
||||||
|
} nxt_fs_type_t;
|
||||||
|
|
||||||
#ifdef MS_REC
|
|
||||||
#define NXT_MS_REC MS_BIND
|
|
||||||
#else
|
|
||||||
#define NXT_MS_REC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MS_NOSUID
|
typedef enum {
|
||||||
#define NXT_MS_NOSUID MS_NOSUID
|
NXT_FS_FLAGS_NOSUID = 1 << 0,
|
||||||
#else
|
NXT_FS_FLAGS_NOEXEC = 1 << 1,
|
||||||
#define NXT_MS_NOSUID 0
|
NXT_FS_FLAGS_NOTIME = 1 << 2,
|
||||||
#endif
|
NXT_FS_FLAGS_NODEV = 1 << 3,
|
||||||
|
NXT_FS_FLAGS_RDONLY = 1 << 4,
|
||||||
#ifdef MS_NOEXEC
|
} nxt_fs_flags_t;
|
||||||
#define NXT_MS_NOEXEC MS_NOEXEC
|
|
||||||
#else
|
|
||||||
#define NXT_MS_NOEXEC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MS_RELATIME
|
|
||||||
#define NXT_MS_RELATIME MS_RELATIME
|
|
||||||
#else
|
|
||||||
#define NXT_MS_RELATIME 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MS_NODEV
|
|
||||||
#define NXT_MS_NODEV MS_NODEV
|
|
||||||
#else
|
|
||||||
#define NXT_MS_NODEV 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_char *src;
|
u_char *src;
|
||||||
u_char *dst;
|
u_char *dst;
|
||||||
u_char *fstype;
|
nxt_fs_type_t type;
|
||||||
nxt_int_t flags;
|
u_char *name;
|
||||||
|
nxt_fs_flags_t flags;
|
||||||
u_char *data;
|
u_char *data;
|
||||||
nxt_uint_t builtin; /* 1-bit */
|
nxt_uint_t builtin; /* 1-bit */
|
||||||
|
nxt_uint_t deps; /* 1-bit */
|
||||||
} nxt_fs_mount_t;
|
} nxt_fs_mount_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -87,15 +87,6 @@ nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (NXT_HAVE_ISOLATION_ROOTFS)
|
|
||||||
if (process->isolation.rootfs != NULL) {
|
|
||||||
ret = nxt_isolation_set_mounts(task, process, &app_conf->type);
|
|
||||||
if (nxt_slow_path(ret != NXT_OK)) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (cap_setid) {
|
if (cap_setid) {
|
||||||
ret = nxt_process_creds_set(task, process, &app_conf->user,
|
ret = nxt_process_creds_set(task, process, &app_conf->user,
|
||||||
&app_conf->group);
|
&app_conf->group);
|
||||||
@@ -126,6 +117,29 @@ nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (NXT_HAVE_ISOLATION_ROOTFS)
|
||||||
|
if (process->isolation.rootfs != NULL) {
|
||||||
|
nxt_int_t has_mnt;
|
||||||
|
|
||||||
|
ret = nxt_isolation_set_mounts(task, process, &app_conf->type);
|
||||||
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
has_mnt = 0;
|
||||||
|
|
||||||
|
#if (NXT_HAVE_CLONE_NEWNS)
|
||||||
|
has_mnt = nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (process->user_cred->uid == 0 && !has_mnt) {
|
||||||
|
nxt_log(task, NXT_LOG_WARN,
|
||||||
|
"setting user \"root\" with \"rootfs\" is unsafe without "
|
||||||
|
"\"mount\" namespace isolation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (NXT_HAVE_CLONE_NEWUSER)
|
#if (NXT_HAVE_CLONE_NEWUSER)
|
||||||
ret = nxt_isolation_vldt_creds(task, process);
|
ret = nxt_isolation_vldt_creds(task, process);
|
||||||
if (nxt_slow_path(ret != NXT_OK)) {
|
if (nxt_slow_path(ret != NXT_OK)) {
|
||||||
@@ -568,10 +582,13 @@ nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mnt->src = (u_char *) "tmpfs";
|
mnt->src = (u_char *) "tmpfs";
|
||||||
mnt->fstype = (u_char *) "tmpfs";
|
mnt->name = (u_char *) "tmpfs";
|
||||||
mnt->flags = NXT_MS_NOSUID | NXT_MS_NODEV | NXT_MS_NOEXEC | NXT_MS_RELATIME;
|
mnt->type = NXT_FS_TMP;
|
||||||
|
mnt->flags = (NXT_FS_FLAGS_NOSUID | NXT_FS_FLAGS_NODEV
|
||||||
|
| NXT_FS_FLAGS_NOEXEC);
|
||||||
mnt->data = (u_char *) "size=1m,mode=777";
|
mnt->data = (u_char *) "size=1m,mode=777";
|
||||||
mnt->builtin = 1;
|
mnt->builtin = 1;
|
||||||
|
mnt->deps = 0;
|
||||||
|
|
||||||
mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/tmp") + 1);
|
mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/tmp") + 1);
|
||||||
if (nxt_slow_path(mnt->dst == NULL)) {
|
if (nxt_slow_path(mnt->dst == NULL)) {
|
||||||
@@ -582,19 +599,14 @@ nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process,
|
|||||||
p = nxt_cpymem(p, "/tmp", 4);
|
p = nxt_cpymem(p, "/tmp", 4);
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
#if (NXT_HAVE_CLONE_NEWPID) && (NXT_HAVE_CLONE_NEWNS)
|
|
||||||
|
|
||||||
if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)
|
|
||||||
&& nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS))
|
|
||||||
{
|
|
||||||
mnt = nxt_array_add(mounts);
|
mnt = nxt_array_add(mounts);
|
||||||
if (nxt_slow_path(mnt == NULL)) {
|
if (nxt_slow_path(mnt == NULL)) {
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
mnt->fstype = (u_char *) "proc";
|
mnt->name = (u_char *) "proc";
|
||||||
mnt->src = (u_char *) "proc";
|
mnt->type = NXT_FS_PROC;
|
||||||
|
mnt->src = (u_char *) "none";
|
||||||
mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/proc") + 1);
|
mnt->dst = nxt_mp_nget(mp, rootfs_len + nxt_length("/proc") + 1);
|
||||||
if (nxt_slow_path(mnt->dst == NULL)) {
|
if (nxt_slow_path(mnt->dst == NULL)) {
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
@@ -605,9 +617,9 @@ nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process,
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
mnt->data = (u_char *) "";
|
mnt->data = (u_char *) "";
|
||||||
mnt->flags = 0;
|
mnt->flags = NXT_FS_FLAGS_NOEXEC | NXT_FS_FLAGS_NOSUID;
|
||||||
}
|
mnt->builtin = 1;
|
||||||
#endif
|
mnt->deps = 0;
|
||||||
|
|
||||||
qsort(mounts->elts, mounts->nelts, sizeof(nxt_fs_mount_t),
|
qsort(mounts->elts, mounts->nelts, sizeof(nxt_fs_mount_t),
|
||||||
nxt_isolation_mount_compare);
|
nxt_isolation_mount_compare);
|
||||||
@@ -661,7 +673,7 @@ nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process)
|
|||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
n--;
|
n--;
|
||||||
|
|
||||||
if (mnt[n].builtin && !automount->language_deps) {
|
if (mnt[n].deps && !automount->language_deps) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,11 +702,11 @@ nxt_isolation_prepare_rootfs(nxt_task_t *task, nxt_process_t *process)
|
|||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
dst = mnt[i].dst;
|
dst = mnt[i].dst;
|
||||||
|
|
||||||
if (mnt[i].builtin && !automount->language_deps) {
|
if (mnt[i].deps && !automount->language_deps) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(nxt_memcmp(mnt[i].fstype, "bind", 4) == 0
|
if (nxt_slow_path(mnt[i].type == NXT_FS_BIND
|
||||||
&& stat((const char *) mnt[i].src, &st) != 0))
|
&& stat((const char *) mnt[i].src, &st) != 0))
|
||||||
{
|
{
|
||||||
nxt_log(task, NXT_LOG_WARN, "host path not found: %s", mnt[i].src);
|
nxt_log(task, NXT_LOG_WARN, "host path not found: %s", mnt[i].src);
|
||||||
|
|||||||
@@ -1163,9 +1163,14 @@ static nxt_conf_map_t nxt_app_lang_mounts_map[] = {
|
|||||||
offsetof(nxt_fs_mount_t, dst),
|
offsetof(nxt_fs_mount_t, dst),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("fstype"),
|
nxt_string("name"),
|
||||||
NXT_CONF_MAP_CSTRZ,
|
NXT_CONF_MAP_CSTRZ,
|
||||||
offsetof(nxt_fs_mount_t, fstype),
|
offsetof(nxt_fs_mount_t, name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nxt_string("type"),
|
||||||
|
NXT_CONF_MAP_INT,
|
||||||
|
offsetof(nxt_fs_mount_t, type),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("flags"),
|
nxt_string("flags"),
|
||||||
@@ -1297,6 +1302,7 @@ nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mnt->builtin = 1;
|
mnt->builtin = 1;
|
||||||
|
mnt->deps = 1;
|
||||||
|
|
||||||
ret = nxt_conf_map_object(rt->mem_pool, value,
|
ret = nxt_conf_map_object(rt->mem_pool, value,
|
||||||
nxt_app_lang_mounts_map,
|
nxt_app_lang_mounts_map,
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t language_deps; /* 1-byte */
|
uint8_t language_deps; /* 1-bit */
|
||||||
} nxt_process_automount_t;
|
} nxt_process_automount_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -226,13 +226,23 @@ class TestGoIsolation(TestApplicationGo):
|
|||||||
if not self.isolation_key('pid'):
|
if not self.isolation_key('pid'):
|
||||||
pytest.skip('pid namespace is not supported')
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
if not (is_su or self.isolation_key('unprivileged_userns_clone')):
|
if not is_su:
|
||||||
pytest.skip('requires root or unprivileged_userns_clone')
|
if not self.isolation_key('unprivileged_userns_clone'):
|
||||||
|
pytest.skip('unprivileged clone is not available')
|
||||||
|
|
||||||
self.load(
|
if not self.isolation_key('user'):
|
||||||
'ns_inspect',
|
pytest.skip('user namespace is not supported')
|
||||||
isolation={'namespaces': {'pid': True, 'credential': True}},
|
|
||||||
)
|
if not self.isolation_key('mnt'):
|
||||||
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
|
isolation = {'namespaces': {'pid': True}}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces']['mount'] = True
|
||||||
|
isolation['namespaces']['credential'] = True
|
||||||
|
|
||||||
|
self.load('ns_inspect', isolation=isolation)
|
||||||
|
|
||||||
obj = self.getjson()['body']
|
obj = self.getjson()['body']
|
||||||
|
|
||||||
@@ -269,16 +279,27 @@ class TestGoIsolation(TestApplicationGo):
|
|||||||
== option.available['features']['isolation'][ns]
|
== option.available['features']['isolation'][ns]
|
||||||
), ('%s match' % ns)
|
), ('%s match' % ns)
|
||||||
|
|
||||||
def test_go_isolation_rootfs_container(self, temp_dir):
|
def test_go_isolation_rootfs_container(self, is_su, temp_dir):
|
||||||
|
if not is_su:
|
||||||
if not self.isolation_key('unprivileged_userns_clone'):
|
if not self.isolation_key('unprivileged_userns_clone'):
|
||||||
pytest.skip('unprivileged clone is not available')
|
pytest.skip('unprivileged clone is not available')
|
||||||
|
|
||||||
|
if not self.isolation_key('user'):
|
||||||
|
pytest.skip('user namespace is not supported')
|
||||||
|
|
||||||
if not self.isolation_key('mnt'):
|
if not self.isolation_key('mnt'):
|
||||||
pytest.skip('mnt namespace is not supported')
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
isolation = {
|
if not self.isolation_key('pid'):
|
||||||
'namespaces': {'mount': True, 'credential': True},
|
pytest.skip('pid namespace is not supported')
|
||||||
'rootfs': temp_dir,
|
|
||||||
|
isolation = {'rootfs': temp_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('ns_inspect', isolation=isolation)
|
self.load('ns_inspect', isolation=isolation)
|
||||||
@@ -311,16 +332,27 @@ class TestGoIsolation(TestApplicationGo):
|
|||||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||||
assert obj['FileExists'] == False, 'file should not exists'
|
assert obj['FileExists'] == False, 'file should not exists'
|
||||||
|
|
||||||
def test_go_isolation_rootfs_default_tmpfs(self, temp_dir):
|
def test_go_isolation_rootfs_default_tmpfs(self, is_su, temp_dir):
|
||||||
|
if not is_su:
|
||||||
if not self.isolation_key('unprivileged_userns_clone'):
|
if not self.isolation_key('unprivileged_userns_clone'):
|
||||||
pytest.skip('unprivileged clone is not available')
|
pytest.skip('unprivileged clone is not available')
|
||||||
|
|
||||||
|
if not self.isolation_key('user'):
|
||||||
|
pytest.skip('user namespace is not supported')
|
||||||
|
|
||||||
if not self.isolation_key('mnt'):
|
if not self.isolation_key('mnt'):
|
||||||
pytest.skip('mnt namespace is not supported')
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
isolation = {
|
if not self.isolation_key('pid'):
|
||||||
'namespaces': {'mount': True, 'credential': True},
|
pytest.skip('pid namespace is not supported')
|
||||||
'rootfs': temp_dir,
|
|
||||||
|
isolation = {'rootfs': temp_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('ns_inspect', isolation=isolation)
|
self.load('ns_inspect', isolation=isolation)
|
||||||
|
|||||||
@@ -26,57 +26,71 @@ class TestPHPIsolation(TestApplicationPHP):
|
|||||||
|
|
||||||
return check if not complete_check else check()
|
return check if not complete_check else check()
|
||||||
|
|
||||||
def test_php_isolation_rootfs(self, is_su):
|
def test_php_isolation_rootfs(self, is_su, temp_dir):
|
||||||
isolation_features = option.available['features']['isolation'].keys()
|
isolation_features = option.available['features']['isolation'].keys()
|
||||||
|
|
||||||
if 'mnt' not in isolation_features:
|
|
||||||
pytest.skip('requires mnt ns')
|
|
||||||
|
|
||||||
if not is_su:
|
if not is_su:
|
||||||
if 'user' not in isolation_features:
|
|
||||||
pytest.skip('requires unprivileged userns or root')
|
|
||||||
|
|
||||||
if not 'unprivileged_userns_clone' in isolation_features:
|
if not 'unprivileged_userns_clone' in isolation_features:
|
||||||
pytest.skip('requires unprivileged userns or root')
|
pytest.skip('requires unprivileged userns or root')
|
||||||
|
|
||||||
isolation = {
|
if 'user' not in isolation_features:
|
||||||
'namespaces': {'credential': not is_su, 'mount': True},
|
pytest.skip('user namespace is not supported')
|
||||||
'rootfs': option.test_dir,
|
|
||||||
|
if 'mnt' not in isolation_features:
|
||||||
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
|
if 'pid' not in isolation_features:
|
||||||
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
|
isolation = {'rootfs': temp_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('phpinfo', isolation=isolation)
|
self.load('phpinfo', isolation=isolation)
|
||||||
|
|
||||||
assert 'success' in self.conf(
|
assert 'success' in self.conf(
|
||||||
'"/php/phpinfo"', 'applications/phpinfo/root'
|
'"/app/php/phpinfo"', 'applications/phpinfo/root'
|
||||||
)
|
)
|
||||||
assert 'success' in self.conf(
|
assert 'success' in self.conf(
|
||||||
'"/php/phpinfo"', 'applications/phpinfo/working_directory'
|
'"/app/php/phpinfo"', 'applications/phpinfo/working_directory'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert self.get()['status'] == 200, 'empty rootfs'
|
assert self.get()['status'] == 200, 'empty rootfs'
|
||||||
|
|
||||||
def test_php_isolation_rootfs_extensions(self, is_su):
|
def test_php_isolation_rootfs_extensions(self, is_su, temp_dir):
|
||||||
isolation_features = option.available['features']['isolation'].keys()
|
isolation_features = option.available['features']['isolation'].keys()
|
||||||
|
|
||||||
if not is_su:
|
if not is_su:
|
||||||
if 'user' not in isolation_features:
|
|
||||||
pytest.skip('requires unprivileged userns or root')
|
|
||||||
|
|
||||||
if not 'unprivileged_userns_clone' in isolation_features:
|
if not 'unprivileged_userns_clone' in isolation_features:
|
||||||
pytest.skip('requires unprivileged userns or root')
|
pytest.skip('requires unprivileged userns or root')
|
||||||
|
|
||||||
if 'mnt' not in isolation_features:
|
if 'user' not in isolation_features:
|
||||||
pytest.skip('requires mnt ns')
|
pytest.skip('user namespace is not supported')
|
||||||
|
|
||||||
isolation = {
|
if 'mnt' not in isolation_features:
|
||||||
'rootfs': option.test_dir,
|
pytest.skip('mnt namespace is not supported')
|
||||||
'namespaces': {'credential': not is_su, 'mount': not is_su},
|
|
||||||
|
if 'pid' not in isolation_features:
|
||||||
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
|
isolation = {'rootfs': temp_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('list-extensions', isolation=isolation)
|
self.load('list-extensions', isolation=isolation)
|
||||||
|
|
||||||
assert 'success' in self.conf(
|
assert 'success' in self.conf(
|
||||||
'"/php/list-extensions"', 'applications/list-extensions/root'
|
'"/app/php/list-extensions"', 'applications/list-extensions/root'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 'success' in self.conf(
|
assert 'success' in self.conf(
|
||||||
@@ -85,7 +99,7 @@ class TestPHPIsolation(TestApplicationPHP):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert 'success' in self.conf(
|
assert 'success' in self.conf(
|
||||||
'"/php/list-extensions"',
|
'"/app/php/list-extensions"',
|
||||||
'applications/list-extensions/working_directory',
|
'applications/list-extensions/working_directory',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -29,25 +29,28 @@ class TestPythonIsolation(TestApplicationPython):
|
|||||||
def test_python_isolation_rootfs(self, is_su, temp_dir):
|
def test_python_isolation_rootfs(self, is_su, temp_dir):
|
||||||
isolation_features = option.available['features']['isolation'].keys()
|
isolation_features = option.available['features']['isolation'].keys()
|
||||||
|
|
||||||
if 'mnt' not in isolation_features:
|
|
||||||
pytest.skip('requires mnt ns')
|
|
||||||
|
|
||||||
if not is_su:
|
if not is_su:
|
||||||
if 'user' not in isolation_features:
|
|
||||||
pytest.skip('requires unprivileged userns or root')
|
|
||||||
|
|
||||||
if not 'unprivileged_userns_clone' in isolation_features:
|
if not 'unprivileged_userns_clone' in isolation_features:
|
||||||
pytest.skip('requires unprivileged userns or root')
|
pytest.skip('requires unprivileged userns or root')
|
||||||
|
|
||||||
isolation = {
|
if 'user' not in isolation_features:
|
||||||
'namespaces': {'credential': not is_su, 'mount': True},
|
pytest.skip('user namespace is not supported')
|
||||||
'rootfs': temp_dir,
|
|
||||||
|
if 'mnt' not in isolation_features:
|
||||||
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
|
if 'pid' not in isolation_features:
|
||||||
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
|
isolation = {'rootfs': temp_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('empty', isolation=isolation)
|
|
||||||
|
|
||||||
assert self.get()['status'] == 200, 'python rootfs'
|
|
||||||
|
|
||||||
self.load('ns_inspect', isolation=isolation)
|
self.load('ns_inspect', isolation=isolation)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -57,7 +60,7 @@ class TestPythonIsolation(TestApplicationPython):
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||||
== False
|
== True
|
||||||
), 'no /proc/self'
|
), 'no /proc/self'
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -78,22 +81,31 @@ class TestPythonIsolation(TestApplicationPython):
|
|||||||
def test_python_isolation_rootfs_no_language_deps(self, is_su, temp_dir):
|
def test_python_isolation_rootfs_no_language_deps(self, is_su, temp_dir):
|
||||||
isolation_features = option.available['features']['isolation'].keys()
|
isolation_features = option.available['features']['isolation'].keys()
|
||||||
|
|
||||||
if 'mnt' not in isolation_features:
|
|
||||||
pytest.skip('requires mnt ns')
|
|
||||||
|
|
||||||
if not is_su:
|
if not is_su:
|
||||||
if 'user' not in isolation_features:
|
|
||||||
pytest.skip('requires unprivileged userns or root')
|
|
||||||
|
|
||||||
if not 'unprivileged_userns_clone' in isolation_features:
|
if not 'unprivileged_userns_clone' in isolation_features:
|
||||||
pytest.skip('requires unprivileged userns or root')
|
pytest.skip('requires unprivileged userns or root')
|
||||||
|
|
||||||
|
if 'user' not in isolation_features:
|
||||||
|
pytest.skip('user namespace is not supported')
|
||||||
|
|
||||||
|
if 'mnt' not in isolation_features:
|
||||||
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
|
if 'pid' not in isolation_features:
|
||||||
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
isolation = {
|
isolation = {
|
||||||
'namespaces': {'credential': not is_su, 'mount': True},
|
|
||||||
'rootfs': temp_dir,
|
'rootfs': temp_dir,
|
||||||
'automount': {'language_deps': False}
|
'automount': {'language_deps': False}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
|
}
|
||||||
|
|
||||||
self.load('empty', isolation=isolation)
|
self.load('empty', isolation=isolation)
|
||||||
|
|
||||||
assert (self.get()['status'] != 200), 'disabled language_deps'
|
assert (self.get()['status'] != 200), 'disabled language_deps'
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class TestPythonIsolation(TestApplicationPython):
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||||
== False
|
== True
|
||||||
), 'no /proc/self'
|
), 'no /proc/self'
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
|
|||||||
@@ -29,19 +29,26 @@ class TestRubyIsolation(TestApplicationRuby):
|
|||||||
def test_ruby_isolation_rootfs_mount_namespace(self, is_su):
|
def test_ruby_isolation_rootfs_mount_namespace(self, is_su):
|
||||||
isolation_features = option.available['features']['isolation'].keys()
|
isolation_features = option.available['features']['isolation'].keys()
|
||||||
|
|
||||||
if 'mnt' not in isolation_features:
|
|
||||||
pytest.skip('requires mnt ns')
|
|
||||||
|
|
||||||
if not is_su:
|
if not is_su:
|
||||||
if 'user' not in isolation_features:
|
|
||||||
pytest.skip('requires unprivileged userns or root')
|
|
||||||
|
|
||||||
if not 'unprivileged_userns_clone' in isolation_features:
|
if not 'unprivileged_userns_clone' in isolation_features:
|
||||||
pytest.skip('requires unprivileged userns or root')
|
pytest.skip('requires unprivileged userns or root')
|
||||||
|
|
||||||
isolation = {
|
if 'user' not in isolation_features:
|
||||||
'namespaces': {'credential': not is_su, 'mount': True},
|
pytest.skip('user namespace is not supported')
|
||||||
'rootfs': option.test_dir,
|
|
||||||
|
if 'mnt' not in isolation_features:
|
||||||
|
pytest.skip('mnt namespace is not supported')
|
||||||
|
|
||||||
|
if 'pid' not in isolation_features:
|
||||||
|
pytest.skip('pid namespace is not supported')
|
||||||
|
|
||||||
|
isolation = {'rootfs': option.test_dir}
|
||||||
|
|
||||||
|
if not is_su:
|
||||||
|
isolation['namespaces'] = {
|
||||||
|
'mount': True,
|
||||||
|
'credential': True,
|
||||||
|
'pid': True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.load('status_int', isolation=isolation)
|
self.load('status_int', isolation=isolation)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from conftest import option
|
from conftest import option
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
from unit.applications.proto import TestApplicationProto
|
from unit.applications.proto import TestApplicationProto
|
||||||
|
|
||||||
|
|
||||||
@@ -8,6 +11,17 @@ class TestApplicationPHP(TestApplicationProto):
|
|||||||
def load(self, script, index='index.php', **kwargs):
|
def load(self, script, index='index.php', **kwargs):
|
||||||
script_path = option.test_dir + '/php/' + script
|
script_path = option.test_dir + '/php/' + script
|
||||||
|
|
||||||
|
if kwargs.get('isolation') and kwargs['isolation'].get('rootfs'):
|
||||||
|
rootfs = kwargs['isolation']['rootfs']
|
||||||
|
|
||||||
|
if not os.path.exists(rootfs + '/app/php/'):
|
||||||
|
os.makedirs(rootfs + '/app/php/')
|
||||||
|
|
||||||
|
if not os.path.exists(rootfs + '/app/php/' + script):
|
||||||
|
shutil.copytree(script_path, rootfs + '/app/php/' + script)
|
||||||
|
|
||||||
|
script_path = '/app/php/' + script
|
||||||
|
|
||||||
self._load_conf(
|
self._load_conf(
|
||||||
{
|
{
|
||||||
"listeners": {"*:7080": {"pass": "applications/" + script}},
|
"listeners": {"*:7080": {"pass": "applications/" + script}},
|
||||||
|
|||||||
Reference in New Issue
Block a user