aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-07-07 01:59:45 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-07 01:59:45 +0200
commit0f49f6f9265ed339e69868708e4d303592a70507 (patch)
tree2c1618ae18f6ac9a2e532d8bda56a722bd276dd2
parent5e0987405cb966ec041db96b75169bb992fb710e (diff)
downloadbusybox-w32-0f49f6f9265ed339e69868708e4d303592a70507.tar.gz
busybox-w32-0f49f6f9265ed339e69868708e4d303592a70507.tar.bz2
busybox-w32-0f49f6f9265ed339e69868708e4d303592a70507.zip
setpriv: allow modifying inheritable caps
The main use case of setpriv is to modify the current state of privileges available to the calling process and spawn a new executable with the modified, new state. Next to the already supported case of modifying the no-new-privs flag, util-linux also supports to modify capability sets. This commit introduces to add or drop capabilities from the set of inheritable capabilities. Quoting from capabilities(7): This is a set of capabilities preserved across an execve(2). Inheritable capabilities remain inheritable when executing any program, and inheritable capabilities are added to the permitted set when executing a program that has the corresponding bits set in the file inheritable set. As such, inheritable capabilities enable executing files with certain privileges if the file itself has these privileges set. Note though that inheritable capabilities are dropped across execve when running as a non-root user. function old new delta getcaps - 237 +237 setpriv_main 1129 1246 +117 .rodata 146198 146307 +109 static.setpriv_longopts 29 40 +11 packed_usage 32107 32092 -15 Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--util-linux/setpriv.c106
1 files changed, 95 insertions, 11 deletions
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 89fa2fc10..a1fa889e7 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -56,6 +56,9 @@
56//usage: "\n-d,--dump Show current capabilities" 56//usage: "\n-d,--dump Show current capabilities"
57//usage: ) 57//usage: )
58//usage: "\n--nnp,--no-new-privs Ignore setuid/setgid bits and file capabilities" 58//usage: "\n--nnp,--no-new-privs Ignore setuid/setgid bits and file capabilities"
59//usage: IF_FEATURE_SETPRIV_CAPABILITIES(
60//usage: "\n--inh-caps CAP[,CAP...] Set inheritable capabilities"
61//usage: )
59 62
60//setpriv from util-linux 2.28: 63//setpriv from util-linux 2.28:
61// -d, --dump show current state (and do not exec anything) 64// -d, --dump show current state (and do not exec anything)
@@ -101,9 +104,11 @@
101 104
102enum { 105enum {
103 IF_FEATURE_SETPRIV_DUMP(OPTBIT_DUMP,) 106 IF_FEATURE_SETPRIV_DUMP(OPTBIT_DUMP,)
107 IF_FEATURE_SETPRIV_CAPABILITIES(OPTBIT_INH,)
104 OPTBIT_NNP, 108 OPTBIT_NNP,
105 109
106 IF_FEATURE_SETPRIV_DUMP(OPT_DUMP = (1 << OPTBIT_DUMP),) 110 IF_FEATURE_SETPRIV_DUMP(OPT_DUMP = (1 << OPTBIT_DUMP),)
111 IF_FEATURE_SETPRIV_CAPABILITIES(OPT_INH = (1 << OPTBIT_INH),)
107 OPT_NNP = (1 << OPTBIT_NNP), 112 OPT_NNP = (1 << OPTBIT_NNP),
108}; 113};
109 114
@@ -159,8 +164,7 @@ static const char *const capabilities[] = {
159 164
160#endif /* FEATURE_SETPRIV_CAPABILITIES */ 165#endif /* FEATURE_SETPRIV_CAPABILITIES */
161 166
162#if ENABLE_FEATURE_SETPRIV_DUMP 167#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
163# if ENABLE_FEATURE_SETPRIV_CAPABILITIES
164static void getcaps(struct caps *caps) 168static void getcaps(struct caps *caps)
165{ 169{
166 int versions[] = { 170 int versions[] = {
@@ -197,8 +201,9 @@ static void getcaps(struct caps *caps)
197 if (capget(&caps->header, caps->data) < 0) 201 if (capget(&caps->header, caps->data) < 0)
198 bb_simple_perror_msg_and_die("capget"); 202 bb_simple_perror_msg_and_die("capget");
199} 203}
200# endif /* FEATURE_SETPRIV_CAPABILITIES */ 204#endif /* FEATURE_SETPRIV_CAPABILITIES */
201 205
206#if ENABLE_FEATURE_SETPRIV_DUMP
202static int dump(void) 207static int dump(void)
203{ 208{
204 IF_FEATURE_SETPRIV_CAPABILITIES(struct caps caps;) 209 IF_FEATURE_SETPRIV_CAPABILITIES(struct caps caps;)
@@ -215,7 +220,7 @@ static int dump(void)
215 220
216 nnp = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0); 221 nnp = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
217 if (nnp < 0) 222 if (nnp < 0)
218 bb_simple_perror_msg_and_die("prctl: GET_NO_NEW_PRIVS"); 223 bb_perror_msg_and_die("prctl: %s", "GET_NO_NEW_PRIVS");
219 224
220 printf("uid: %u\n", (unsigned)ruid); 225 printf("uid: %u\n", (unsigned)ruid);
221 printf("euid: %u\n", (unsigned)euid); 226 printf("euid: %u\n", (unsigned)euid);
@@ -262,7 +267,7 @@ static int dump(void)
262 for (i = 0; cap_valid(i); i++) { 267 for (i = 0; cap_valid(i); i++) {
263 int ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, (unsigned long) i, 0UL, 0UL); 268 int ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, (unsigned long) i, 0UL, 0UL);
264 if (ret < 0) 269 if (ret < 0)
265 bb_simple_perror_msg_and_die("prctl: CAP_AMBIENT_IS_SET"); 270 bb_perror_msg_and_die("prctl: %s", "CAP_AMBIENT_IS_SET");
266 if (ret) { 271 if (ret) {
267# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES 272# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
268 if (i < ARRAY_SIZE(capabilities)) 273 if (i < ARRAY_SIZE(capabilities))
@@ -283,7 +288,7 @@ static int dump(void)
283 for (i = 0; cap_valid(i); i++) { 288 for (i = 0; cap_valid(i); i++) {
284 int ret = prctl(PR_CAPBSET_READ, (unsigned long) i, 0UL, 0UL, 0UL); 289 int ret = prctl(PR_CAPBSET_READ, (unsigned long) i, 0UL, 0UL, 0UL);
285 if (ret < 0) 290 if (ret < 0)
286 bb_simple_perror_msg_and_die("prctl: CAPBSET_READ"); 291 bb_perror_msg_and_die("prctl: %s", "CAPBSET_READ");
287 if (ret) { 292 if (ret) {
288# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES 293# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
289 if (i < ARRAY_SIZE(capabilities)) 294 if (i < ARRAY_SIZE(capabilities))
@@ -307,20 +312,94 @@ static int dump(void)
307} 312}
308#endif /* FEATURE_SETPRIV_DUMP */ 313#endif /* FEATURE_SETPRIV_DUMP */
309 314
315#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
316static void parse_cap(unsigned long *index, int *add, const char *cap)
317{
318 unsigned long i;
319
320 switch (cap[0]) {
321 case '-':
322 *add = 0;
323 break;
324 case '+':
325 *add = 1;
326 break;
327 default:
328 bb_error_msg_and_die("invalid capability '%s'", cap);
329 break;
330 }
331
332 cap++;
333 if ((sscanf(cap, "cap_%lu", &i)) == 1) {
334 if (!cap_valid(i))
335 bb_error_msg_and_die("unsupported capability '%s'", cap);
336 *index = i;
337 return;
338 }
339
340# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
341 for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
342 if (strcmp(capabilities[i], cap) != 0)
343 continue;
344
345 if (!cap_valid(i))
346 bb_error_msg_and_die("unsupported capability '%s'", cap);
347 *index = i;
348 return;
349 }
350# endif
351
352 bb_error_msg_and_die("unknown capability '%s'", cap);
353}
354
355static void set_inh_caps(char *capstring)
356{
357 struct caps caps;
358
359 getcaps(&caps);
360
361 capstring = strtok(capstring, ",");
362 while (capstring) {
363 unsigned long cap;
364 int add;
365
366 parse_cap(&cap, &add, capstring);
367 if (CAP_TO_INDEX(cap) >= caps.u32s)
368 bb_error_msg_and_die("invalid capability cap");
369 if (add)
370 caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap);
371 else
372 caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap);
373 capstring = strtok(NULL, ",");
374 }
375
376 if ((capset(&caps.header, caps.data)) < 0)
377 bb_perror_msg_and_die("capset");
378
379 if (ENABLE_FEATURE_CLEAN_UP)
380 free(caps.data);
381}
382#endif /* FEATURE_SETPRIV_CAPABILITIES */
383
310int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 384int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
311int setpriv_main(int argc UNUSED_PARAM, char **argv) 385int setpriv_main(int argc UNUSED_PARAM, char **argv)
312{ 386{
313 static const char setpriv_longopts[] ALIGN1 = 387 static const char setpriv_longopts[] ALIGN1 =
314 IF_FEATURE_SETPRIV_DUMP( 388 IF_FEATURE_SETPRIV_DUMP(
315 "dump\0" No_argument "d" 389 "dump\0" No_argument "d"
390 )
391 "nnp\0" No_argument "\xff"
392 "no-new-privs\0" No_argument "\xff"
393 IF_FEATURE_SETPRIV_CAPABILITIES(
394 "inh-caps\0" Required_argument "\xfe"
316 ) 395 )
317 "nnp\0" No_argument "\xff"
318 "no-new-privs\0" No_argument "\xff"
319 ; 396 ;
320 int opts; 397 int opts;
398 IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps;)
321 399
322 applet_long_options = setpriv_longopts; 400 applet_long_options = setpriv_longopts;
323 opts = getopt32(argv, "+"IF_FEATURE_SETPRIV_DUMP("d")); 401 opts = getopt32(argv, "+"IF_FEATURE_SETPRIV_DUMP("d")
402 IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:", &inh_caps));
324 argv += optind; 403 argv += optind;
325 404
326#if ENABLE_FEATURE_SETPRIV_DUMP 405#if ENABLE_FEATURE_SETPRIV_DUMP
@@ -332,9 +411,14 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv)
332#endif 411#endif
333 if (opts & OPT_NNP) { 412 if (opts & OPT_NNP) {
334 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) 413 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
335 bb_simple_perror_msg_and_die("prctl: NO_NEW_PRIVS"); 414 bb_perror_msg_and_die("prctl: %s", "SET_NO_NEW_PRIVS");
336 } 415 }
337 416
417#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
418 if (opts & OPT_INH)
419 set_inh_caps(inh_caps);
420#endif
421
338 if (!argv[0]) 422 if (!argv[0])
339 bb_show_usage(); 423 bb_show_usage();
340 BB_EXECVP_or_die(argv); 424 BB_EXECVP_or_die(argv);