Skip to content

Commit 7ea554a

Browse files
committed
Rework capabilities to support more unprivileged use-cases
1 parent f06cbbb commit 7ea554a

File tree

8 files changed

+81
-90
lines changed

8 files changed

+81
-90
lines changed

src/cli/configure.c

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -173,20 +173,16 @@ configure_command(const struct context *ctx)
173173
struct error err = {0};
174174
int rv = EXIT_FAILURE;
175175

176-
if (geteuid() != 0) {
177-
warnx("requires root privileges");
178-
return (rv);
179-
}
180-
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
181-
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
182-
perm_drop_bounds(&err) < 0) {
176+
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
177+
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
178+
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
183179
warnx("permission error: %s", err.msg);
184180
return (rv);
185181
}
186182

187183
/* Initialize the library and container contexts. */
188-
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
189-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
184+
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
185+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
190186
warnx("permission error: %s", err.msg);
191187
goto fail;
192188
}
@@ -204,7 +200,7 @@ configure_command(const struct context *ctx)
204200
warnx("initialization error: %s", nvc_error(nvc));
205201
goto fail;
206202
}
207-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_CONTAINER], effective_caps_size(CAPS_CONTAINER)) < 0) {
203+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_CONTAINER], ecaps_size(NVC_CONTAINER)) < 0) {
208204
warnx("permission error: %s", err.msg);
209205
goto fail;
210206
}
@@ -215,7 +211,7 @@ configure_command(const struct context *ctx)
215211
}
216212

217213
/* Query the driver and device information. */
218-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
214+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
219215
warnx("permission error: %s", err.msg);
220216
goto fail;
221217
}
@@ -263,7 +259,7 @@ configure_command(const struct context *ctx)
263259
}
264260

265261
/* Mount the driver and visible devices. */
266-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_MOUNT], effective_caps_size(CAPS_MOUNT)) < 0) {
262+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_MOUNT], ecaps_size(NVC_MOUNT)) < 0) {
267263
warnx("permission error: %s", err.msg);
268264
goto fail;
269265
}
@@ -279,7 +275,7 @@ configure_command(const struct context *ctx)
279275
}
280276

281277
/* Update the container ldcache. */
282-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_LDCACHE], effective_caps_size(CAPS_LDCACHE)) < 0) {
278+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_LDCACHE], ecaps_size(NVC_LDCACHE)) < 0) {
283279
warnx("permission error: %s", err.msg);
284280
goto fail;
285281
}
@@ -288,7 +284,7 @@ configure_command(const struct context *ctx)
288284
goto fail;
289285
}
290286

291-
if (perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
287+
if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
292288
warnx("permission error: %s", err.msg);
293289
goto fail;
294290
}

src/cli/info.c

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,18 @@ info_command(const struct context *ctx)
5353
int rv = EXIT_FAILURE;
5454

5555
run_as_root = (geteuid() == 0);
56-
if (!run_as_root && (ctx->load_kmods || ctx->root != NULL)) {
57-
warnx("requires root privileges");
58-
return (rv);
59-
}
6056
if (run_as_root) {
61-
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
62-
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
63-
perm_drop_bounds(&err) < 0) {
64-
warnx("permission error: %s", err.msg);
65-
return (rv);
66-
}
67-
} else {
68-
if (perm_set_capabilities(&err, CAP_PERMITTED, NULL, 0) < 0) {
57+
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
58+
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
59+
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
6960
warnx("permission error: %s", err.msg);
7061
return (rv);
7162
}
7263
}
7364

7465
/* Initialize the library context. */
75-
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
76-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
66+
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
67+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
7768
warnx("permission error: %s", err.msg);
7869
goto fail;
7970
}
@@ -92,7 +83,7 @@ info_command(const struct context *ctx)
9283
}
9384

9485
/* Query the driver and device information. */
95-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
86+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
9687
warnx("permission error: %s", err.msg);
9788
goto fail;
9889
}
@@ -116,7 +107,7 @@ info_command(const struct context *ctx)
116107
"Bus Location:", dev->gpus[i].busid, "Architecture:", dev->gpus[i].arch);
117108
}
118109

119-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
110+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
120111
warnx("permission error: %s", err.msg);
121112
goto fail;
122113
}

src/cli/list.c

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,18 @@ list_command(const struct context *ctx)
8484
int rv = EXIT_FAILURE;
8585

