caps: move to C++
authorRobert Swiecki <robert@swiecki.net>
Fri, 9 Feb 2018 16:49:13 +0000 (17:49 +0100)
committerRobert Swiecki <robert@swiecki.net>
Fri, 9 Feb 2018 16:49:13 +0000 (17:49 +0100)
Makefile
caps.c [deleted file]
caps.cc [new file with mode: 0644]
caps.h
cmdline.cc
config.cc
contain.cc

index 2f30677b6359f10b42b97179966f0a077edffc07..8c20fe968d48230df9858419084011c4baf7d7cd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,8 +35,8 @@ LDFLAGS += -pie -Wl,-z,noexecstack -lpthread $(shell pkg-config --libs protobuf)
 
 BIN = nsjail
 LIBS = kafel/libkafel.a
-SRCS_C = caps.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_C = log.c cgroup.c mount.c pid.c user.c util.c uts.c
+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_PB_CXX = $(SRCS_PROTO:.proto=.pb.cc)
 SRCS_PB_H = $(SRCS_PROTO:.proto=.pb.h)
@@ -97,7 +97,6 @@ indent:
 
 # 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
 cgroup.o: cgroup.h nsjail.h log.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
 util.o: util.h nsjail.h common.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
-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
-contain.o: contain.h nsjail.h caps.h cgroup.h log.h mount.h pid.h user.h
-contain.o: uts.h cpu.h net.h
+contain.o: contain.h nsjail.h cgroup.h log.h mount.h pid.h user.h uts.h
+contain.o: caps.h cpu.h net.h
 cpu.o: cpu.h nsjail.h log.h util.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
