caps: move to C++

This commit is contained in:
Robert Swiecki 2018-02-09 17:49:13 +01:00
parent ff282fb385
commit c4e57bf27e
6 changed files with 52 additions and 44 deletions

View File

@ -35,8 +35,8 @@ LDFLAGS += -pie -Wl,-z,noexecstack -lpthread $(shell pkg-config --libs protobuf)
BIN = nsjail BIN = nsjail
LIBS = kafel/libkafel.a LIBS = kafel/libkafel.a
SRCS_C = caps.c log.c cgroup.c mount.c pid.c user.c util.c uts.c SRCS_C = log.c cgroup.c mount.c pid.c user.c util.c uts.c
SRCS_CXX = cmdline.cc config.cc contain.cc cpu.cc net.cc nsjail.cc sandbox.cc subproc.cc SRCS_CXX = caps.cc cmdline.cc config.cc contain.cc cpu.cc net.cc nsjail.cc sandbox.cc subproc.cc
SRCS_PROTO = config.proto SRCS_PROTO = config.proto
SRCS_PB_CXX = $(SRCS_PROTO:.proto=.pb.cc) SRCS_PB_CXX = $(SRCS_PROTO:.proto=.pb.cc)
SRCS_PB_H = $(SRCS_PROTO:.proto=.pb.h) SRCS_PB_H = $(SRCS_PROTO:.proto=.pb.h)
@ -97,7 +97,6 @@ indent:
# DO NOT DELETE THIS LINE -- make depend depends on it. # DO NOT DELETE THIS LINE -- make depend depends on it.
caps.o: caps.h nsjail.h common.h log.h util.h
log.o: log.h nsjail.h log.o: log.h nsjail.h
cgroup.o: cgroup.h nsjail.h log.h util.h cgroup.o: cgroup.h nsjail.h log.h util.h
mount.o: mount.h nsjail.h common.h log.h subproc.h util.h mount.o: mount.h nsjail.h common.h log.h subproc.h util.h
@ -105,12 +104,13 @@ pid.o: pid.h nsjail.h log.h subproc.h
user.o: user.h nsjail.h common.h log.h subproc.h util.h user.o: user.h nsjail.h common.h log.h subproc.h util.h
util.o: util.h nsjail.h common.h log.h util.o: util.h nsjail.h common.h log.h
uts.o: uts.h nsjail.h log.h uts.o: uts.h nsjail.h log.h
cmdline.o: cmdline.h nsjail.h caps.h common.h log.h mount.h user.h util.h caps.o: caps.h nsjail.h common.h log.h util.h
cmdline.o: cmdline.h nsjail.h common.h log.h mount.h user.h util.h caps.h
cmdline.o: config.h sandbox.h cmdline.o: config.h sandbox.h
config.o: common.h caps.h nsjail.h config.h log.h mount.h user.h util.h config.o: common.h config.h nsjail.h log.h mount.h user.h util.h caps.h
config.o: cmdline.h config.o: cmdline.h
contain.o: contain.h nsjail.h caps.h cgroup.h log.h mount.h pid.h user.h contain.o: contain.h nsjail.h cgroup.h log.h mount.h pid.h user.h uts.h
contain.o: uts.h cpu.h net.h contain.o: caps.h cpu.h net.h
cpu.o: cpu.h nsjail.h log.h util.h cpu.o: cpu.h nsjail.h log.h util.h
net.o: net.h nsjail.h log.h subproc.h net.o: net.h nsjail.h log.h subproc.h
nsjail.o: nsjail.h cmdline.h common.h log.h net.h subproc.h util.h nsjail.o: nsjail.h cmdline.h common.h log.h net.h subproc.h util.h

View File