8686
run_as_root = (geteuid() == 0);
87-
if (!run_as_root && (ctx->load_kmods || ctx->root != NULL)) {
88-
warnx("requires root privileges");
89-
return (rv);
90-
}
9187
if (run_as_root) {
92-
if (perm_set_capabilities(&err, CAP_PERMITTED, permitted_caps, nitems(permitted_caps)) < 0 ||
93-
perm_set_capabilities(&err, CAP_INHERITABLE, inherited_caps, nitems(inherited_caps)) < 0 ||
94-
perm_drop_bounds(&err) < 0) {
95-
warnx("permission error: %s", err.msg);
96-
return (rv);
97-
}
98-
} else {
99-
if (perm_set_capabilities(&err, CAP_PERMITTED, NULL, 0) < 0) {
88+
if (perm_set_capabilities(&err, CAP_PERMITTED, pcaps, nitems(pcaps)) < 0 ||
89+
perm_set_capabilities(&err, CAP_INHERITABLE, NULL, 0) < 0 ||
90+
perm_set_bounds(&err, bcaps, nitems(bcaps)) < 0) {
10091
warnx("permission error: %s", err.msg);
10192
return (rv);
10293
}
10394
}
10495

10596
/* Initialize the library context. */
106-
int c = ctx->load_kmods ? CAPS_INIT_KMODS : CAPS_INIT;
107-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[c], effective_caps_size(c)) < 0) {
97+
int c = ctx->load_kmods ? NVC_INIT_KMODS : NVC_INIT;
98+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[c], ecaps_size(c)) < 0) {
10899
warnx("permission error: %s", err.msg);
109100
goto fail;
110101
}
@@ -123,7 +114,7 @@ list_command(const struct context *ctx)
123114
}
124115

125116
/* Query the driver and device information. */
126-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_INFO], effective_caps_size(CAPS_INFO)) < 0) {
117+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_INFO], ecaps_size(NVC_INFO)) < 0) {
127118
warnx("permission error: %s", err.msg);
128119
goto fail;
129120
}
@@ -169,7 +160,7 @@ list_command(const struct context *ctx)
169160
printf("%s\n", drv->ipcs[i]);
170161
}
171162

172-
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, effective_caps[CAPS_SHUTDOWN], effective_caps_size(CAPS_SHUTDOWN)) < 0) {
163+
if (run_as_root && perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_SHUTDOWN], ecaps_size(NVC_SHUTDOWN)) < 0) {
173164
warnx("permission error: %s", err.msg);
174165
goto fail;
175166
}

