Use common subprocSystem for executing commands

This commit is contained in:
Robert Swiecki 2016-10-12 02:01:12 +02:00
parent a30e2f107c
commit fe7fe8591f
4 changed files with 115 additions and 91 deletions

50
net.c
View File

@ -42,6 +42,7 @@
#include <unistd.h>
#include "log.h"
#include "subproc.h"
#define IFACE_NAME "vs"
@ -114,51 +115,15 @@ bool netInitNsFromParent(struct nsjconf_t *nsjconf, int pid)
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;
@ -171,7 +136,8 @@ bool netInitNsFromParent(struct nsjconf_t *nsjconf, int pid)
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) {

View File

@ -352,3 +352,68 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
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);
}
}

View File

@ -28,6 +28,7 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
int subprocCount(struct nsjconf_t *nsjconf);
void subprocDisplay(struct nsjconf_t *nsjconf);
void subprocKillAll(struct nsjconf_t *nsjconf);
int subprocSystem(const char **argv, char **env);
/* Returns the exit code of the first failing subprocess, or 0 if none fail */
int subprocReap(struct nsjconf_t *nsjconf);

90
user.c
View File

@ -32,6 +32,7 @@
#include <unistd.h>
#include "log.h"
#include "subproc.h"
#include "util.h"
static bool userSetGroups(pid_t pid)
@ -87,79 +88,70 @@ static bool userGidMapSelf(struct nsjconf_t *nsjconf, 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;
char pid_str[16];
char ins_gid_str[16];
char out_gid_str[16];
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;
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;
}
if (system(cmd_buf) != 0) {
LOG_E("system('%s') failed", cmd_buf);
while (1) ;
argv[argv_idx++] = p->inside_id;
argv[argv_idx++] = p->outside_id;
argv[argv_idx++] = p->count;
}
argv[argv_idx++] = NULL;
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;
char pid_str[16];
char ins_uid_str[16];
char out_uid_str[16];
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;
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;
}
if (system(cmd_buf) != 0) {
LOG_E("system('%s') failed", cmd_buf);
argv[argv_idx++] = p->inside_id;
argv[argv_idx++] = p->outside_id;
argv[argv_idx++] = p->count;
}
argv[argv_idx++] = NULL;
if (subprocSystem(argv, environ) != 0) {
LOG_E("'/usr/bin/newuidmap' failed");
return false;
}