@ -28,9 +28,13 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
extern "C" {
#include "common.h" #include "common.h"
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
}
namespace caps {
static struct { static struct {
const int val; const int val;
@ -78,7 +82,7 @@ static struct {
#endif /* defined(CAP_AUDIT_READ) */ #endif /* defined(CAP_AUDIT_READ) */
}; };
int capsNameToVal(const char* name) { int nameToVal(const char* name) {
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) { for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (strcmp(name, capNames[i].name) == 0) { if (strcmp(name, capNames[i].name) == 0) {
return capNames[i].val; return capNames[i].val;
@ -88,7 +92,7 @@ int capsNameToVal(const char* name) {
return -1; return -1;
} }
static const char* capsValToStr(int val) { static const char* valToStr(int val) {
static __thread char capsStr[1024]; static __thread char capsStr[1024];
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) { for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (val == capNames[i].val) { if (val == capNames[i].val) {
@ -101,7 +105,7 @@ static const char* capsValToStr(int val) {
return capsStr; return capsStr;
} }
static cap_user_data_t capsGet() { static cap_user_data_t getCaps() {
static __thread struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3]; static __thread struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3];
const struct __user_cap_header_struct cap_hdr = { const struct __user_cap_header_struct cap_hdr = {
.version = _LINUX_CAPABILITY_VERSION_3, .version = _LINUX_CAPABILITY_VERSION_3,
@ -114,7 +118,7 @@ static cap_user_data_t capsGet() {
return cap_data; return cap_data;
} }
static bool capsSet(const cap_user_data_t cap_data) { static bool setCaps(const cap_user_data_t cap_data) {
const struct __user_cap_header_struct cap_hdr = { const struct __user_cap_header_struct cap_hdr = {
.version = _LINUX_CAPABILITY_VERSION_3, .version = _LINUX_CAPABILITY_VERSION_3,
.pid = 0, .pid = 0,
@ -126,31 +130,31 @@ static bool capsSet(const cap_user_data_t cap_data) {
return true; return true;
} }
static void capsClearInheritable(cap_user_data_t cap_data) { static void clearInheritable(cap_user_data_t cap_data) {
for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; i++) { for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; i++) {
cap_data[i].inheritable = 0U; cap_data[i].inheritable = 0U;
} }
} }
static bool capsGetPermitted(cap_user_data_t cap_data, unsigned int cap) { static bool getPermitted(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = cap / (sizeof(cap_data->permitted) * 8); size_t off_byte = cap / (sizeof(cap_data->permitted) * 8);
size_t off_bit = cap % (sizeof(cap_data->permitted) * 8); size_t off_bit = cap % (sizeof(cap_data->permitted) * 8);
return cap_data[off_byte].permitted & (1U << off_bit); return cap_data[off_byte].permitted & (1U << off_bit);
} }
static bool capsGetEffective(cap_user_data_t cap_data, unsigned int cap) { static bool getEffective(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = cap / (sizeof(cap_data->effective) * 8); size_t off_byte = cap / (sizeof(cap_data->effective) * 8);
size_t off_bit = cap % (sizeof(cap_data->effective) * 8); size_t off_bit = cap % (sizeof(cap_data->effective) * 8);
return cap_data[off_byte].effective & (1U << off_bit); return cap_data[off_byte].effective & (1U << off_bit);
} }
static bool capsGetInheritable(cap_user_data_t cap_data, unsigned int cap) { static bool getInheritable(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = cap / (sizeof(cap_data->inheritable) * 8); size_t off_byte = cap / (sizeof(cap_data->inheritable) * 8);
size_t off_bit = cap % (sizeof(cap_data->inheritable) * 8); size_t off_bit = cap % (sizeof(cap_data->inheritable) * 8);
return cap_data[off_byte].inheritable & (1U << off_bit); return cap_data[off_byte].inheritable & (1U << off_bit);
} }
static void capsSetInheritable(cap_user_data_t cap_data, unsigned int cap) { static void setInheritable(cap_user_data_t cap_data, unsigned int cap) {
size_t off_byte = cap / (sizeof(cap_data->inheritable) * 8); size_t off_byte = cap / (sizeof(cap_data->inheritable) * 8);
size_t off_bit = cap % (sizeof(cap_data->inheritable) * 8); size_t off_bit = cap % (sizeof(cap_data->inheritable) * 8);
cap_data[off_byte].inheritable |= (1U << off_bit); cap_data[off_byte].inheritable |= (1U << off_bit);
@ -161,27 +165,27 @@ static void capsSetInheritable(cap_user_data_t cap_data, unsigned int cap) {
#define PR_CAP_AMBIENT_RAISE 2 #define PR_CAP_AMBIENT_RAISE 2
#define PR_CAP_AMBIENT_CLEAR_ALL 4 #define PR_CAP_AMBIENT_CLEAR_ALL 4
#endif /* !defined(PR_CAP_AMBIENT) */ #endif /* !defined(PR_CAP_AMBIENT) */
static bool CapsInitNsKeepCaps(cap_user_data_t cap_data) { static bool initNsKeepCaps(cap_user_data_t cap_data) {
char dbgmsg[4096]; char dbgmsg[4096];
/* Copy all permitted caps to the inheritable set */ /* Copy all permitted caps to the inheritable set */
dbgmsg[0] = '\0'; dbgmsg[0] = '\0';
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) { for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (capsGetPermitted(cap_data, capNames[i].val)) { if (getPermitted(cap_data, capNames[i].val)) {
utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name); utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
capsSetInheritable(cap_data, capNames[i].val); setInheritable(cap_data, capNames[i].val);
} }
} }
LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg); LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
if (capsSet(cap_data) == false) { if (setCaps(cap_data) == false) {
return false; return false;
} }
/* Make sure the inheritable set is preserved across execve via the ambient set */ /* Make sure the inheritable set is preserved across execve via the ambient set */
dbgmsg[0] = '\0'; dbgmsg[0] = '\0';
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) { for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (capsGetPermitted(cap_data, capNames[i].val) == false) { if (getPermitted(cap_data, capNames[i].val) == false) {
continue; continue;
} }
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val, 0UL, if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val, 0UL,
@ -196,17 +200,17 @@ static bool CapsInitNsKeepCaps(cap_user_data_t cap_data) {
return true; return true;
} }
bool capsInitNs(struct nsjconf_t* nsjconf) { bool initNs(struct nsjconf_t* nsjconf) {
char dbgmsg[4096]; char dbgmsg[4096];
struct ints_t* p; struct ints_t* p;
cap_user_data_t cap_data = capsGet(); cap_user_data_t cap_data = getCaps();
if (cap_data == NULL) { if (cap_data == NULL) {
return false; return false;
} }
/* Let's start with an empty inheritable set to avoid any mistakes */ /* Let's start with an empty inheritable set to avoid any mistakes */
capsClearInheritable(cap_data); clearInheritable(cap_data);
/* /*
* Remove all capabilities from the ambient set first. It works with newer kernel versions * Remove all capabilities from the ambient set first. It works with newer kernel versions
* only, so don't panic() if it fails * only, so don't panic() if it fails
@ -216,24 +220,23 @@ bool capsInitNs(struct nsjconf_t* nsjconf) {
} }
if (nsjconf->keep_caps) { if (nsjconf->keep_caps) {
return CapsInitNsKeepCaps(cap_data); return initNsKeepCaps(cap_data);
} }
/* Set all requested caps in the inheritable set if these are present in the permitted set /* Set all requested caps in the inheritable set if these are present in the permitted set
*/ */
dbgmsg[0] = '\0'; dbgmsg[0] = '\0';
TAILQ_FOREACH(p, &nsjconf->caps, pointers) { TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (capsGetPermitted(cap_data, p->val) == false) { if (getPermitted(cap_data, p->val) == false) {
LOG_W("Capability %s is not permitted in the namespace", LOG_W("Capability %s is not permitted in the namespace", valToStr(p->val));
capsValToStr(p->val));
return false; return false;
} }
utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capsValToStr(p->val)); utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", valToStr(p->val));
capsSetInheritable(cap_data, p->val); setInheritable(cap_data, p->val);
} }
LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg); LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
if (capsSet(cap_data) == false) { if (setCaps(cap_data) == false) {
return false; return false;
} }
@ -241,10 +244,10 @@ bool capsInitNs(struct nsjconf_t* nsjconf) {
* Make sure all other caps (those which were not explicitly requested) are removed from the * Make sure all other caps (those which were not explicitly requested) are removed from the
* bounding set. We need to have CAP_SETPCAP to do that now * bounding set. We need to have CAP_SETPCAP to do that now
*/ */
if (capsGetEffective(cap_data, CAP_SETPCAP)) { if (getEffective(cap_data, CAP_SETPCAP)) {
dbgmsg[0] = '\0'; dbgmsg[0] = '\0';
for (size_t i = 0; i < ARRAYSIZE(capNames); i++) { for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
if (capsGetInheritable(cap_data, capNames[i].val)) { if (getInheritable(cap_data, capNames[i].val)) {
continue; continue;
} }
utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name); utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
@ -262,13 +265,14 @@ bool capsInitNs(struct nsjconf_t* nsjconf) {
TAILQ_FOREACH(p, &nsjconf->caps, pointers) { TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL, 0UL) == if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL, 0UL) ==
-1) { -1) {
PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", valToStr(p->val));
capsValToStr(p->val));
} else { } else {
utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capsValToStr(p->val)); utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", valToStr(p->val));
} }
} }
LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg); LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg);
return true; return true;
} }
} // namespace caps

8
caps.h
View File

@ -27,7 +27,11 @@
#include "nsjail.h" #include "nsjail.h"
int capsNameToVal(const char* name); namespace caps {
bool capsInitNs(struct nsjconf_t* nsjconf);
int nameToVal(const char* name);
bool initNs(struct nsjconf_t* nsjconf);
} // namespace caps
#endif /* NS_CAPS_H */ #endif /* NS_CAPS_H */

View File

@ -45,7 +45,6 @@
#include <memory> #include <memory>
extern "C" { extern "C" {
#include "caps.h"
#include "common.h" #include "common.h"
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
@ -53,6 +52,7 @@ extern "C" {
#include "util.h" #include "util.h"
} }
#include "caps.h"
#include "config.h" #include "config.h"
#include "sandbox.h" #include "sandbox.h"
@ -585,7 +585,7 @@ std::unique_ptr<struct nsjconf_t> parseArgs(int argc, char* argv[]) {
case 0x0509: { case 0x0509: {
struct ints_t* f = struct ints_t* f =
reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t))); reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t)));
f->val = capsNameToVal(optarg); f->val = caps::nameToVal(optarg);
if (f->val == -1) { if (f->val == -1) {
return nullptr; return nullptr;
} }

