Skip to content

Instantly share code, notes, and snippets.

@oskarirauta
Last active April 5, 2024 07:09
Show Gist options
  • Save oskarirauta/3ca45fc058620363a8fb092687a2c412 to your computer and use it in GitHub Desktop.
Save oskarirauta/3ca45fc058620363a8fb092687a2c412 to your computer and use it in GitHub Desktop.
procd patches
--- a/jail/jail.c
+++ b/jail/jail.c
@@ -585,7 +585,7 @@ static struct mknod_args default_devices
{ .path = "/dev/full", .mode = (S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH), .dev = makedev(1, 7) },
{ .path = "/dev/random", .mode = (S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH), .dev = makedev(1, 8) },
{ .path = "/dev/urandom", .mode = (S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH), .dev = makedev(1, 9) },
- { .path = "/dev/tty", .mode = (S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP), .dev = makedev(5, 0), .gid = 5 },
+ { .path = "/dev/tty", .mode = (S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH), .dev = makedev(5, 0), .gid = 5 },
{ 0 },
};
--- a/uxc.c
+++ b/uxc.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sched.h>
#include <libubus.h>
#include <libubox/avl-cmp.h>
@@ -71,6 +72,7 @@ struct settings {
enum uxc_cmd {
CMD_ATTACH,
+ CMD_EXEC,
CMD_LIST,
CMD_BOOT,
CMD_START,
@@ -112,6 +114,7 @@ static int usage(void) {
printf("commands:\n");
printf("\tlist [--json]\t\t\t\tlist all configured containers\n");
printf("\tattach <conf>\t\t\t\tattach to container console\n");
+ printf("\texec <conf> [cmd]\t\t\texecute command or shell in container\n");
printf("\tcreate <conf>\t\t\t\t(re-)create <conf>\n");
printf("\t\t[--bundle <path>]\t\t\tOCI bundle at <path>\n");
printf("\t\t[--autostart]\t\t\t\tstart on boot\n");
@@ -150,6 +153,29 @@ static const struct blobmsg_policy conf_
[CONF_VOLUMES] = { .name = "volumes", .type = BLOBMSG_TYPE_ARRAY },
};
+static int open_ns(int pid, char *name) {
+
+ char *path;
+
+ if (asprintf(&path, "/proc/%d/%s", pid, name) == -1 ) {
+ fprintf(stderr, "cannot allocate path /proc/%d/%s\n", pid, name);
+ return -1;
+ }
+
+ struct stat st;
+ if (stat(path, &st) == 0 && S_ISLNK(st.st_mode)) {
+ fprintf(stderr, "file /proc/%d/%s does not exists or is not a symbolic link\n", pid, name);
+ return -1;
+ }
+
+ int fd = open(path, O_RDONLY);
+ if ( fd < 0 ) {
+ fprintf(stderr, "cannot open /proc/%d/%s\n", pid, name);
+ return fd;
+ }
+ return fd;
+}
+
static int conf_load(bool load_settings)
{
int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
@@ -613,6 +639,94 @@ static int uxc_attach(const char *contai
return 0;
}
+static int uxc_exec(const char *container_name, char **args)
+{
+ struct blob_attr *cur, *tb[__CONF_MAX], *ts[__STATE_MAX];
+ struct runtime_state *rsstate = NULL;
+ int rem, container_pid;
+ bool found = false;
+
+ blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
+ blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
+ if (!tb[CONF_NAME] || !tb[CONF_PATH])
+ continue;
+
+ if (strcmp(container_name, blobmsg_get_string(tb[CONF_NAME])))
+ continue;
+
+ found = true;
+ break;
+ }
+
+ if (!found)
+ return -ENOENT;
+
+ rsstate = avl_find_element(&runtime, container_name, rsstate, avl);
+ container_pid = 0;
+
+ if (rsstate && rsstate->ocistate) {
+ blobmsg_parse(state_policy, __STATE_MAX, ts, blobmsg_data(rsstate->ocistate), blobmsg_len(rsstate->ocistate));
+ container_pid = blobmsg_get_u32(ts[STATE_PID]);
+ }
+
+ if (container_pid < 2) {
+ fprintf(stderr, "failed to container pid for %s\n", container_name);
+ return -ENOENT;
+ }
+
+ int ns_ipc = open_ns(container_pid, "ns/ipc");
+ int ns_mnt = open_ns(container_pid, "ns/mnt");
+ int ns_net = open_ns(container_pid, "ns/net");
+ int ns_uts = open_ns(container_pid, "ns/uts");
+ int ns_pid = open_ns(container_pid, "ns/pid");
+ int ns_root = open_ns(container_pid, "root");
+
+ if (ns_ipc == -1 || ns_mnt == -1 || ns_net == -1 || ns_uts == -1 || ns_pid == -1 || ns_root == -1)
+ return -ENXIO;
+
+ if (setns(ns_ipc, 0) == -1) {
+ fprintf(stderr, "failed to enter ipc namespace\n");
+ return -ENXIO;
+ }
+
+ if (setns(ns_mnt, 0) == -1) {
+ fprintf(stderr, "failed to enter mnt namespace\n");
+ return -ENXIO;
+ }
+
+ if (setns(ns_net, 0) == -1) {
+ fprintf(stderr, "failed to enter net namespace\n");
+ return -ENXIO;
+ }
+
+ if (setns(ns_uts, 0) == -1) {
+ fprintf(stderr, "failed to enter uts namespace\n");
+ return -ENXIO;
+ }
+
+ if (setns(ns_pid, 0) == -1) {
+ fprintf(stderr, "failed to enter pid namespace\n");
+ return -ENXIO;
+ }
+
+ if (fchdir(ns_root) == -1) {
+ fprintf(stderr, "failed to change working directory\n");
+ return -ENXIO;
+ }
+
+ if (chroot(".") == -1) {
+ fprintf(stderr, "failed to chroot\n");
+ return -ENXIO;
+ }
+
+ if (execv(args[0], args) == -1) {
+ fprintf(stderr, "failed to execute %s in container %s\n", args[0], container_name);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
static int uxc_state(char *name)
{
struct runtime_state *rsstate = avl_find_element(&runtime, name, rsstate, avl);
@@ -1413,7 +1527,10 @@ int main(int argc, char **argv)
if (ret)
goto settings_avl_out;
- while (true) {
+ if ( argc > 1 && !strcmp("exec", argv[1]))
+ cmd = CMD_EXEC;
+
+ while (cmd != CMD_EXEC) {
int option_index = 0;
c = getopt_long(argc, argv, OPT_ARGS, long_options, &option_index);
if (c == -1)
@@ -1466,13 +1583,15 @@ int main(int argc, char **argv)
}
}
- if (optind == argc)
+ if (optind == argc && cmd != CMD_EXEC)
goto usage_out;
if (!strcmp("list", argv[optind]))
cmd = CMD_LIST;
else if (!strcmp("attach", argv[optind]))
cmd = CMD_ATTACH;
+ else if (!strcmp("exec", argv[optind]))
+ cmd = CMD_EXEC;
else if (!strcmp("boot", argv[optind]))
cmd = CMD_BOOT;
else if(!strcmp("start", argv[optind]))
@@ -1498,6 +1617,24 @@ int main(int argc, char **argv)
ret = uxc_attach(argv[optind + 1]);
break;
+ case CMD_EXEC:
+ if (argc < 3)
+ goto usage_out;
+
+ int i;
+ char *cmd = argc < 4 ? "/bin/sh" : argv[3];
+ int cnt = argc < 5 ? 2 : ( argc - 2 );
+ char **args = (char **)malloc(cnt * sizeof(char*));
+
+ if (argc > 3) {
+ for (i = 0; i < cnt - 1; i++ )
+ args[i] = argv[i + 3];
+ } else args[0] = cmd;
+
+ args[cnt - 1] = NULL;
+ ret = uxc_exec(argv[optind + 1], args);
+ break;
+
case CMD_LIST:
ret = uxc_list();
break;
--- a/uxc.c
+++ b/uxc.c
@@ -1598,13 +1598,13 @@ int main(int argc, char **argv)
cmd = CMD_START;
else if(!strcmp("state", argv[optind]))
cmd = CMD_STATE;
- else if(!strcmp("kill", argv[optind]))
+ else if(!strcmp("kill", argv[optind]) || !strcmp("stop", argv[optind]))
cmd = CMD_KILL;
else if(!strcmp("enable", argv[optind]))
cmd = CMD_ENABLE;
else if(!strcmp("disable", argv[optind]))
cmd = CMD_DISABLE;
- else if(!strcmp("delete", argv[optind]))
+ else if(!strcmp("delete", argv[optind]) || !strcmp("rm", argv[optind]))
cmd = CMD_DELETE;
else if(!strcmp("create", argv[optind]))
cmd = CMD_CREATE;
--- a/uxc.c
+++ b/uxc.c
@@ -82,6 +82,7 @@ enum uxc_cmd {
CMD_DISABLE,
CMD_DELETE,
CMD_CREATE,
+ CMD_RESTART,
CMD_UNKNOWN
};
@@ -124,6 +125,7 @@ static int usage(void) {
printf("\tstart [--console] <conf>\t\tstart container <conf>\n");
printf("\tstate <conf>\t\t\t\tget state of container <conf>\n");
printf("\tkill <conf> [<signal>]\t\t\tsend signal to container <conf>\n");
+ printf("\trestart [--console] <conf> [<signal>]\trestart container <conf>\n");
printf("\tenable <conf>\t\t\t\tstart container <conf> on boot\n");
printf("\tdisable <conf>\t\t\t\tdon't start container <conf> on boot\n");
printf("\tdelete <conf> [--force]\t\t\tdelete <conf>\n");
@@ -1600,6 +1602,8 @@ int main(int argc, char **argv)
cmd = CMD_STATE;
else if(!strcmp("kill", argv[optind]) || !strcmp("stop", argv[optind]))
cmd = CMD_KILL;
+ else if(!strcmp("restart", argv[optind]))
+ cmd = CMD_RESTART;
else if(!strcmp("enable", argv[optind]))
cmd = CMD_ENABLE;
else if(!strcmp("disable", argv[optind]))
@@ -1649,6 +1653,39 @@ int main(int argc, char **argv)
ret = uxc_start(argv[optind + 1], console);
break;
+
+ case CMD_RESTART:
+ if (optind == (argc - 3))
+ signal = atoi(argv[optind + 2]);
+ else if (optind != argc - 2)
+ goto usage_out;
+
+ uxc_kill(argv[optind + 1], signal);
+
+ runtime_free(); // poll runtime
+ sleep(1);
+ runtime_load();
+
+ ret = uxc_exists(argv[optind + 1]);
+ if (ret)
+ goto runtime_out;
+
+ ret = uxc_set(argv[optind + 1], bundle, autostart, pidfile, tmprwsize, writepath, requiredmounts);
+ if (ret < 0)
+ goto runtime_out;
+ else if (ret > 0)
+ reload_conf();
+
+ ret = uxc_create(argv[optind + 1], false);
+ if (ret != 0)
+ goto runtime_out;
+
+ runtime_free(); // poll runtime again
+ sleep(1);
+ runtime_load();
+
+ ret = uxc_start(argv[optind + 1], console);
+ break;
case CMD_STATE:
if (optind != argc - 2)
--- a/jail/jail.c
+++ b/jail/jail.c
@@ -322,7 +322,7 @@ static int mount_overlay(char *jail_root
fd = creat(upperresolvconf, 0644);
if (fd < 0) {
- if (errno != EEXIST)
+ if (errno != EEXIST && errno != ENOENT)
ERROR("creat(%s) failed: %m\n", upperresolvconf);
} else {
close(fd);
--- a/uxc.c
+++ b/uxc.c
@@ -67,6 +67,7 @@ struct settings {
char *tmprwsize;
char *writepath;
signed char autostart;
+ signed char no_resolv;
struct blob_attr *volumes;
};
@@ -86,7 +87,7 @@ enum uxc_cmd {
CMD_UNKNOWN
};
-#define OPT_ARGS "ab:fjm:p:t:vVw:"
+#define OPT_ARGS "ab:fjm:np:t:vVw:"
static struct option long_options[] = {
{"autostart", no_argument, 0, 'a' },
{"console", no_argument, 0, 'c' },
@@ -94,6 +95,7 @@ static struct option long_options[] = {
{"force", no_argument, 0, 'f' },
{"json", no_argument, 0, 'j' },
{"mounts", required_argument, 0, 'm' },
+ {"no-resolv", no_argument, 0, 'n' },
{"pid-file", required_argument, 0, 'p' },
{"temp-overlay-size", required_argument, 0, 't' },
{"write-overlay-path", required_argument, 0, 'w' },
@@ -122,6 +124,7 @@ static int usage(void) {
printf("\t\t[--temp-overlay-size <size>]\t\tuse tmpfs overlay with {size}\n");
printf("\t\t[--write-overlay-path <path>]\t\tuse overlay on {path}\n");
printf("\t\t[--mounts <v1>,<v2>,...,<vN>]\t\trequire filesystems to be available\n");
+ printf("\t\t[--no-resolv]\t\t\t\tskip resolv.conf auto-generation\n");
printf("\tstart [--console] <conf>\t\tstart container <conf>\n");
printf("\tstate <conf>\t\t\t\tget state of container <conf>\n");
printf("\tkill <conf> [<signal>]\t\t\tsend signal to container <conf>\n");
@@ -140,6 +143,7 @@ enum {
CONF_PIDFILE,
CONF_TEMP_OVERLAY_SIZE,
CONF_WRITE_OVERLAY_PATH,
+ CONF_NO_RESOLV,
CONF_VOLUMES,
__CONF_MAX,
};
@@ -152,6 +156,7 @@ static const struct blobmsg_policy conf_
[CONF_PIDFILE] = { .name = "pidfile", .type = BLOBMSG_TYPE_STRING },
[CONF_TEMP_OVERLAY_SIZE] = { .name = "temp-overlay-size", .type = BLOBMSG_TYPE_STRING },
[CONF_WRITE_OVERLAY_PATH] = { .name = "write-overlay-path", .type = BLOBMSG_TYPE_STRING },
+ [CONF_NO_RESOLV] = { .name = "no-resolv", .type = BLOBMSG_TYPE_BOOL },
[CONF_VOLUMES] = { .name = "volumes", .type = BLOBMSG_TYPE_ARRAY },
};
@@ -238,6 +243,7 @@ settings_alloc(const char *container_nam
s->container_name = new_name;
s->avl.key = s->container_name;
s->autostart = -1;
+ s->no_resolv = -1;
s->tmprwsize = NULL;
s->writepath = NULL;
s->volumes = NULL;
@@ -271,6 +277,9 @@ static int settings_add(void)
if (tb[CONF_WRITE_OVERLAY_PATH])
s->writepath = blobmsg_get_string(tb[CONF_WRITE_OVERLAY_PATH]);
+ if (tb[CONF_NO_RESOLV])
+ s->no_resolv = blobmsg_get_bool(tb[CONF_NO_RESOLV]);
+
s->volumes = tb[CONF_VOLUMES];
s->fname = blobmsg_name(cur);
@@ -801,7 +810,7 @@ static int uxc_list(void)
struct settings *usettings = NULL;
char *name, *ocistatus, *status, *tmp;
int container_pid = -1;
- bool autostart;
+ bool autostart, no_resolv;
static struct blob_buf buf;
void *arr, *obj;
@@ -816,6 +825,7 @@ static int uxc_list(void)
continue;
autostart = tb[CONF_AUTOSTART] && blobmsg_get_bool(tb[CONF_AUTOSTART]);
+ no_resolv = tb[CONF_NO_RESOLV] && blobmsg_get_bool(tb[CONF_NO_RESOLV]);
ocistatus = NULL;
container_pid = 0;
@@ -840,6 +850,7 @@ static int uxc_list(void)
blobmsg_add_string(&buf, "name", name);
blobmsg_add_string(&buf, "status", status);
blobmsg_add_u8(&buf, "autostart", autostart);
+ blobmsg_add_u8(&buf, "no-resolv", no_resolv);
} else {
printf("[%c] %s %s", autostart?'*':' ', name, status);
}
@@ -905,6 +916,7 @@ static int uxc_create(char *name, bool i
uint32_t id;
struct settings *usettings = NULL;
char *path = NULL, *jailname = NULL, *pidfile = NULL, *tmprwsize = NULL, *writepath = NULL;
+ bool no_resolv = false;
void *in, *ins, *j;
bool found = false;
@@ -935,6 +947,9 @@ static int uxc_create(char *name, bool i
if (tb[CONF_WRITE_OVERLAY_PATH])
writepath = blobmsg_get_string(tb[CONF_WRITE_OVERLAY_PATH]);
+ if (tb[CONF_NO_RESOLV])
+ no_resolv = blobmsg_get_bool(tb[CONF_NO_RESOLV]);
+
if (tb[CONF_JAIL])
jailname = blobmsg_get_string(tb[CONF_JAIL]);
@@ -948,6 +963,8 @@ static int uxc_create(char *name, bool i
tmprwsize = usettings->tmprwsize;
writepath = NULL;
}
+ if (usettings->no_resolv)
+ no_resolv = usettings->no_resolv;
}
blob_buf_init(&req, 0);
@@ -970,6 +987,9 @@ static int uxc_create(char *name, bool i
if (tmprwsize)
blobmsg_add_string(&req, "tmpoverlaysize", tmprwsize);
+ if (no_resolv)
+ blobmsg_add_u8(&req, "no-resolv", !!no_resolv);
+
blobmsg_close_table(&req, in);
blobmsg_close_table(&req, ins);
@@ -1063,7 +1083,7 @@ static int uxc_kill(char *name, int sign
}
-static int uxc_set(char *name, char *path, signed char autostart, char *pidfile, char *tmprwsize, char *writepath, char *requiredmounts)
+static int uxc_set(char *name, char *path, signed char autostart, signed char no_resolv, char *pidfile, char *tmprwsize, char *writepath, char *requiredmounts)
{
static struct blob_buf req;
struct settings *usettings = NULL;
@@ -1125,6 +1145,8 @@ static int uxc_set(char *name, char *pat
}
if (usettings->autostart >= 0 && autostart < 0)
autostart = !!(usettings->autostart);
+ if (usettings->no_resolv >= 0 && no_resolv < 0)
+ no_resolv = !!(usettings->no_resolv);
}
if (path) {
@@ -1204,6 +1226,9 @@ static int uxc_set(char *name, char *pat
blobmsg_close_array(&req, mntarr);
}
+ if (no_resolv >= 0)
+ blobmsg_add_u8(&req, "no-resolv", !!no_resolv);
+
tmp = blobmsg_format_json_indent(req.head, true, 0);
if (tmp) {
dprintf(f, "%s\n", tmp);
@@ -1501,6 +1526,7 @@ int main(int argc, char **argv)
char *writepath = NULL;
char *requiredmounts = NULL;
signed char autostart = -1;
+ signed char no_resolv = -1;
bool force = false;
bool console = false;
int signal = SIGTERM;
@@ -1582,6 +1608,10 @@ int main(int argc, char **argv)
case 'm':
requiredmounts = optarg;
break;
+
+ case 'n':
+ no_resolv = 1;
+ break;
}
}
@@ -1670,7 +1700,7 @@ int main(int argc, char **argv)
if (ret)
goto runtime_out;
- ret = uxc_set(argv[optind + 1], bundle, autostart, pidfile, tmprwsize, writepath, requiredmounts);
+ ret = uxc_set(argv[optind + 1], bundle, autostart, -1, pidfile, tmprwsize, writepath, requiredmounts);
if (ret < 0)
goto runtime_out;
else if (ret > 0)
@@ -1707,14 +1737,14 @@ int main(int argc, char **argv)
if (optind != argc - 2)
goto usage_out;
- ret = uxc_set(argv[optind + 1], NULL, 1, NULL, NULL, NULL, NULL);
+ ret = uxc_set(argv[optind + 1], NULL, 1, -1, NULL, NULL, NULL, NULL);
break;
case CMD_DISABLE:
if (optind != argc - 2)
goto usage_out;
- ret = uxc_set(argv[optind + 1], NULL, 0, NULL, NULL, NULL, NULL);
+ ret = uxc_set(argv[optind + 1], NULL, 0, -1, NULL, NULL, NULL, NULL);
break;
case CMD_DELETE:
@@ -1732,7 +1762,7 @@ int main(int argc, char **argv)
if (ret)
goto runtime_out;
- ret = uxc_set(argv[optind + 1], bundle, autostart, pidfile, tmprwsize, writepath, requiredmounts);
+ ret = uxc_set(argv[optind + 1], bundle, autostart, no_resolv, pidfile, tmprwsize, writepath, requiredmounts);
if (ret < 0)
goto runtime_out;
--- a/jail/jail.c
+++ b/jail/jail.c
@@ -69,7 +69,7 @@
#endif
#define STACK_SIZE (1024 * 1024)
-#define OPT_ARGS "cC:d:e:EfFG:h:ij:J:ln:NoO:pP:r:R:sS:uU:w:t:T:y"
+#define OPT_ARGS "cC:Dd:e:EfFG:h:ij:J:ln:NoO:pP:r:R:sS:uU:w:t:T:y"
#define OCI_VERSION_STRING "1.0.2"
@@ -154,6 +154,7 @@ static struct {
bool immediately;
struct blob_attr *annotations;
int term_timeout;
+ bool no_resolv;
} opts;
static struct blob_buf ocibuf;
@@ -285,7 +286,7 @@ static void free_opts(bool parent) {
free_hooklist(opts.hooks.poststop);
}
-static int mount_overlay(char *jail_root, char *overlaydir) {
+static int mount_overlay(char *jail_root, char *overlaydir, bool no_resolv) {
char *upperdir, *workdir, *optsstr, *upperetc, *upperresolvconf;
const char mountoptsformat[] = "lowerdir=%s,upperdir=%s,workdir=%s";
int ret = -1, fd;
@@ -317,7 +318,7 @@ static int mount_overlay(char *jail_root
if (mkdir_p(upperetc, 0755))
goto upper_etc_printf;
- if (asprintf(&upperresolvconf, "%s/resolv.conf", upperetc) < 0)
+ if (no_resolv || asprintf(&upperresolvconf, "%s/resolv.conf", upperetc) < 0)
goto upper_etc_printf;
fd = creat(upperresolvconf, 0644);
@@ -732,7 +733,7 @@ static int build_jail_fs(void)
overlaydir = opts.overlaydir;
if (overlaydir) {
- ret = mount_overlay(jail_root, overlaydir);
+ ret = mount_overlay(jail_root, overlaydir, opts.no_resolv);
if (ret)
return ret;
}
@@ -751,7 +752,7 @@ static int build_jail_fs(void)
create_dev_console(jail_root);
/* make sure /etc/resolv.conf exists if in new network namespace */
- if (opts.namespace & CLONE_NEWNET) {
+ if (!opts.no_resolv && opts.namespace & CLONE_NEWNET) {
char jailetc[PATH_MAX], jaillink[PATH_MAX];
snprintf(jailetc, PATH_MAX, "%s/etc", jail_root);
@@ -1020,7 +1021,7 @@ static void usage(void)
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, " -o\t\tremount jail root (/) read only\n");
fprintf(stderr, " -R <dir>\texternal jail rootfs (system container)\n");
fprintf(stderr, " -O <dir>\tdirectory for r/w overlayfs\n");
fprintf(stderr, " -T <size>\tuse tmpfs r/w overlayfs with <size>\n");
@@ -1029,6 +1030,7 @@ static void usage(void)
fprintf(stderr, " -J <dir>\tcreate container from OCI bundle\n");
fprintf(stderr, " -i\t\tstart container immediately\n");
fprintf(stderr, " -P <pidfile>\tcreate <pidfile>\n");
+ fprintf(stderr, " -D\t\tignore resolv.conf setup\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\
thus he can escape the jail and/or break stuff.\n\
@@ -2612,6 +2614,8 @@ int main(int argc, char **argv)
/* default 5 seconds timeout after SIGTERM before SIGKILL is sent */
opts.term_timeout = 5;
+ opts.no_resolv = false;
+
umask(022);
mount_list_init();
init_library_search();
@@ -2730,6 +2734,9 @@ int main(int argc, char **argv)
case 'P':
opts.pidfile = optarg;
break;
+ case 'D':
+ opts.no_resolv = true;
+ break;
}
}
@@ -2944,7 +2951,7 @@ static void post_main(struct uloop_timeo
if (!opts.extroot)
add_mount_bind("/etc/nsswitch.conf", 1, -1);
#endif
- if (opts.setns.ns == -1) {
+ if (!opts.no_resolv && opts.setns.ns == -1) {
if (!(opts.namespace & CLONE_NEWNET)) {
add_mount_bind("/etc/resolv.conf", 1, 0);
} else {
--- a/service/instance.c
+++ b/service/instance.c
@@ -69,6 +69,7 @@ enum {
INSTANCE_ATTR_TMPOVERLAYSIZE,
INSTANCE_ATTR_BUNDLE,
INSTANCE_ATTR_WATCHDOG,
+ INSTANCE_ATTR_NO_RESOLV,
__INSTANCE_ATTR_MAX
};
@@ -102,6 +103,7 @@ static const struct blobmsg_policy insta
[INSTANCE_ATTR_TMPOVERLAYSIZE] = { "tmpoverlaysize", BLOBMSG_TYPE_STRING },
[INSTANCE_ATTR_BUNDLE] = { "bundle", BLOBMSG_TYPE_STRING },
[INSTANCE_ATTR_WATCHDOG] = { "watchdog", BLOBMSG_TYPE_ARRAY },
+ [INSTANCE_ATTR_NO_RESOLV] = { "no-resolv", BLOBMSG_TYPE_BOOL },
};
enum {
@@ -392,6 +394,9 @@ jail_run(struct service_instance *in, ch
if (in->require_jail)
argv[argc++] = "-E";
+ if (in->no_resolv)
+ argv[argc++] = "-D";
+
blobmsg_list_for_each(&in->env, var) {
argv[argc++] = "-e";
argv[argc++] = (char *) blobmsg_name(var->data);
@@ -1014,6 +1019,9 @@ instance_config_changed(struct service_i
if (in->no_new_privs != in_new->no_new_privs)
return true;
+ if (in->no_resolv != in_new->no_resolv)
+ return true;
+
if (string_changed(in->jail.name, in_new->jail.name))
return true;
@@ -1261,6 +1269,9 @@ instance_jail_parse(struct service_insta
if (in->no_new_privs)
jail->argc++;
+ if (in->no_resolv)
+ jail->argc++;
+
if (in->bundle)
jail->argc += 2;
@@ -1369,6 +1380,9 @@ instance_config_parse(struct service_ins
if (tb[INSTANCE_ATTR_NO_NEW_PRIVS])
in->no_new_privs = blobmsg_get_bool(tb[INSTANCE_ATTR_NO_NEW_PRIVS]);
+ if (tb[INSTANCE_ATTR_NO_RESOLV])
+ in->no_resolv = blobmsg_get_bool(tb[INSTANCE_ATTR_NO_RESOLV]);
+
if (!in->trace && tb[INSTANCE_ATTR_SECCOMP])
in->seccomp = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP]));
@@ -1534,6 +1548,7 @@ instance_config_move(struct service_inst
in->require_jail = in_src->require_jail;
in->no_new_privs = in_src->no_new_privs;
in->immediately = in_src->immediately;
+ in->no_resolv = in_src->no_resolv;
in->uid = in_src->uid;
in->pw_gid = in_src->pw_gid;
in->gr_gid = in_src->gr_gid;
@@ -1733,6 +1748,9 @@ void instance_dump(struct blob_buf *b, s
if (in->no_new_privs)
blobmsg_add_u8(b, "no_new_privs", true);
+ if (in->no_resolv)
+ blobmsg_add_u8(b, "no_resolv", true);
+
if (in->seccomp)
blobmsg_add_string(b, "seccomp", in->seccomp);
--- a/service/instance.h
+++ b/service/instance.h
@@ -88,6 +88,7 @@ struct service_instance {
char *overlaydir;
char *tmpoverlaysize;
char *bundle;
+ bool no_resolv;
int syslog_facility;
int exit_code;
#!/bin/sh
[ -n "$INCLUDE_ONLY" ] || {
. /lib/functions.sh
. ../netifd-proto.sh
init_proto "$@"
}
proto_infra_init_config() {
no_device=1
available=1
proto_config_add_string "device:device"
proto_config_add_string "namespace"
proto_config_add_string "ipaddr"
proto_config_add_string "netmask"
proto_config_add_string "gateway"
proto_config_add_string "script"
proto_config_add_string "args"
}
find_pid() {
local cfg="$1"
local token ns pid
for token in $(pidof catatonit); do
ns=$(cat /proc/$token/environ | tr '\0' '\n'|grep NAMESPACE|cut -d'=' -f2)
[ "$ns" = "$cfg" ] &&
pid="$token"
done
echo $pid
}
proto_infra_setup() {
local cfg="$1"
local iface namespace ipaddr netmask mask gateway script args
local pid=$(find_pid "$cfg")
json_get_var iface "device"
json_get_vars namespace ipaddr netmask gateway script args
[ -z "$iface" ] &&
iface="$cfg"
[ -z "$ipaddr" ] && {
echo "ip address not set for $cfg"
proto_notify_error "$cfg" "NO_IP_ADDRESS"
return 1
}
[ -z "$namespace" ] && {
echo "namespace not set for $cfg"
proto_notify_error "$cfg" "NO_NAMESPACE_SET"
return 1
}
mask="$netmask"
[ $(echo "$netmask" | cut -c1-1) = "/" ] ||
mask=$(/bin/ipcalc.sh "$ipaddr" "$netmask" | grep PREFIX | cut -d'=' -f2)
[ -z "$mask" ] && {
echo "invalid netmask for $cfg"
proto_notify_error "$cfg" "INVAlID_NETMASK"
return 1
}
[ -z "$pid" ] && {
proto_export NAMESPACE="$cfg"
proto_run_command "$cfg" "/usr/bin/unshare" -u -i -n -U -C "/usr/bin/catatonit" -P
pid=$(find_pid "$cfg")
}
[ -z "$pid" ] && {
echo "catatonit pid for namespace $cfg was not found, catatonit not running?"
proto_notify_error "$cfg" "PID_NOT_FOUND"
return 1
}
proto_init_update "$iface" 1
proto_add_ipv4_address $ipaddr $mask
proto_add_data
json_add_string "pid" "$pid"
json_add_string "namespace" "$namespace"
proto_close_data
proto_send_update "$cfg"
[ -z $(ip netns list | grep "$namespace") ] ||
ip netns delete "$namespace"
ip netns attach "$namespace" "$pid"
ip link set "$iface" netns "$namespace"
ip -n "$namespace" addr add "${ipaddr}/${mask}" dev "$iface"
ip -n "$namespace" link set dev lo up
ip -n "$namespace" link set dev "$iface" up
[ -n "$gateway" ] &&
ip -n "$namespace" route add default via "$gateway"
[ -n "$script" -a -x "$script" ] && {
interface="$iface" \
pid="$pid" \
ipaddr="$ipaddr" \
netmask="$netmask" \
mask="$mask" \
gateway="$gateway" \
namespace="$namespace" \
$script "$cfg" $args
} || {
[ -n "$script" ] &&
echo "post setup script $script for $cfg does not exist or is not executable"
}
}
proto_infra_teardown() {
local cfg="$1"
return 0
}
[ -n "$INCLUDE_ONLY" ] || {
add_protocol infra
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment