cmdline: add option --execute_fd and support for it, in order to use execveat()

This commit is contained in:
Robert Swiecki 2017-10-18 17:57:52 +02:00
parent 5ef11f65a4
commit 9c2f19b972
6 changed files with 90 additions and 5 deletions

View File

@ -36,6 +36,8 @@
#include <strings.h>
#include <sys/mount.h>
#include <sys/personality.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
@ -63,6 +65,7 @@ struct custom_option custom_opts[] = {
"\tr: Launch a single process on the console with clone/execve, keep doing it forever [MODE_STANDALONE_RERUN]" },
{ { "config", required_argument, NULL, 'C' }, "Configuration file in the config.proto ProtoBuf format (see configs/ directory for examples)" },
{ { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" },
{ { "execute_fd", no_argument, NULL, 0x0607 }, "Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing" },
{ { "chroot", required_argument, NULL, 'c' }, "Directory containing / of the jail (default: none)" },
{ { "rw", no_argument, NULL, 0x601 }, "Mount chroot dir (/) R/W (default: R/O)" },
{ { "user", required_argument, NULL, 'u' }, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times" },
@ -312,10 +315,12 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf)
{
(*nsjconf) = (const struct nsjconf_t){
.exec_file = NULL,
.use_execveat = false,
.exec_fd = -1,
.argv = NULL,
.hostname = "NSJAIL",
.cwd = "/",
.chroot = NULL,
.argv = NULL,
.port = 0,
.bindhost = "::",
.log_fd = STDERR_FILENO,
@ -556,7 +561,7 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf)
case 0x0508:
nsjconf->max_cpus = strtoul(optarg, NULL, 0);
break;
case 0x509: {
case 0x0509: {
struct ints_t* f = utilMalloc(sizeof(struct ints_t));
f->val = capsNameToVal(optarg);
if (f->val == -1) {
@ -581,6 +586,9 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf)
case 0x0606:
nsjconf->is_proc_rw = true;
break;
case 0x0607:
nsjconf->use_execveat = true;
break;
case 'E': {
struct charptr_t* p = utilMalloc(sizeof(struct charptr_t));
p->val = optarg;
@ -799,5 +807,18 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf)
nsjconf->exec_file = nsjconf->argv[0];
}
if (nsjconf->use_execveat) {
#if !defined(__NR_execveat)
LOG_E("Your nsjail is compiled without support for the execveat() syscall, yet you "
"specified --execute_fd flag");
return false;
#endif /* !defined(__NR_execveat) */
if ((nsjconf->exec_fd = open(nsjconf->exec_file, O_RDONLY | O_PATH | O_CLOEXEC))
== -1) {
PLOG_W("Couldn't open '%s' file", nsjconf->exec_file);
return false;
}
}
return true;
}

View File

@ -296,6 +296,7 @@ static bool configParseInternal(struct nsjconf_t* nsjconf, const nsjail::NsJailC
argv.push_back(nullptr);
nsjconf->exec_file = DUP_IF_SET(njc.exec_bin(), path);
nsjconf->argv = argv.data();
nsjconf->use_execveat = njc.exec_bin().exec_fd();
}
return true;

View File

@ -68,6 +68,8 @@ message Exe
repeated string arg = 2;
/* Override argv[0] */
optional string arg0 = 3;
/* Should execveat() be used to execute a file-descriptor instead? */
optional bool exec_fd = 4 [ default = false ];
}
message NsJailConfig
{

View File

@ -0,0 +1,48 @@
name: "busybox-with-execveat"
description: "An example/demo policy which allows to execute /bin/busybox in an empty (only /proc) "
description: "mount namespace which doesn't even include busybox itself."
mode: ONCE
hostname: "BUSYBOX"
cwd: "/"
time_limit: 100
keep_env: false
envar: "TERM=linux"
envar: "PS1=$ "
skip_setsid: true
clone_newcgroup: true
uidmap {
inside_id: "999999"
outside_id: ""
count: 1
}
gidmap {
inside_id: "999999"
outside_id: ""
count: 1
}
mount_proc: false
mount {
dst: "/proc"
fstype: "proc"
rw: false
}
seccomp_string: "POLICY example { "
seccomp_string: " ERRNO(0) { ptrace } "
seccomp_string: "} "
seccomp_string: "USE example DEFAULT ALLOW"
exec_bin {
path: "/bin/busybox"
arg: "sh"
exec_fd: true
}

View File

@ -105,9 +105,12 @@ enum llevel_t {
struct nsjconf_t {
const char* exec_file;
bool use_execveat;
int exec_fd;
const char** argv;
const char* hostname;
const char* cwd;
const char** argv;
const char* chroot;
int port;
const char* bindhost;
int log_fd;
@ -135,7 +138,6 @@ struct nsjconf_t {
bool clone_newuts;
bool clone_newcgroup;
enum ns_mode_t mode;
const char* chroot;
bool is_root_rw;
bool is_silent;
bool skip_setsid;

View File

@ -36,6 +36,7 @@
#include <string.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
@ -170,7 +171,17 @@ static int subprocNewProc(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int
if (sandboxApply(nsjconf) == false) {
exit(0xff);
}
if (nsjconf->use_execveat) {
#if defined(__NR_execveat)
syscall(__NR_execveat, (uintptr_t)nsjconf->exec_fd, "",
(char* const*)&nsjconf->argv[0], environ, (uintptr_t)AT_EMPTY_PATH);
#else /* defined(__NR_execveat) */
LOG_F("Your system doesn't support execveat() syscall");
#endif /* defined(__NR_execveat) */
} else {
execv(nsjconf->exec_file, (char* const*)&nsjconf->argv[0]);
}
PLOG_E("execve('%s') failed", nsjconf->exec_file);