src/nvc.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,15 @@ load_kernel_modules(struct error *err, const char *root)
175175
return (-1);
176176
}
177177
if (pid == 0) {
178-
if (chroot(root) < 0 || chdir("/") < 0) {
179-
log_errf("failed to change root directory: %s", strerror(errno));
178+
if (!str_equal(root, "/")) {
179+
if (chroot(root) < 0 || chdir("/") < 0) {
180+
log_errf("failed to change root directory: %s", strerror(errno));
181+
log_warn("skipping kernel modules load due to failure");
182+
_exit(EXIT_FAILURE);
183+
}
184+
}
185+
if (perm_set_capabilities(NULL, CAP_INHERITABLE, &(cap_value_t){CAP_SYS_MODULE}, 1) < 0) {
186+
log_warn("failed to set inheritable capabilities");
180187
log_warn("skipping kernel modules load due to failure");
181188
_exit(EXIT_FAILURE);
182189
}

src/nvc_internal.h

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,18 @@ struct nvc_container {
5454
};
5555

5656
enum {
57-
CAPS_INIT,
58-
CAPS_INIT_KMODS,
59-
CAPS_SHUTDOWN,
60-
CAPS_CONTAINER,
61-
CAPS_INFO,
62-
CAPS_MOUNT,
63-
CAPS_LDCACHE,
57+
NVC_INIT,
58+
NVC_INIT_KMODS,
59+
NVC_SHUTDOWN,
60+
NVC_CONTAINER,
61+
NVC_INFO,
62+
NVC_MOUNT,
63+
NVC_LDCACHE,
6464
};
6565

66-
static const cap_value_t permitted_caps[] = {
66+
static const cap_value_t pcaps[] = {
6767
CAP_CHOWN, /* kmods */
68-
CAP_DAC_OVERRIDE, /* rhel, cgroups */
68+
CAP_DAC_OVERRIDE, /* rhel userns, cgroups */
6969
CAP_DAC_READ_SEARCH, /* userns */
7070
CAP_FOWNER, /* kmods */
7171
CAP_KILL, /* privsep */
@@ -78,30 +78,37 @@ static const cap_value_t permitted_caps[] = {
7878
CAP_SYS_PTRACE, /* procns */
7979
};
8080

81-
static const cap_value_t effective_caps[][nitems(permitted_caps) + 1] = {
82-
[CAPS_INIT] = {CAP_KILL, CAP_SETGID, CAP_SETUID, CAP_SYS_CHROOT, -1},
83-
[CAPS_INIT_KMODS] = {CAP_KILL, CAP_CHOWN, CAP_FOWNER, CAP_MKNOD, CAP_SETGID, CAP_SETUID, CAP_SYS_CHROOT, -1},
84-
[CAPS_SHUTDOWN] = {CAP_KILL, -1},
85-
[CAPS_CONTAINER] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, -1},
86-
[CAPS_INFO] = {CAP_KILL, -1},
87-
[CAPS_MOUNT] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SETGID, CAP_SETUID, CAP_SYS_ADMIN,
88-
CAP_SYS_CHROOT, CAP_SYS_PTRACE, -1},
89-
[CAPS_LDCACHE] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SETGID, CAP_SETPCAP, CAP_SETUID,
90-
CAP_SYS_ADMIN, CAP_SYS_CHROOT, CAP_SYS_PTRACE, -1},
81+
static const cap_value_t ecaps[][nitems(pcaps) + 1] = {
82+
[NVC_INIT] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT, -1},
83+
84+
[NVC_INIT_KMODS] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
85+
CAP_CHOWN, CAP_FOWNER, CAP_MKNOD, CAP_SETPCAP, -1},
86+
87+
[NVC_SHUTDOWN] = {CAP_KILL, -1},
88+
89+
[NVC_CONTAINER] = {CAP_KILL, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, -1},
90+
91+
[NVC_INFO] = {CAP_KILL, -1},
92+
93+
[NVC_MOUNT] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
94+
CAP_SYS_ADMIN, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, CAP_DAC_OVERRIDE, -1},
95+
96+
[NVC_LDCACHE] = {CAP_KILL, CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT,
97+
CAP_SYS_ADMIN, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, CAP_SETPCAP, -1},
9198
};
9299

