}
-int applyOCIcapabilities(struct jail_capset ocicapset)
+int applyOCIcapabilities(struct jail_capset ocicapset, uint64_t retain)
{
struct __user_cap_header_struct uh = {};
struct __user_cap_data_struct ud;
continue;
}
- if ( (ocicapset.bounding & (1LLU << cap)) == 0) {
+ if ( ((ocicapset.bounding | retain) & (1LLU << cap)) == 0) {
DEBUG("dropping capability %s (%d) from bounding set\n", capabilities_names[cap], cap);
if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) {
ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %m\n", cap);
DEBUG("old capabilities: Pe=%08x Pp=%08x Pi=%08x\n", ud.effective, ud.permitted, ud.inheritable);
if (ocicapset.effective != JAIL_CAP_ALL)
- ud.effective = ocicapset.effective;
+ ud.effective = ocicapset.effective | retain;
if (ocicapset.permitted != JAIL_CAP_ALL)
- ud.permitted = ocicapset.permitted;
+ ud.permitted = ocicapset.permitted | retain;
if (ocicapset.inheritable != JAIL_CAP_ALL)
ud.inheritable = ocicapset.inheritable;
struct blob_buf b = { 0 };
int ret;
- DEBUG("dropping capabilities\n");
-
blob_buf_init(&b, 0);
ret = !blobmsg_add_json_from_file(&b, file);
if (ret) {
int parseOCIcapabilities(struct jail_capset *capset, struct blob_attr *msg);
int parseOCIcapabilities_from_file(struct jail_capset *capset, const char *file);
-int applyOCIcapabilities(struct jail_capset capset);
+int applyOCIcapabilities(struct jail_capset capset, uint64_t retain);
/* capget/capset syscall wrappers are provided by libc */
extern int capget(cap_user_header_t header, cap_user_data_t data);
#include <linux/filter.h>
#include <linux/limits.h>
#include <linux/nsfs.h>
+#include <linux/securebits.h>
#include <signal.h>
#include <inttypes.h>
static void post_start_hook(void)
{
- if (applyOCIcapabilities(opts.capset))
+ int pw_uid, pw_gid, gr_gid;
+
+ if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP)) {
+ ERROR("prctl(PR_SET_SECUREBITS) failed: %m\n");
exit(EXIT_FAILURE);
+ }
- if (!(opts.namespace & CLONE_NEWUSER) && (opts.setns.user == -1)) {
- int pw_uid, pw_gid, gr_gid;
- get_jail_user(&pw_uid, &pw_gid, &gr_gid);
+ /* drop capabilities, retain those still needed to further setup jail */
+ if (applyOCIcapabilities(opts.capset, (1LLU << CAP_SETGID) | (1LLU << CAP_SETUID) | (1LLU << CAP_SETPCAP)))
+ exit(EXIT_FAILURE);
- set_jail_user(opts.pw_uid?:pw_uid, opts.pw_gid?:pw_gid, opts.gr_gid?:gr_gid);
- }
+ /* use either cmdline-supplied user/group or uid/gid from OCI spec */
+ get_jail_user(&pw_uid, &pw_gid, &gr_gid);
+ set_jail_user(opts.pw_uid?:pw_uid, opts.pw_gid?:pw_gid, opts.gr_gid?:gr_gid);
if (opts.additional_gids &&
(setgroups(opts.num_additional_gids, opts.additional_gids) < 0)) {
if (opts.set_umask)
umask(opts.umask);
+ if (prctl(PR_SET_SECUREBITS, 0)) {
+ ERROR("prctl(PR_SET_SECUREBITS) failed: %m\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* drop remaining capabilities to end up with specified sets */
+ if (applyOCIcapabilities(opts.capset, 0))
+ exit(EXIT_FAILURE);
+
if (opts.no_new_privs && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
- ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %m\n");
+ ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %m\n");
exit(EXIT_FAILURE);
}