View File

@ -30,7 +30,6 @@ extern "C" {
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include "caps.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
@ -38,6 +37,7 @@ extern "C" {
#include "util.h" #include "util.h"
} }
#include "caps.h"
#include "cmdline.h" #include "cmdline.h"
#include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/zero_copy_stream_impl.h>
@ -142,7 +142,7 @@ static bool configParseInternal(struct nsjconf_t* nsjconf, const nsjail::NsJailC
for (ssize_t i = 0; i < njc.cap_size(); i++) { for (ssize_t i = 0; i < njc.cap_size(); i++) {
struct ints_t* f = struct ints_t* f =
reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t))); reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t)));
f->val = capsNameToVal(njc.cap(i).c_str()); f->val = caps::nameToVal(njc.cap(i).c_str());
if (f->val == -1) { if (f->val == -1) {
return false; return false;
} }

View File

@ -38,7 +38,6 @@
#include <unistd.h> #include <unistd.h>
extern "C" { extern "C" {
#include "caps.h"
#include "cgroup.h" #include "cgroup.h"
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
@ -47,6 +46,7 @@ extern "C" {
#include "uts.h" #include "uts.h"
} }
#include "caps.h"
#include "cpu.h" #include "cpu.h"
#include "net.h" #include "net.h"
@ -73,7 +73,7 @@ static bool containDropPrivs(struct nsjconf_t* nsjconf) {
} }
} }
if (capsInitNs(nsjconf) == false) { if (caps::initNs(nsjconf) == false) {
return false; return false;
} }