93-
static const cap_value_t inherited_caps[] = {
100+
static const cap_value_t bcaps[] = {
94101
CAP_DAC_OVERRIDE,
95102
CAP_SYS_MODULE,
96103
};
97104

98105
static inline size_t
99-
effective_caps_size(int idx)
106+
ecaps_size(int idx)
100107
{
101108
size_t i;
102109

103-
for (i = 0; i < nitems(*effective_caps); ++i) {
104-
if (effective_caps[idx][i] == -1)
110+
for (i = 0; i < nitems(*ecaps); ++i) {
111+
if (ecaps[idx][i] == -1)
105112
break;
106113
}
107114
return (i);

src/nvc_ldcache.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,6 @@ change_rootfs(struct error *err, const char *rootfs, bool mount_proc, bool *drop
153153
static int
154154
adjust_capabilities(struct error *err, uid_t uid, bool host_ldconfig)
155155
{
156-
cap_value_t cap = CAP_DAC_OVERRIDE;
157-
158156
/*
159157
* Drop all the inheritable capabilities and the ambient capabilities consequently.
160158
* Don't bother with the other capabilities, execve will take care of it.
@@ -168,21 +166,21 @@ adjust_capabilities(struct error *err, uid_t uid, bool host_ldconfig)
168166
* If allowed, set the CAP_DAC_OVERRIDE capability because some distributions rely on it
169167
* (e.g. https://bugzilla.redhat.com/show_bug.cgi?id=517575).
170168
*/
171-
if (perm_set_capabilities(err, CAP_INHERITABLE, &cap, 1) < 0) {
169+
if (perm_set_capabilities(err, CAP_INHERITABLE, &(cap_value_t){CAP_DAC_OVERRIDE}, 1) < 0) {
172170
if (err->code != EPERM)
173171
return (-1);
174172
if (perm_set_capabilities(err, CAP_INHERITABLE, NULL, 0) < 0)
175173
return (-1);
176174
log_warn("could not set inheritable capabilities, containers may require additional tuning");
177-
} else if (uid != 0 && perm_set_capabilities(err, CAP_AMBIENT, &cap, 1) < 0) {
175+
} else if (uid != 0 && perm_set_capabilities(err, CAP_AMBIENT, &(cap_value_t){CAP_DAC_OVERRIDE}, 1) < 0) {
178176
if (err->code != EPERM)
179177
return (-1);
180178
log_warn("could not set ambient capabilities, containers may require additional tuning");
181179
}
182180
}
183181

184182
/* Drop all the bounding set */
185-
if (perm_drop_bounds(err) < 0)
183+
if (perm_set_bounds(err, NULL, 0) < 0)
186184
return (-1);
187185

188186
return (0);

src/utils.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ perm_drop_privileges(struct error *err, uid_t uid, gid_t gid, bool drop_groups)
918918
}
919919

920920
int
921-
perm_drop_bounds(struct error *err)
921+
perm_set_bounds(struct error *err, const cap_value_t caps[], size_t size)
922922
{
923923
uint32_t n;
924924
cap_value_t last_cap = CAP_LAST_CAP;
@@ -929,10 +929,15 @@ perm_drop_bounds(struct error *err)
929929
last_cap = (cap_value_t)n;
930930

931931
for (cap_value_t c = 0; c <= last_cap; ++c) {
932+
for (size_t i = 0; caps != NULL && i < size; ++i) {
933+
if (caps[i] == c)
934+
goto next;
935+
}
932936
if (prctl(PR_CAPBSET_READ, c) > 0 && prctl(PR_CAPBSET_DROP, c) < 0) {
933937
error_set(err, "capability change failed");
934938
return (-1);
935939
}
940+
next:;
936941
}
937942
return (0);
938943
}
@@ -949,11 +954,9 @@ perm_set_capabilities(struct error *err, cap_flag_t type, const cap_value_t caps
949954
/* Ambient capabilities are only supported since Linux 4.3 and are not available in libcap. */
950955
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) < 0 && errno != EINVAL)
951956
goto fail;
952-
if (caps != NULL && size > 0) {
953-
for (size_t i = 0; i < size; ++i) {
954-
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, caps[i], 0, 0) < 0 && errno != EINVAL)
955-
goto fail;
956-
}
957+
for (size_t i = 0; caps != NULL && i < size; ++i) {
958+
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, caps[i], 0, 0) < 0 && errno != EINVAL)
959+
goto fail;
957960
}
958961
return (0);
959962
}
@@ -971,13 +974,11 @@ perm_set_capabilities(struct error *err, cap_flag_t type, const cap_value_t caps
971974
goto fail;
972975
if (cap_clear_flag(state, CAP_EFFECTIVE) < 0)
973976
goto fail;
974-
if (caps != NULL && size > 0) {
975-
for (size_t i = 0; i < size; ++i) {
976-
if (cap_get_flag(tmp, caps[i], CAP_EFFECTIVE, &flag) < 0)
977-
goto fail;
978-
if (cap_set_flag(state, CAP_EFFECTIVE, 1, &caps[i], flag) < 0)
979-
goto fail;
980-
}
977+
for (size_t i = 0; caps != NULL && i < size; ++i) {
978+
if (cap_get_flag(tmp, caps[i], CAP_EFFECTIVE, &flag) < 0)
979+
goto fail;
980+
if (cap_set_flag(state, CAP_EFFECTIVE, 1, &caps[i], flag) < 0)
981+
goto fail;
981982
}
982983
}
983984
if (cap_set_proc(state) < 0)

src/utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ int path_resolve(struct error *, char *, const char *, const char *);
8181
int path_resolve_full(struct error *, char *, const char *, const char *);
8282

8383
int perm_drop_privileges(struct error *, uid_t, gid_t, bool);
84-
int perm_drop_bounds(struct error *);
84+
int perm_set_bounds(struct error *, const cap_value_t [], size_t);
8585
int perm_set_capabilities(struct error *, cap_flag_t, const cap_value_t [], size_t);
8686

8787
#endif /* HEADER_UTILS_H */

0 commit comments

Comments
 (0)