caps: just local caps

This commit is contained in:
Robert Swiecki 2017-07-05 17:29:57 +02:00
parent 54a522326f
commit 39ce9d22a7
9 changed files with 25 additions and 64 deletions

27
caps.c
View File

@ -150,15 +150,12 @@ static void capsClrFlag(cap_t cap, cap_value_t id, cap_value_t type)
}
}
bool capsInitInternal(struct nsjconf_t *nsjconf, bool is_global)
bool capsInitNs(struct nsjconf_t *nsjconf)
{
cap_t cap_orig = capsGet();
cap_t cap_new = capsGet();
struct capslistt *l = is_global ? &nsjconf->global_caps : &nsjconf->local_caps;
bool keep_caps = is_global ? nsjconf->keep_global_caps : nsjconf->keep_local_caps;
if (keep_caps) {
if (nsjconf->keep_caps) {
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (capsGetCap(cap_orig, capNames[i].val, CAP_PERMITTED) == CAP_SET) {
capsSetCap(cap_new, capNames[i].val, CAP_INHERITABLE);
@ -169,10 +166,10 @@ bool capsInitInternal(struct nsjconf_t *nsjconf, bool is_global)
} else {
capsClearType(cap_new, CAP_INHERITABLE);
struct ints_t *p;
TAILQ_FOREACH(p, l, pointers) {
TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (capsGetCap(cap_orig, p->val, CAP_PERMITTED) != CAP_SET) {
LOG_W("Capability %s is not permitted in the %s namespace",
capsValToStr(p->val), is_global ? "global" : "local");
LOG_W("Capability %s is not permitted in the namespace",
capsValToStr(p->val));
capsFree(cap_orig);
capsFree(cap_new);
return false;
@ -190,7 +187,7 @@ bool capsInitInternal(struct nsjconf_t *nsjconf, bool is_global)
#define PR_CAP_AMBIENT 47
#define PR_CAP_AMBIENT_RAISE 2
#endif /* !defined(PR_CAP_AMBIENT) */
if (keep_caps) {
if (nsjconf->keep_caps) {
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (capsGetCap(cap_orig, capNames[i].val, CAP_PERMITTED) != CAP_SET) {
continue;
@ -204,7 +201,7 @@ bool capsInitInternal(struct nsjconf_t *nsjconf, bool is_global)
}
} else {
struct ints_t *p;
TAILQ_FOREACH(p, l, pointers) {
TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (prctl
(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL,
0UL) == -1) {
@ -218,13 +215,3 @@ bool capsInitInternal(struct nsjconf_t *nsjconf, bool is_global)
capsFree(cap_new);
return true;
}
bool capsInitGlobalNs(struct nsjconf_t * nsjconf)
{
return capsInitInternal(nsjconf, true /* global */ );
}
bool capsInitLocalNs(struct nsjconf_t * nsjconf)
{
return capsInitInternal(nsjconf, false /* local */ );
}

3
caps.h
View File

@ -25,7 +25,6 @@
#include "common.h"
int capsNameToVal(const char *name);
bool capsInitGlobalNs(struct nsjconf_t *nsjconf);
bool capsInitLocalNs(struct nsjconf_t *nsjconf);
bool capsInitNs(struct nsjconf_t *nsjconf);
#endif /* NS_CAPS_H */

View File

@ -86,14 +86,12 @@ struct custom_option custom_opts[] = {
{{"quiet", no_argument, NULL, 'q'}, "Only output warning and more important messages"},
{{"keep_env", no_argument, NULL, 'e'}, "Should all environment variables be passed to the child?"},
{{"env", required_argument, NULL, 'E'}, "Environment variable (can be used multiple times)"},
{{"keep_global_caps", no_argument, NULL, 0x0500}, "Don't drop capabilities in the global namespace"},
{{"keep_local_caps", no_argument, NULL, 0x0501}, "Don't drop capabilities in the local namespace"},
{{"keep_caps", no_argument, NULL, 0x0501}, "Don't drop capabilities in the local namespace"},
{{"silent", no_argument, NULL, 0x0502}, "Redirect child's fd:0/1/2 to /dev/null"},
{{"skip_setsid", no_argument, NULL, 0x0504}, "Don't call setsid(), allows for terminal signal handling in the sandboxed process"},
{{"pass_fd", required_argument, NULL, 0x0505}, "Don't close this FD before executing child (can be specified multiple times), by default: 0/1/2 are kept open"},
{{"disable_no_new_privs", no_argument, NULL, 0x0507}, "Don't set the prctl(NO_NEW_PRIVS, 1) (DANGEROUS)"},
{{"global_cap", required_argument, NULL, 0x0509}, "Retain this capability in global namespace (e.g. CAP_PTRACE). Can be specified multiple times"},
{{"local_cap", required_argument, NULL, 0x050A}, "Retain this capability in local namespace (e.g. CAP_PTRACE). Can be specified multiple times)"},
{{"cap", required_argument, NULL, 0x0509}, "Retain this capability in local namespace (e.g. CAP_PTRACE). Can be specified multiple times)"},
{{"rlimit_as", required_argument, NULL, 0x0201}, "RLIMIT_AS in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 512)"},
{{"rlimit_core", required_argument, NULL, 0x0202}, "RLIMIT_CORE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 0)"},
{{"rlimit_cpu", required_argument, NULL, 0x0203}, "RLIMIT_CPU, 'max' for RLIM_INFINITY, 'def' for the current value (default: 600)"},
@ -142,7 +140,6 @@ struct custom_option deprecated_opts[] = {
{{"iface_vs_ip", required_argument, NULL, 0x701}, "IP of the 'vs' interface (e.g. \"192.168.0.1\")"},
{{"iface_vs_nm", required_argument, NULL, 0x702}, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")"},
{{"iface_vs_gw", required_argument, NULL, 0x703}, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")"},
{{"keep_caps", no_argument, NULL, 0x0501}, "Don't drop capabilities in the local namespace"},
};
/* *INDENT-ON* */
@ -217,16 +214,16 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
"bind:[%s]:%d, "
"max_conns_per_ip:%u, time_limit:%ld, personality:%#lx, daemonize:%s, "
"clone_newnet:%s, clone_newuser:%s, clone_newns:%s, clone_newpid:%s, "
"clone_newipc:%s, clonew_newuts:%s, clone_newcgroup:%s, keep_global_caps:%s, "
"keep_local_caps:%s, tmpfs_size:%zu, disable_no_new_privs:%s, max_cpus:%zu",
"clone_newipc:%s, clonew_newuts:%s, clone_newcgroup:%s, keep_caps:%s, "
"tmpfs_size:%zu, disable_no_new_privs:%s, max_cpus:%zu",
nsjconf->hostname, nsjconf->chroot ? nsjconf->chroot : "[NULL]", nsjconf->argv[0],
nsjconf->bindhost, nsjconf->port, nsjconf->max_conns_per_ip, nsjconf->tlimit,
nsjconf->personality, logYesNo(nsjconf->daemonize), logYesNo(nsjconf->clone_newnet),
logYesNo(nsjconf->clone_newuser), logYesNo(nsjconf->clone_newns),
logYesNo(nsjconf->clone_newpid), logYesNo(nsjconf->clone_newipc),
logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
logYesNo(nsjconf->keep_global_caps), logYesNo(nsjconf->keep_local_caps),
nsjconf->tmpfs_size, logYesNo(nsjconf->disable_no_new_privs), nsjconf->max_cpus);
logYesNo(nsjconf->keep_caps), nsjconf->tmpfs_size,
logYesNo(nsjconf->disable_no_new_privs), nsjconf->max_cpus);
{
struct mounts_t *p;
@ -322,8 +319,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
.daemonize = false,
.tlimit = 0,
.max_cpus = 0,
.keep_global_caps = false,
.keep_local_caps = false,
.keep_caps = false,
.disable_no_new_privs = false,
.rl_as = 512 * (1024 * 1024),
.rl_core = 0,
@ -370,8 +366,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
TAILQ_INIT(&nsjconf->envs);
TAILQ_INIT(&nsjconf->uids);
TAILQ_INIT(&nsjconf->gids);
TAILQ_INIT(&nsjconf->global_caps);
TAILQ_INIT(&nsjconf->local_caps);
TAILQ_INIT(&nsjconf->caps);
static char cmdlineTmpfsSz[PATH_MAX] = "size=4194304";
@ -529,11 +524,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
case 0x0407:
nsjconf->clone_newcgroup = true;
break;
case 0x0500:
nsjconf->keep_global_caps = true;
break;
case 0x0501:
nsjconf->keep_local_caps = true;
nsjconf->keep_caps = true;
break;
case 0x0502:
nsjconf->is_silent = true;
@ -559,16 +551,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
if (f->val == -1) {
return false;
}
TAILQ_INSERT_HEAD(&nsjconf->global_caps, f, pointers);
}
break;
case 0x50A:{
struct ints_t *f = utilMalloc(sizeof(struct ints_t));
f->val = capsNameToVal(optarg);
if (f->val == -1) {
return false;
}
TAILQ_INSERT_HEAD(&nsjconf->local_caps, f, pointers);
TAILQ_INSERT_HEAD(&nsjconf->caps, f, pointers);
}
break;
case 0x0601:

View File

@ -127,8 +127,7 @@ struct nsjconf_t {
time_t tlimit;
size_t max_cpus;
bool keep_env;
bool keep_global_caps;
bool keep_local_caps;
bool keep_caps;
bool disable_no_new_privs;
__rlim64_t rl_as;
__rlim64_t rl_core;
@ -174,7 +173,7 @@ struct nsjconf_t {
TAILQ_HEAD(pidslist, pids_t) pids;
TAILQ_HEAD(mountptslist, mounts_t) mountpts;
TAILQ_HEAD(fdslistt, ints_t) open_fds;
TAILQ_HEAD(capslistt, ints_t) global_caps, local_caps;
TAILQ_HEAD(capslistt, ints_t) caps;
};
#endif /* NS_COMMON_H */

View File

@ -112,8 +112,7 @@ static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
}
nsjconf->keep_local_caps = njc->keep_local_caps;
nsjconf->keep_global_caps = njc->keep_global_caps;
nsjconf->keep_caps = njc->keep_caps;
nsjconf->is_silent = njc->silent;
nsjconf->skip_setsid = njc->skip_setsid;

View File

@ -108,10 +108,8 @@ message NsJailConfig
/* EnvVars to be set before executing binaries */
repeated string envar = 20;
/* Should local (inside ns) capabilities be preserved or dropped */
required bool keep_local_caps = 21 [ default = false ];
/* Should global (outside ns) capabilities be preserved or dropped */
required bool keep_global_caps = 63 [ default = false ];
/* Should capabilities be preserved or dropped */
required bool keep_caps = 21 [ default = false ];
/* Should nsjail close FD=0,1,2 before executing the process */
required bool silent = 22 [ default = false ];
/* Should the child process have control over terminal?

View File

@ -28,7 +28,7 @@ envar: "TERM=linux"
envar: "HOME=/"
envar: "PS1=[\\H:\\t:\\s-\\V:\\w]\\$ "
keep_local_caps: true
keep_caps: true
silent: false
skip_setsid: true
pass_fd: 100

View File

@ -89,7 +89,7 @@ static bool containDropPrivs(struct nsjconf_t *nsjconf)
PLOG_W("prctl(PR_SET_NO_NEW_PRIVS, 1)");
}
}
if (capsInitLocalNs(nsjconf) == false) {
if (capsInitNs(nsjconf) == false) {
return false;
}

View File

@ -185,10 +185,6 @@ int main(int argc, char *argv[])
if (nsjailSetTimer(&nsjconf) == false) {
exit(1);
}
if (capsInitGlobalNs(&nsjconf) == false) {
LOG_E("Couldn't initialize global capabilities");
exit(1);
}
if (nsjconf.mode == MODE_LISTEN_TCP) {
nsjailListenMode(&nsjconf);