#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/wait.h>
+#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libubox/uloop.h>
#define STACK_SIZE (1024 * 1024)
-#define OPT_ARGS "S:C:n:h:r:w:d:psuloc"
+#define OPT_ARGS "S:C:n:h:r:w:d:psulocU:G:"
static struct {
char *name;
char **jail_argv;
char *seccomp;
char *capabilities;
+ char *user;
+ char *group;
int no_new_privs;
int namespace;
int procfs;
fprintf(stderr, " -s\t\tjail has /sys\n");
fprintf(stderr, " -l\t\tjail has /dev/log\n");
fprintf(stderr, " -u\t\tjail has a ubus socket\n");
+ fprintf(stderr, " -U <name>\tuser to run jailed process\n");
+ fprintf(stderr, " -G <name>\tgroup to run jailed process\n");
fprintf(stderr, " -o\t\tremont jail root (/) read only\n");
fprintf(stderr, "\nWarning: by default root inside the jail is the same\n\
and he has the same powers as root outside the jail,\n\
static int exec_jail(void *_notused)
{
+ struct passwd *p = NULL;
+ struct group *g = NULL;
+
if (opts.capabilities && drop_capabilities(opts.capabilities))
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
+ if (opts.user) {
+ p = getpwnam(opts.user);
+ if (!p) {
+ ERROR("failed to get uid/gid for user %s: %d (%s)\n",
+ opts.user, errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (opts.group) {
+ g = getgrnam(opts.group);
+ if (!g) {
+ ERROR("failed to get gid for group %s: %m\n", opts.group);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (p && p->pw_gid && initgroups(opts.user, p->pw_gid)) {
+ ERROR("failed to initgroups() for user %s: %m\n", opts.user);
+ exit(EXIT_FAILURE);
+ }
+
+ if (g && g->gr_gid && setgid(g->gr_gid)) {
+ ERROR("failed to set group id %d: %m\n", g?g->gr_gid:p->pw_gid);
+ exit(EXIT_FAILURE);
+ }
+
+ if (p && p->pw_uid && setuid(p->pw_uid)) {
+ ERROR("failed to set user id %d: %m\n", p->pw_uid);
+ exit(EXIT_FAILURE);
+ }
+
+
char **envp = build_envp(opts.seccomp);
if (!envp)
exit(EXIT_FAILURE);
opts.namespace = 1;
add_mount(log, 0, -1);
break;
+ case 'U':
+ opts.user = optarg;
+ break;
+ case 'G':
+ opts.group = optarg;
+ break;
}
}
add_mount("/dev/urandom", 0, -1);
add_mount("/dev/zero", 0, -1);
+ if (opts.user || opts.group) {
+ add_mount("/etc/passwd", 0, -1);
+ add_mount("/etc/group", 0, -1);
+ }
+
+ if (opts.namespace & NAMESPACE_IPC)
+ flags |= CLONE_NEWIPC;
+
int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | SIGCHLD;
if (opts.hostname)
flags |= CLONE_NEWUTS;
argv[argc++] = in->seccomp;
}
+ if (in->user) {
+ argv[argc++] = "-U";
+ argv[argc++] = in->user;
+ }
+
+ if (in->group) {
+ argv[argc++] = "-G";
+ argv[argc++] = in->group;
+ }
+
if (in->no_new_privs)
argv[argc++] = "-c";
closefd(_stderr);
}
- if (in->user && in->pw_gid && initgroups(in->user, in->pw_gid)) {
+ if (!in->has_jail && in->user && in->pw_gid && initgroups(in->user, in->pw_gid)) {
ERROR("failed to initgroups() for user %s: %m\n", in->user);
exit(127);
}
- if (in->gr_gid && setgid(in->gr_gid)) {
+ if (!in->has_jail && in->gr_gid && setgid(in->gr_gid)) {
ERROR("failed to set group id %d: %m\n", in->gr_gid);
exit(127);
}
- if (in->uid && setuid(in->uid)) {
+ if (!in->has_jail && in->uid && setuid(in->uid)) {
ERROR("failed to set user id %d: %m\n", in->uid);
exit(127);
}
if (in->seccomp)
jail->argc += 2;
+ if (in->user)
+ jail->argc += 2;
+
+ if (in->group)
+ jail->argc += 2;
+
if (in->no_new_privs)
jail->argc++;