diff --git a/caps.c b/caps.c
deleted file mode 100644 (file)
index b1d02d3..0000000
--- a/caps.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-
-   nsjail - capability-related operations
-   -----------------------------------------
-
-   Copyright 2014 Google Inc. All Rights Reserved.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-*/
-
-#include "caps.h"
-
-#include <linux/capability.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "common.h"
-#include "log.h"
-#include "util.h"
-
-static struct {
-       const int val;
-       const char* const name;
-} const capNames[] = {
-    NS_VALSTR_STRUCT(CAP_CHOWN),
-    NS_VALSTR_STRUCT(CAP_DAC_OVERRIDE),
-    NS_VALSTR_STRUCT(CAP_DAC_READ_SEARCH),
-    NS_VALSTR_STRUCT(CAP_FOWNER),
-    NS_VALSTR_STRUCT(CAP_FSETID),
-    NS_VALSTR_STRUCT(CAP_KILL),
-    NS_VALSTR_STRUCT(CAP_SETGID),
-    NS_VALSTR_STRUCT(CAP_SETUID),
-    NS_VALSTR_STRUCT(CAP_SETPCAP),
-    NS_VALSTR_STRUCT(CAP_LINUX_IMMUTABLE),
-    NS_VALSTR_STRUCT(CAP_NET_BIND_SERVICE),
-    NS_VALSTR_STRUCT(CAP_NET_BROADCAST),
-    NS_VALSTR_STRUCT(CAP_NET_ADMIN),
-    NS_VALSTR_STRUCT(CAP_NET_RAW),
-    NS_VALSTR_STRUCT(CAP_IPC_LOCK),
-    NS_VALSTR_STRUCT(CAP_IPC_OWNER),
-    NS_VALSTR_STRUCT(CAP_SYS_MODULE),
-    NS_VALSTR_STRUCT(CAP_SYS_RAWIO),
-    NS_VALSTR_STRUCT(CAP_SYS_CHROOT),
-    NS_VALSTR_STRUCT(CAP_SYS_PTRACE),
-    NS_VALSTR_STRUCT(CAP_SYS_PACCT),
-    NS_VALSTR_STRUCT(CAP_SYS_ADMIN),
-    NS_VALSTR_STRUCT(CAP_SYS_BOOT),
-    NS_VALSTR_STRUCT(CAP_SYS_NICE),
-    NS_VALSTR_STRUCT(CAP_SYS_RESOURCE),
-    NS_VALSTR_STRUCT(CAP_SYS_TIME),
-    NS_VALSTR_STRUCT(CAP_SYS_TTY_CONFIG),
-    NS_VALSTR_STRUCT(CAP_MKNOD),
-    NS_VALSTR_STRUCT(CAP_LEASE),
-    NS_VALSTR_STRUCT(CAP_AUDIT_WRITE),
-    NS_VALSTR_STRUCT(CAP_AUDIT_CONTROL),
-    NS_VALSTR_STRUCT(CAP_SETFCAP),
-    NS_VALSTR_STRUCT(CAP_MAC_OVERRIDE),
-    NS_VALSTR_STRUCT(CAP_MAC_ADMIN),
-    NS_VALSTR_STRUCT(CAP_SYSLOG),
-    NS_VALSTR_STRUCT(CAP_WAKE_ALARM),
-    NS_VALSTR_STRUCT(CAP_BLOCK_SUSPEND),
-#if defined(CAP_AUDIT_READ)
-    NS_VALSTR_STRUCT(CAP_AUDIT_READ),
-#endif /* defined(CAP_AUDIT_READ) */
-};
-
-int capsNameToVal(const char* name) {
-       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
-               if (strcmp(name, capNames[i].name) == 0) {
-                       return capNames[i].val;
-               }
-       }
-       LOG_W("Uknown capability: '%s'", name);
-       return -1;
-}
-
-static const char* capsValToStr(int val) {
-       static __thread char capsStr[1024];
-       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
-               if (val == capNames[i].val) {
-                       snprintf(capsStr, sizeof(capsStr), "%s", capNames[i].name);
-                       return capsStr;
-               }
-       }
-
-       snprintf(capsStr, sizeof(capsStr), "CAP_UNKNOWN(%d)", val);
-       return capsStr;
-}
-
-static cap_user_data_t capsGet() {
-       static __thread struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3];
-       const struct __user_cap_header_struct cap_hdr = {
-           .version = _LINUX_CAPABILITY_VERSION_3,
-           .pid = 0,
-       };
-       if (syscall(__NR_capget, &cap_hdr, &cap_data) == -1) {
-               PLOG_W("capget() failed");
-               return NULL;
-       }
-       return cap_data;
-}
-
-static bool capsSet(const cap_user_data_t cap_data) {
-       const struct __user_cap_header_struct cap_hdr = {
-           .version = _LINUX_CAPABILITY_VERSION_3,
-           .pid = 0,
-       };
-       if (syscall(__NR_capset, &cap_hdr, cap_data) == -1) {
-               PLOG_W("capset() failed");
-               return false;
-       }
-       return true;
-}
-
-static void capsClearInheritable(cap_user_data_t cap_data) {
-       for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; i++) {
-               cap_data[i].inheritable = 0U;
-       }
-}
-
-static bool capsGetPermitted(cap_user_data_t cap_data, unsigned int cap) {
-       size_t off_byte = 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);
-}
-
-static bool capsGetEffective(cap_user_data_t cap_data, unsigned int cap) {
-       size_t off_byte = 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);
-}
-
-static bool capsGetInheritable(cap_user_data_t cap_data, unsigned int cap) {
-       size_t off_byte = 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);
-}
-
-static void capsSetInheritable(cap_user_data_t cap_data, unsigned int cap) {
-       size_t off_byte = cap / (sizeof(cap_data->inheritable) * 8);
-       size_t off_bit = cap % (sizeof(cap_data->inheritable) * 8);
-       cap_data[off_byte].inheritable |= (1U << off_bit);
-}
-
-#if !defined(PR_CAP_AMBIENT)
-#define PR_CAP_AMBIENT 47
-#define PR_CAP_AMBIENT_RAISE 2
-#define PR_CAP_AMBIENT_CLEAR_ALL 4
-#endif /* !defined(PR_CAP_AMBIENT) */
-static bool CapsInitNsKeepCaps(cap_user_data_t cap_data) {
-       char dbgmsg[4096];
-
-       /* Copy all permitted caps to the inheritable set */
-       dbgmsg[0] = '\0';
-       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
-               if (capsGetPermitted(cap_data, capNames[i].val)) {
-                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
-                       capsSetInheritable(cap_data, capNames[i].val);
-               }
-       }
-       LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
-
-       if (capsSet(cap_data) == false) {
-               return false;
-       }
-
-       /* Make sure the inheritable set is preserved across execve via the ambient set */
-       dbgmsg[0] = '\0';
-       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
-               if (capsGetPermitted(cap_data, capNames[i].val) == false) {
-                       continue;
-               }
-               if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val, 0UL,
-                       0UL) == -1) {
-                       PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", capNames[i].name);
-               } else {
-                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
-               }
-       }
-       LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg);
-
-       return true;
-}
-
-bool capsInitNs(struct nsjconf_t* nsjconf) {
-       char dbgmsg[4096];
-       struct ints_t* p;
-
-       cap_user_data_t cap_data = capsGet();
-       if (cap_data == NULL) {
-               return false;
-       }
-
-       /* Let's start with an empty inheritable set to avoid any mistakes */
-       capsClearInheritable(cap_data);
-       /*
-        * Remove all capabilities from the ambient set first. It works with newer kernel versions
-        * only, so don't panic() if it fails
-        */
-       if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0UL, 0UL, 0UL) == -1) {
-               PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL)");
-       }
-
-       if (nsjconf->keep_caps) {
-               return CapsInitNsKeepCaps(cap_data);
-       }
-
-       /* Set all requested caps in the inheritable set if these are present in the permitted set
-        */
-       dbgmsg[0] = '\0';
-       TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
-               if (capsGetPermitted(cap_data, p->val) == false) {
-                       LOG_W("Capability %s is not permitted in the namespace",
-                           capsValToStr(p->val));
-                       return false;
-               }
-               utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capsValToStr(p->val));
-               capsSetInheritable(cap_data, p->val);
-       }
-       LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
-
-       if (capsSet(cap_data) == false) {
-               return false;
-       }
-
-       /*
-        * 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
-        */
-       if (capsGetEffective(cap_data, CAP_SETPCAP)) {
-               dbgmsg[0] = '\0';
-               for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
-                       if (capsGetInheritable(cap_data, capNames[i].val)) {
-                               continue;
-                       }
-                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
-                       if (prctl(PR_CAPBSET_DROP, (unsigned long)capNames[i].val, 0UL, 0UL, 0UL) ==
-                           -1) {
-                               PLOG_W("prctl(PR_CAPBSET_DROP, %s)", capNames[i].name);
-                               return false;
-                       }
-               }
-               LOG_D("Dropped the following capabilities from the bounding set:%s", dbgmsg);
-       }
-
-       /* Make sure inheritable set is preserved across execve via the modified ambient set */
-       dbgmsg[0] = '\0';
-       TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
-               if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL, 0UL) ==
-                   -1) {
-                       PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)",
-                           capsValToStr(p->val));
-               } else {
-                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capsValToStr(p->val));
-               }
-       }
-       LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg);
-
-       return true;
-}
diff --git a/caps.cc b/caps.cc
new file mode 100644 (file)
index 0000000..563e624
--- /dev/null
+++ b/caps.cc
@@ -0,0 +1,278 @@
+/*
+
+   nsjail - capability-related operations
+   -----------------------------------------
+
+   Copyright 2014 Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#include "caps.h"
+
+#include <linux/capability.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+extern "C" {
+#include "common.h"
+#include "log.h"
+#include "util.h"
+}
+
+namespace caps {
+
+static struct {
+       const int val;
+       const char* const name;
+} const capNames[] = {
+    NS_VALSTR_STRUCT(CAP_CHOWN),
+    NS_VALSTR_STRUCT(CAP_DAC_OVERRIDE),
+    NS_VALSTR_STRUCT(CAP_DAC_READ_SEARCH),
+    NS_VALSTR_STRUCT(CAP_FOWNER),
+    NS_VALSTR_STRUCT(CAP_FSETID),
+    NS_VALSTR_STRUCT(CAP_KILL),
+    NS_VALSTR_STRUCT(CAP_SETGID),
+    NS_VALSTR_STRUCT(CAP_SETUID),
+    NS_VALSTR_STRUCT(CAP_SETPCAP),
+    NS_VALSTR_STRUCT(CAP_LINUX_IMMUTABLE),
+    NS_VALSTR_STRUCT(CAP_NET_BIND_SERVICE),
+    NS_VALSTR_STRUCT(CAP_NET_BROADCAST),
+    NS_VALSTR_STRUCT(CAP_NET_ADMIN),
+    NS_VALSTR_STRUCT(CAP_NET_RAW),
+    NS_VALSTR_STRUCT(CAP_IPC_LOCK),
+    NS_VALSTR_STRUCT(CAP_IPC_OWNER),
+    NS_VALSTR_STRUCT(CAP_SYS_MODULE),
+    NS_VALSTR_STRUCT(CAP_SYS_RAWIO),
+    NS_VALSTR_STRUCT(CAP_SYS_CHROOT),
+    NS_VALSTR_STRUCT(CAP_SYS_PTRACE),
+    NS_VALSTR_STRUCT(CAP_SYS_PACCT),
+    NS_VALSTR_STRUCT(CAP_SYS_ADMIN),
+    NS_VALSTR_STRUCT(CAP_SYS_BOOT),
+    NS_VALSTR_STRUCT(CAP_SYS_NICE),
+    NS_VALSTR_STRUCT(CAP_SYS_RESOURCE),
+    NS_VALSTR_STRUCT(CAP_SYS_TIME),
+    NS_VALSTR_STRUCT(CAP_SYS_TTY_CONFIG),
+    NS_VALSTR_STRUCT(CAP_MKNOD),
+    NS_VALSTR_STRUCT(CAP_LEASE),
+    NS_VALSTR_STRUCT(CAP_AUDIT_WRITE),
+    NS_VALSTR_STRUCT(CAP_AUDIT_CONTROL),
+    NS_VALSTR_STRUCT(CAP_SETFCAP),
+    NS_VALSTR_STRUCT(CAP_MAC_OVERRIDE),
+    NS_VALSTR_STRUCT(CAP_MAC_ADMIN),
+    NS_VALSTR_STRUCT(CAP_SYSLOG),
+    NS_VALSTR_STRUCT(CAP_WAKE_ALARM),
+    NS_VALSTR_STRUCT(CAP_BLOCK_SUSPEND),
+#if defined(CAP_AUDIT_READ)
+    NS_VALSTR_STRUCT(CAP_AUDIT_READ),
+#endif /* defined(CAP_AUDIT_READ) */
+};
+
+int nameToVal(const char* name) {
+       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
+               if (strcmp(name, capNames[i].name) == 0) {
+                       return capNames[i].val;
+               }
+       }
+       LOG_W("Uknown capability: '%s'", name);
+       return -1;
+}
+
+static const char* valToStr(int val) {
+       static __thread char capsStr[1024];
+       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
+               if (val == capNames[i].val) {
+                       snprintf(capsStr, sizeof(capsStr), "%s", capNames[i].name);
+                       return capsStr;
+               }
+       }
+
+       snprintf(capsStr, sizeof(capsStr), "CAP_UNKNOWN(%d)", val);
+       return capsStr;
+}
+
+static cap_user_data_t getCaps() {
+       static __thread struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3];
+       const struct __user_cap_header_struct cap_hdr = {
+           .version = _LINUX_CAPABILITY_VERSION_3,
+           .pid = 0,
+       };
+       if (syscall(__NR_capget, &cap_hdr, &cap_data) == -1) {
+               PLOG_W("capget() failed");
+               return NULL;
+       }
+       return cap_data;
+}
+
+static bool setCaps(const cap_user_data_t cap_data) {
+       const struct __user_cap_header_struct cap_hdr = {
+           .version = _LINUX_CAPABILITY_VERSION_3,
+           .pid = 0,
+       };
+       if (syscall(__NR_capset, &cap_hdr, cap_data) == -1) {
+               PLOG_W("capset() failed");
+               return false;
+       }
+       return true;
+}
+
+static void clearInheritable(cap_user_data_t cap_data) {
+       for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; i++) {
+               cap_data[i].inheritable = 0U;
+       }
+}
+
+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_bit = cap % (sizeof(cap_data->permitted) * 8);
+       return cap_data[off_byte].permitted & (1U << off_bit);
+}
+
+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_bit = cap % (sizeof(cap_data->effective) * 8);
+       return cap_data[off_byte].effective & (1U << off_bit);
+}
+
+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_bit = cap % (sizeof(cap_data->inheritable) * 8);
+       return cap_data[off_byte].inheritable & (1U << off_bit);
+}
+
+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_bit = cap % (sizeof(cap_data->inheritable) * 8);
+       cap_data[off_byte].inheritable |= (1U << off_bit);
+}
+
+#if !defined(PR_CAP_AMBIENT)
+#define PR_CAP_AMBIENT 47
+#define PR_CAP_AMBIENT_RAISE 2
+#define PR_CAP_AMBIENT_CLEAR_ALL 4
+#endif /* !defined(PR_CAP_AMBIENT) */
+static bool initNsKeepCaps(cap_user_data_t cap_data) {
+       char dbgmsg[4096];
+
+       /* Copy all permitted caps to the inheritable set */
+       dbgmsg[0] = '\0';
+       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
+               if (getPermitted(cap_data, capNames[i].val)) {
+                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
+                       setInheritable(cap_data, capNames[i].val);
+               }
+       }
+       LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
+
+       if (setCaps(cap_data) == false) {
+               return false;
+       }
+
+       /* Make sure the inheritable set is preserved across execve via the ambient set */
+       dbgmsg[0] = '\0';
+       for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
+               if (getPermitted(cap_data, capNames[i].val) == false) {
+                       continue;
+               }
+               if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val, 0UL,
+                       0UL) == -1) {
+                       PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", capNames[i].name);
+               } else {
+                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
+               }
+       }
+       LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg);
+
+       return true;
+}
+
+bool initNs(struct nsjconf_t* nsjconf) {
+       char dbgmsg[4096];
+       struct ints_t* p;
+
+       cap_user_data_t cap_data = getCaps();
+       if (cap_data == NULL) {
+               return false;
+       }
+
+       /* Let's start with an empty inheritable set to avoid any mistakes */
+       clearInheritable(cap_data);
+       /*
+        * Remove all capabilities from the ambient set first. It works with newer kernel versions
+        * only, so don't panic() if it fails
+        */
+       if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0UL, 0UL, 0UL) == -1) {
+               PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL)");
+       }
+
+       if (nsjconf->keep_caps) {
+               return initNsKeepCaps(cap_data);
+       }
+
+       /* Set all requested caps in the inheritable set if these are present in the permitted set
+        */
+       dbgmsg[0] = '\0';
+       TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
+               if (getPermitted(cap_data, p->val) == false) {
+                       LOG_W("Capability %s is not permitted in the namespace", valToStr(p->val));
+                       return false;
+               }
+               utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", valToStr(p->val));
+               setInheritable(cap_data, p->val);
+       }
+       LOG_D("Adding the following capabilities to the inheritable set:%s", dbgmsg);
+
+       if (setCaps(cap_data) == false) {
+               return false;
+       }
+
+       /*
+        * 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
+        */
+       if (getEffective(cap_data, CAP_SETPCAP)) {
+               dbgmsg[0] = '\0';
+               for (size_t i = 0; i < ARRAYSIZE(capNames); i++) {
+                       if (getInheritable(cap_data, capNames[i].val)) {
+                               continue;
+                       }
+                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", capNames[i].name);
+                       if (prctl(PR_CAPBSET_DROP, (unsigned long)capNames[i].val, 0UL, 0UL, 0UL) ==
+                           -1) {
+                               PLOG_W("prctl(PR_CAPBSET_DROP, %s)", capNames[i].name);
+                               return false;
+                       }
+               }
+               LOG_D("Dropped the following capabilities from the bounding set:%s", dbgmsg);
+       }
+
+       /* Make sure inheritable set is preserved across execve via the modified ambient set */
+       dbgmsg[0] = '\0';
+       TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
+               if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL, 0UL) ==
+                   -1) {
+                       PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", valToStr(p->val));
+               } else {
+                       utilSSnPrintf(dbgmsg, sizeof(dbgmsg), " %s", valToStr(p->val));
+               }
+       }
+       LOG_D("Added the following capabilities to the ambient set:%s", dbgmsg);
+
+       return true;
+}
+
+}  // namespace caps
diff --git a/caps.h b/caps.h
index f2ccf88d61efbb52e3f7c0fd51b49d3fbf28a551..dd72d55eedd4d907096b7a79c5d70465e75b5137 100644 (file)
--- a/caps.h
+++ b/caps.h
 
 #include "nsjail.h"
 
-int capsNameToVal(const char* name);
-bool capsInitNs(struct nsjconf_t* nsjconf);
+namespace caps {
+
+int nameToVal(const char* name);
+bool initNs(struct nsjconf_t* nsjconf);
+
+}  // namespace caps
 
 #endif /* NS_CAPS_H */
index 2fe4964ddbc05f7c8094eb69e2798577cef2567d..4d535a759685086e4c7b3ba4e26a5ce6c8b3c15c 100644 (file)
@@ -45,7 +45,6 @@
 #include <memory>
 
 extern "C" {
-#include "caps.h"
 #include "common.h"
 #include "log.h"
 #include "mount.h"
@@ -53,6 +52,7 @@ extern "C" {
 #include "util.h"
 }
 
+#include "caps.h"
 #include "config.h"
 #include "sandbox.h"
 
@@ -585,7 +585,7 @@ std::unique_ptr<struct nsjconf_t> parseArgs(int argc, char* argv[]) {
                case 0x0509: {
                        struct ints_t* f =
                            reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t)));
-                       f->val = capsNameToVal(optarg);
+                       f->val = caps::nameToVal(optarg);
                        if (f->val == -1) {
                                return nullptr;
                        }
index 5d0d8d6b1a59300e8eef9009a49431502df9046c..8f8ca47218f23d8482b677f7a6f080b46ad73d36 100644 (file)
--- a/config.cc
+++ b/config.cc
@@ -30,7 +30,6 @@ extern "C" {
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include "caps.h"
 #include "config.h"
 #include "log.h"
 #include "mount.h"
@@ -38,6 +37,7 @@ extern "C" {
 #include "util.h"
 }
 
+#include "caps.h"
 #include "cmdline.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++) {
                struct ints_t* f =
                    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) {
                        return false;
                }
index 6ea3bdbadd860d9f428a07228dcc8ddb313caa6b..a0e085bd43a3ef3c4762b40b23c93c2ea220fba2 100644 (file)
@@ -38,7 +38,6 @@
 #include <unistd.h>
 
 extern "C" {
-#include "caps.h"
 #include "cgroup.h"
 #include "log.h"
 #include "mount.h"
@@ -47,6 +46,7 @@ extern "C" {
 #include "uts.h"
 }
 
+#include "caps.h"
 #include "cpu.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;
        }