#include <unistd.h>
#include "log.h"
+#include "subproc.h"
#define IFACE_NAME "vs"
return true;
}
#else // defined(NSJAIL_NL3_WITH_MACVLAN)
-static bool netSystemSbinIp(struct nsjconf_t *nsjconf, char *const *argv)
+static bool netSystemSbinIp(struct nsjconf_t *nsjconf, const char *const *argv)
{
- if (nsjconf->clone_newnet == false) {
- LOG_W
- ("CLONE_NEWNET not enabled. All changes would affect the global networking namespace");
- return false;
- }
-
- int pid = fork();
- if (pid == -1) {
- PLOG_E("fork()");
- return false;
- }
- if (pid == 0) {
- execve("/sbin/ip", argv, environ);
- PLOG_E("execve('/sbin/ip'");
- _exit(1);
- }
-
- for (;;) {
- int status;
- while (wait4(pid, &status, __WALL, NULL) != pid) ;
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) == 0) {
- return true;
- }
- LOG_W("'/sbin/ip' returned with exit status: %d", WEXITSTATUS(status));
- return false;
- }
- if (WIFSIGNALED(status)) {
- LOG_W("'/sbin/ip' killed with signal: %d", WTERMSIG(status));
- return false;
- }
- if (WIFSTOPPED(status)) {
- continue;
- }
- if (WIFCONTINUED(status)) {
- continue;
- }
- LOG_W("Unknown exit status for '/sbin/ip' (pid=%d): %d", pid, status);
- kill(pid, SIGKILL);
+ if (subprocSystem(argv, environ) == 0) {
+ return true;
}
+ return false;
}
-bool netInitNsFromParent(struct nsjconf_t *nsjconf, int pid)
+bool netInitNsFromParent(struct nsjconf_t * nsjconf, int pid)
{
if (nsjconf->clone_newnet == false) {
return true;
snprintf(pid_str, sizeof(pid_str), "%d", pid);
char *const argv_add[] =
- { "ip", "link", "add", "link", (char *)nsjconf->iface, "name", IFACE_NAME, "netns",
+ { "/sbin/ip", "link", "add", "link", (char *)nsjconf->iface, "name", IFACE_NAME,
+ "netns",
pid_str, "type", "macvlan", "mode", "bridge", NULL
};
if (netSystemSbinIp(nsjconf, argv_add) == false) {
netConnToText(fd_in, true /* remote */ , cs_addr, sizeof(cs_addr), NULL);
LOG_I("PID: %d about to execute '%s' for %s", pid, nsjconf->argv[0], cs_addr);
}
+
+int subprocSystem(const char **argv, char **env)
+{
+ bool exec_failed = false;
+
+ int sv[2];
+ if (pipe2(sv, O_CLOEXEC) == -1) {
+ PLOG_W("pipe2(sv, O_CLOEXEC");
+ return -1;
+ }
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ PLOG_W("fork()");
+ close(sv[0]);
+ close(sv[1]);
+ return -1;
+ }
+
+ if (pid == 0) {
+ close(sv[0]);
+ execve(argv[0], (char *const *)argv, (char *const *)env);
+ PLOG_W("execve('%s')", argv[0]);
+ utilWriteToFd(sv[1], "A", 1);
+ exit(0);
+ }
+
+ close(sv[1]);
+ char buf[1];
+ if (utilReadFromFd(sv[0], buf, sizeof(buf)) > 0) {
+ exec_failed = true;
+ LOG_W("Couldn't execute '%s'", argv[0]);
+ }
+ close(sv[0]);
+
+ for (;;) {
+ int status;
+ int ret = wait4(pid, &status, __WALL, NULL);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ }
+ if (ret == -1) {
+ PLOG_W("wait4(pid=%d)", pid);
+ return -1;
+ }
+ if (WIFEXITED(status)) {
+ int exit_code = WEXITSTATUS(status);
+ LOG_D("PID %d exited with exit code: %d", pid, exit_code);
+ if (exec_failed == true) {
+ return -1;
+ } else if (exit_code == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ if (WIFSIGNALED(status)) {
+ int exit_signal = WTERMSIG(status);
+ LOG_W("PID %d killed by a signal: %d (%s)", pid, exit_signal,
+ strsignal(exit_signal));
+ return 2;
+ }
+ LOG_W("Unknown exit status: %d", status);
+ }
+}
#include <unistd.h>
#include "log.h"
+#include "subproc.h"
#include "util.h"
static bool userSetGroups(pid_t pid)
return true;
}
-// use /usr/bin/newgidmap for writing the uid and gid map
+/* Use /usr/bin/newgidmap for writing the gid map */
static bool userGidMapExternal(struct nsjconf_t *nsjconf, pid_t pid)
{
- char cmd_buf[1024];
- char *cmd_ptr = cmd_buf;
- size_t len = sizeof(cmd_buf);
- int write_size;
-
- write_size = snprintf(cmd_ptr, len, "/usr/bin/newgidmap %lu %lu %lu 1",
- (unsigned long)pid,
- (unsigned long)nsjconf->inside_gid,
- (unsigned long)nsjconf->outside_gid);
- if (write_size <= 0 || (size_t) write_size > len) {
- LOG_E("snprintf writing the new{u,g}idmap command failed");
- return false;
- }
- cmd_ptr += write_size;
- len -= write_size;
+ char pid_str[16];
+ char ins_gid_str[16];
+ char out_gid_str[16];
+
+ snprintf(pid_str, sizeof(pid_str), "%lu", (unsigned long)pid);
+ snprintf(ins_gid_str, sizeof(ins_gid_str), "%lu", (unsigned long)nsjconf->inside_gid);
+ snprintf(out_gid_str, sizeof(out_gid_str), "%lu", (unsigned long)nsjconf->outside_gid);
+
+ const char *argv[1024] = { "/usr/bin/newgidmap", pid_str, ins_gid_str, out_gid_str, "1" };
+ size_t argv_idx = 5;
struct mapping_t *p;
TAILQ_FOREACH(p, &nsjconf->gid_mappings, pointers) {
- write_size = snprintf(cmd_ptr, len, " %s %s %s",
- p->inside_id, p->outside_id, p->count);
- if (write_size <= 0 || (size_t) write_size > len) {
- LOG_E("snprintf writing the new{u,g}idmap command failed");
+ if ((argv_idx + 4) >= ARRAYSIZE(argv)) {
+ LOG_W("Number of arguments to '/usr/bin/newgidmap' too big");
return false;
}
- cmd_ptr += write_size;
- len -= write_size;
+
+ argv[argv_idx++] = p->inside_id;
+ argv[argv_idx++] = p->outside_id;
+ argv[argv_idx++] = p->count;
}
+ argv[argv_idx++] = NULL;
- if (system(cmd_buf) != 0) {
- LOG_E("system('%s') failed", cmd_buf);
- while (1) ;
+ if (subprocSystem(argv, environ) != 0) {
+ LOG_E("'/usr/bin/newgidmap' failed");
return false;
}
return true;
}
-// use /usr/bin/newuidmap for writing the uid and gid map
+/* Use /usr/bin/newuidmap for writing the uid map */
static bool userUidMapExternal(struct nsjconf_t *nsjconf, pid_t pid)
{
- char cmd_buf[1024];
- char *cmd_ptr = cmd_buf;
- size_t len = sizeof(cmd_buf);
- int write_size;
-
- write_size = snprintf(cmd_ptr, len, "/usr/bin/newuidmap %lu %lu %lu 1",
- (unsigned long)pid,
- (unsigned long)nsjconf->inside_uid,
- (unsigned long)nsjconf->outside_uid);
- if (write_size <= 0 || (size_t) write_size > len) {
- LOG_E("snprintf writing the new{u,g}idmap command failed");
- return false;
- }
- cmd_ptr += write_size;
- len -= write_size;
+ char pid_str[16];
+ char ins_uid_str[16];
+ char out_uid_str[16];
+
+ snprintf(pid_str, sizeof(pid_str), "%lu", (unsigned long)pid);
+ snprintf(ins_uid_str, sizeof(ins_uid_str), "%lu", (unsigned long)nsjconf->inside_uid);
+ snprintf(out_uid_str, sizeof(out_uid_str), "%lu", (unsigned long)nsjconf->outside_uid);
+
+ const char *argv[1024] = { "/usr/bin/newuidmap", pid_str, ins_uid_str, out_uid_str, "1" };
+ size_t argv_idx = 5;
struct mapping_t *p;
TAILQ_FOREACH(p, &nsjconf->uid_mappings, pointers) {
- write_size = snprintf(cmd_ptr, len, " %s %s %s",
- p->inside_id, p->outside_id, p->count);
- if (write_size <= 0 || (size_t) write_size > len) {
- LOG_E("snprintf writing the new{u,g}idmap command failed");
+ if ((argv_idx + 4) >= ARRAYSIZE(argv)) {
+ LOG_W("Number of arguments to '/usr/bin/newuidmap' too big");
return false;
}
- cmd_ptr += write_size;
- len -= write_size;
+
+ argv[argv_idx++] = p->inside_id;
+ argv[argv_idx++] = p->outside_id;
+ argv[argv_idx++] = p->count;
}
+ argv[argv_idx++] = NULL;
- if (system(cmd_buf) != 0) {
- LOG_E("system('%s') failed", cmd_buf);
+ if (subprocSystem(argv, environ) != 0) {
+ LOG_E("'/usr/bin/newuidmap' failed");
return false;
}