提交 7ea554a3 编写于 作者: J Jonathan Calmels

Rework capabilities to support more unprivileged use-cases

上级 f06cbbbf
......@@ -173,20 +173,16 @@ configure_command(const struct context *ctx)
struct error err = {0};
int rv = EXIT_FAILURE;
if (geteuid() != 0) {
warnx("requires root privileges");
return (rv);
}
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
perm_drop_bounds(&err) < 0) {
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
warnx("permission error: %s", err.msg);
return (rv);
}
/* Initialize the library and container contexts. */
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -204,7 +200,7 @@ configure_command(const struct context *ctx)
warnx("initialization error: %s", nvc_error(nvc));
goto fail;
}
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_CONTAINER], effective_caps_size(CAPS_CONTAINER)) < 0) {
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_CONTAINER], ecaps_size(NVC_CONTAINER)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -215,7 +211,7 @@ configure_command(const struct context *ctx)
}
/* Query the driver and device information. */
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -263,7 +259,7 @@ configure_command(const struct context *ctx)
}
/* Mount the driver and visible devices. */
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_MOUNT], effective_caps_size(CAPS_MOUNT)) < 0) {
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_MOUNT], ecaps_size(NVC_MOUNT)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -279,7 +275,7 @@ configure_command(const struct context *ctx)
}
/* Update the container ldcache. */
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_LDCACHE], effective_caps_size(CAPS_LDCACHE)) < 0) {
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_LDCACHE], ecaps_size(NVC_LDCACHE)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -288,7 +284,7 @@ configure_command(const struct context *ctx)
goto fail;
}
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......
......@@ -53,27 +53,18 @@ info_command(const struct context *ctx)
int rv = EXIT_FAILURE;
run_as_root = (geteuid() == 0);
if (!run_as_root && (ctx->load_kmods || ctx->root != NULL)) {
warnx("requires root privileges");
return (rv);
}
if (run_as_root) {
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
perm_drop_bounds(&err) < 0) {
warnx("permission error: %s", err.msg);
return (rv);
}
} else {
if (perm_set_capabilities(&err, CAP_PERMITTED, NULL, 0) < 0) {
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
warnx("permission error: %s", err.msg);
return (rv);
}
}
/* Initialize the library context. */
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -92,7 +83,7 @@ info_command(const struct context *ctx)
}
/* Query the driver and device information. */
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -116,7 +107,7 @@ info_command(const struct context *ctx)
"Bus Location:", dev->gpus[i].busid, "Architecture:", dev->gpus[i].arch);
}
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......
......@@ -84,27 +84,18 @@ list_command(const struct context *ctx)
int rv = EXIT_FAILURE;
run_as_root = (geteuid() == 0);
if (!run_as_root && (ctx->load_kmods || ctx->root != NULL)) {
warnx("requires root privileges");
return (rv);
}
if (run_as_root) {
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
perm_drop_bounds(&err) < 0) {
warnx("permission error: %s", err.msg);
return (rv);
}
} else {
if (perm_set_capabilities(&err, CAP_PERMITTED, NULL, 0) < 0) {
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
warnx("permission error: %s", err.msg);
return (rv);
}
}
/* Initialize the library context. */
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -123,7 +114,7 @@ list_command(const struct context *ctx)
}
/* Query the driver and device information. */
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......@@ -169,7 +160,7 @@ list_command(const struct context *ctx)
printf("%s\n", drv->ipcs[i]);
}
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
warnx("permission error: %s", err.msg);
goto fail;
}
......
......@@ -175,8 +175,15 @@ load_kernel_modules(struct error *err, const char *root)
return (-1);
}
if (pid == 0) {
if (chroot(root) < 0 || chdir("/") < 0) {
log_errf("failed to change root directory: %s", strerror(errno));
if (!str_equal(root, "/")) {
if (chroot(root) < 0 || chdir("/") < 0) {
log_errf("failed to change root directory: %s", strerror(errno));
log_warn("skipping kernel modules load due to failure");
_exit(EXIT_FAILURE);
}
}
if (perm_set_capabilities(NULL, CAP_INHERITABLE, &(cap_value_t){CAP_SYS_MODULE}, 1) < 0) {
log_warn("failed to set inheritable capabilities");
log_warn("skipping kernel modules load due to failure");
_exit(EXIT_FAILURE);
}
......
......@@ -54,18 +54,18 @@ struct nvc_container {
};
enum {
CAPS_INIT,
CAPS_INIT_KMODS,
CAPS_SHUTDOWN,
CAPS_CONTAINER,
CAPS_INFO,
CAPS_MOUNT,
CAPS_LDCACHE,
NVC_INIT,
NVC_INIT_KMODS,
NVC_SHUTDOWN,
NVC_CONTAINER,
NVC_INFO,
NVC_MOUNT,
NVC_LDCACHE,
};
static const cap_value_t permitted_caps[] = {
static const cap_value_t pcaps[] = {
CAP_CHOWN, /* kmods */
CAP_DAC_OVERRIDE, /* rhel, cgroups */
CAP_DAC_OVERRIDE, /* rhel userns, cgroups */
CAP_DAC_READ_SEARCH, /* userns */
CAP_FOWNER, /* kmods */
CAP_KILL, /* privsep */
......@@ -78,30 +78,37 @@ static const cap_value_t permitted_caps[] = {
CAP_SYS_PTRACE, /* procns */
};
static const cap_value_t effective_caps[][nitems(permitted_caps) + 1] = {
[CAPS_INIT] = {CAP_KILL, CAP_SETGID, CAP_SETUID, CAP_SYS_CHROOT, -1},
[CAPS_INIT_KMODS] = {CAP_KILL, CAP_CHOWN, CAP_FOWNER, CAP_MKNOD, CAP_SETGID, CAP_SETUID, CAP_SYS_CHROOT, -1},
[CAPS_SHUTDOWN] = {CAP_KILL, -1},
[CAPS_CONTAINER] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, -1},
[CAPS_INFO] = {CAP_KILL, -1},
[CAPS_MOUNT] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SETGID, CAP_SETUID, CAP_SYS_ADMIN,
CAP_SYS_CHROOT, CAP_SYS_PTRACE, -1},
[CAPS_LDCACHE] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SETGID, CAP_SETPCAP, CAP_SETUID,
CAP_SYS_ADMIN, CAP_SYS_CHROOT, CAP_SYS_PTRACE, -1},
static const cap_value_t ecaps[][nitems(pcaps) + 1] = {
[NVC_INIT] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT, -1},
[NVC_INIT_KMODS] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
CAP_CHOWN, CAP_FOWNER, CAP_MKNOD, CAP_SETPCAP, -1},
[NVC_SHUTDOWN] = {CAP_KILL, -1},
[NVC_CONTAINER] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, -1},
[NVC_INFO] = {CAP_KILL, -1},
[NVC_MOUNT] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
CAP_SYS_ADMIN, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, CAP_DAC_OVERRIDE, -1},
[NVC_LDCACHE] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
CAP_SYS_ADMIN, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, CAP_SETPCAP, -1},
};
static const cap_value_t inherited_caps[] = {
static const cap_value_t bcaps[] = {
CAP_DAC_OVERRIDE,
CAP_SYS_MODULE,
};
static inline size_t
effective_caps_size(int idx)
ecaps_size(int idx)
{
size_t i;
for (i = 0; i < nitems(*effective_caps); ++i) {
if (effective_caps[idx][i] == -1)
for (i = 0; i < nitems(*ecaps); ++i) {
if (ecaps[idx][i] == -1)
break;
}
return (i);
......
......@@ -153,8 +153,6 @@ change_rootfs(struct error *err, const char *rootfs, bool mount_proc, bool *drop
static int
adjust_capabilities(struct error *err, uid_t uid, bool host_ldconfig)
{
cap_value_t cap = CAP_DAC_OVERRIDE;
/*
* Drop all the inheritable capabilities and the ambient capabilities consequently.
* Don't bother with the other capabilities, execve will take care of it.
......@@ -168,13 +166,13 @@ adjust_capabilities(struct error *err, uid_t uid, bool host_ldconfig)
* If allowed, set the CAP_DAC_OVERRIDE capability because some distributions rely on it
* (e.g. https://bugzilla.redhat.com/show_bug.cgi?id=517575).
*/
if (perm_set_capabilities(err, CAP_INHERITABLE, &cap, 1) < 0) {
if (perm_set_capabilities(err, CAP_INHERITABLE, &(cap_value_t){CAP_DAC_OVERRIDE}, 1) < 0) {
if (err->code != EPERM)
return (-1);
if (perm_set_capabilities(err, CAP_INHERITABLE, NULL, 0) < 0)
return (-1);
log_warn("could not set inheritable capabilities, containers may require additional tuning");
} else if (uid != 0 && perm_set_capabilities(err, CAP_AMBIENT, &cap, 1) < 0) {
} else if (uid != 0 && perm_set_capabilities(err, CAP_AMBIENT, &(cap_value_t){CAP_DAC_OVERRIDE}, 1) < 0) {
if (err->code != EPERM)
return (-1);
log_warn("could not set ambient capabilities, containers may require additional tuning");
......@@ -182,7 +180,7 @@ adjust_capabilities(struct error *err, uid_t uid, bool host_ldconfig)
}
/* Drop all the bounding set */
if (perm_drop_bounds(err) < 0)
if (perm_set_bounds(err, NULL, 0) < 0)
return (-1);
return (0);
......
......@@ -918,7 +918,7 @@ perm_drop_privileges(struct error *err, uid_t uid, gid_t gid, bool drop_groups)
}
int
perm_drop_bounds(struct error *err)
perm_set_bounds(struct error *err, const cap_value_t caps[], size_t size)
{
uint32_t n;
cap_value_t last_cap = CAP_LAST_CAP;
......@@ -929,10 +929,15 @@ perm_drop_bounds(struct error *err)
last_cap = (cap_value_t)n;
for (cap_value_t c = 0; c <= last_cap; ++c) {
for (size_t i = 0; caps != NULL && i < size; ++i) {
if (caps[i] == c)
goto next;
}
if (prctl(PR_CAPBSET_READ, c) > 0 && prctl(PR_CAPBSET_DROP, c) < 0) {
error_set(err, "capability change failed");
return (-1);
}
next:;
}
return (0);
}
......@@ -949,11 +954,9 @@ perm_set_capabilities(struct error *err, cap_flag_t type, const cap_value_t caps
/* Ambient capabilities are only supported since Linux 4.3 and are not available in libcap. */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0 && errno != EINVAL)
goto fail;
if (caps != NULL && size > 0) {
for (size_t i = 0; i < size; ++i) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, caps[i], 0, 0) < 0 && errno != EINVAL)
goto fail;
}
for (size_t i = 0; caps != NULL && i < size; ++i) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, caps[i], 0, 0) < 0 && errno != EINVAL)
goto fail;
}
return (0);
}
......@@ -971,13 +974,11 @@ perm_set_capabilities(struct error *err, cap_flag_t type, const cap_value_t caps
goto fail;
if (cap_clear_flag(state, CAP_EFFECTIVE) < 0)
goto fail;
if (caps != NULL && size > 0) {
for (size_t i = 0; i < size; ++i) {
if (cap_get_flag(tmp, caps[i], CAP_EFFECTIVE, &flag) < 0)
goto fail;
if (cap_set_flag(state, CAP_EFFECTIVE, 1, &caps[i], flag) < 0)
goto fail;
}
for (size_t i = 0; caps != NULL && i < size; ++i) {
if (cap_get_flag(tmp, caps[i], CAP_EFFECTIVE, &flag) < 0)
goto fail;
if (cap_set_flag(state, CAP_EFFECTIVE, 1, &caps[i], flag) < 0)
goto fail;
}
}
if (cap_set_proc(state) < 0)
......
......@@ -81,7 +81,7 @@ int path_resolve(struct error *, char *, const char *, const char *);
int path_resolve_full(struct error *, char *, const char *, const char *);
int perm_drop_privileges(struct error *, uid_t, gid_t, bool);
int perm_drop_bounds(struct error *);
int perm_set_bounds(struct error *, const cap_value_t [], size_t);
int perm_set_capabilities(struct error *, cap_flag_t, const cap_value_t [], size_t);
#endif /* HEADER_UTILS_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册