1 /*
2 * Copyright (c) 1997-8,2007-8,2019 Andrew G Morgan <morgan@kernel.org>
3 * Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk>
4 *
5 * This file deals with exchanging internal and textual
6 * representations of capability sets.
7 */
8
9 #ifndef _GNU_SOURCE
10 #define _GNU_SOURCE
11 #endif
12
13 #include <stdio.h>
14
15 #define LIBCAP_PLEASE_INCLUDE_ARRAY
16 #include "libcap.h"
17
18 static char const *_cap_names[__CAP_BITS] = LIBCAP_CAP_NAMES;
19
20 #include <ctype.h>
21 #include <limits.h>
22
23 #ifdef INCLUDE_GPERF_OUTPUT
24 /* we need to include it after #define _GNU_SOURCE is set */
25 #include INCLUDE_GPERF_OUTPUT
26 #endif
27
28 /* Maximum output text length */
29 #define CAP_TEXT_SIZE (__CAP_NAME_SIZE * __CAP_MAXBITS)
30
31 /*
32 * Parse a textual representation of capabilities, returning an internal
33 * representation.
34 */
35
36 #define raise_cap_mask(flat, c) (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c)
37
setbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)38 static void setbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
39 {
40 int n;
41 for (n = blks; n--; ) {
42 a->u[n].flat[set] |= b[n];
43 }
44 }
45
clrbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)46 static void clrbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
47 {
48 int n;
49 for (n = blks; n--; )
50 a->u[n].flat[set] &= ~b[n];
51 }
52
namcmp(char const * str,char const * nam)53 static char const *namcmp(char const *str, char const *nam)
54 {
55 while (*nam && tolower((unsigned char)*str) == *nam) {
56 str++;
57 nam++;
58 }
59 if (*nam || isalnum((unsigned char)*str) || *str == '_')
60 return NULL;
61 return str;
62 }
63
64 /*
65 * forceall forces all of the kernel named capabilities to be assigned
66 * the masked value, and zeroed otherwise. Note, if the kernel is ahead
67 * of libcap, the upper bits will be referred to by number.
68 */
forceall(__u32 * flat,__u32 value,unsigned blks)69 static void forceall(__u32 *flat, __u32 value, unsigned blks)
70 {
71 unsigned n;
72 cap_value_t cmb = cap_max_bits();
73 for (n = blks; n--; ) {
74 unsigned base = 32*n;
75 __u32 mask = 0;
76 if (cmb >= base + 32) {
77 mask = ~0;
78 } else if (cmb > base) {
79 mask = (unsigned) ((1ULL << (cmb % 32)) - 1);
80 }
81 flat[n] = value & mask;
82 }
83
84 return;
85 }
86
lookupname(char const ** strp)87 static int lookupname(char const **strp)
88 {
89 union {
90 char const *constp;
91 char *p;
92 } str;
93
94 str.constp = *strp;
95 if (isdigit(*str.constp)) {
96 unsigned long n = strtoul(str.constp, &str.p, 0);
97 if (n >= __CAP_MAXBITS)
98 return -1;
99 *strp = str.constp;
100 return n;
101 } else {
102 int c;
103 unsigned len;
104
105 for (len=0; (c = str.constp[len]); ++len) {
106 if (!(isalpha(c) || (c == '_'))) {
107 break;
108 }
109 }
110
111 #ifdef GPERF_DOWNCASE
112 const struct __cap_token_s *token_info;
113
114 token_info = __cap_lookup_name(str.constp, len);
115 if (token_info != NULL) {
116 *strp = str.constp + len;
117 return token_info->index;
118 }
119 #else /* ie., ndef GPERF_DOWNCASE */
120 char const *s;
121 unsigned n = cap_max_bits();
122 if (n > __CAP_BITS) {
123 n = __CAP_BITS;
124 }
125 while (n--) {
126 if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
127 *strp = s;
128 return n;
129 }
130 }
131 #endif /* def GPERF_DOWNCASE */
132
133 return -1; /* No definition available */
134 }
135 }
136
cap_from_text(const char * str)137 cap_t cap_from_text(const char *str)
138 {
139 cap_t res;
140 int n;
141 unsigned cap_blks;
142
143 if (str == NULL) {
144 _cap_debug("bad argument");
145 errno = EINVAL;
146 return NULL;
147 }
148
149 if (!(res = cap_init()))
150 return NULL;
151
152 switch (res->head.version) {
153 case _LINUX_CAPABILITY_VERSION_1:
154 cap_blks = _LINUX_CAPABILITY_U32S_1;
155 break;
156 case _LINUX_CAPABILITY_VERSION_2:
157 cap_blks = _LINUX_CAPABILITY_U32S_2;
158 break;
159 case _LINUX_CAPABILITY_VERSION_3:
160 cap_blks = _LINUX_CAPABILITY_U32S_3;
161 break;
162 default:
163 errno = EINVAL;
164 return NULL;
165 }
166
167 _cap_debug("%s", str);
168
169 for (;;) {
170 __u32 list[__CAP_BLKS];
171 char op;
172 int flags = 0, listed=0;
173
174 memset(list, 0, sizeof(__u32)*__CAP_BLKS);
175
176 /* skip leading spaces */
177 while (isspace((unsigned char)*str))
178 str++;
179 if (!*str) {
180 _cap_debugcap("e = ", *res, CAP_EFFECTIVE);
181 _cap_debugcap("i = ", *res, CAP_INHERITABLE);
182 _cap_debugcap("p = ", *res, CAP_PERMITTED);
183
184 return res;
185 }
186
187 /* identify caps specified by this clause */
188 if (isalnum((unsigned char)*str) || *str == '_') {
189 for (;;) {
190 if (namcmp(str, "all")) {
191 str += 3;
192 forceall(list, ~0, cap_blks);
193 } else {
194 n = lookupname(&str);
195 if (n == -1)
196 goto bad;
197 raise_cap_mask(list, n);
198 }
199 if (*str != ',')
200 break;
201 if (!isalnum((unsigned char)*++str) && *str != '_')
202 goto bad;
203 }
204 listed = 1;
205 } else if (*str == '+' || *str == '-') {
206 goto bad; /* require a list of capabilities */
207 } else {
208 forceall(list, ~0, cap_blks);
209 }
210
211 /* identify first operation on list of capabilities */
212 op = *str++;
213 if (op == '=' && (*str == '+' || *str == '-')) {
214 if (!listed)
215 goto bad;
216 op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */
217 } else if (op != '+' && op != '-' && op != '=')
218 goto bad;
219
220 /* cycle through list of actions */
221 do {
222 _cap_debug("next char = `%c'", *str);
223 if (*str && !isspace(*str)) {
224 switch (*str++) { /* Effective, Inheritable, Permitted */
225 case 'e':
226 flags |= LIBCAP_EFF;
227 break;
228 case 'i':
229 flags |= LIBCAP_INH;
230 break;
231 case 'p':
232 flags |= LIBCAP_PER;
233 break;
234 default:
235 goto bad;
236 }
237 } else if (op != '=') {
238 _cap_debug("only '=' can be followed by space");
239 goto bad;
240 }
241
242 _cap_debug("how to read?");
243 switch (op) { /* how do we interpret the caps? */
244 case '=':
245 case 'P': /* =+ */
246 case 'M': /* =- */
247 clrbits(res, list, CAP_EFFECTIVE, cap_blks);
248 clrbits(res, list, CAP_PERMITTED, cap_blks);
249 clrbits(res, list, CAP_INHERITABLE, cap_blks);
250 if (op == 'M')
251 goto minus;
252 /* fall through */
253 case '+':
254 if (flags & LIBCAP_EFF)
255 setbits(res, list, CAP_EFFECTIVE, cap_blks);
256 if (flags & LIBCAP_PER)
257 setbits(res, list, CAP_PERMITTED, cap_blks);
258 if (flags & LIBCAP_INH)
259 setbits(res, list, CAP_INHERITABLE, cap_blks);
260 break;
261 case '-':
262 minus:
263 if (flags & LIBCAP_EFF)
264 clrbits(res, list, CAP_EFFECTIVE, cap_blks);
265 if (flags & LIBCAP_PER)
266 clrbits(res, list, CAP_PERMITTED, cap_blks);
267 if (flags & LIBCAP_INH)
268 clrbits(res, list, CAP_INHERITABLE, cap_blks);
269 break;
270 }
271
272 /* new directive? */
273 if (*str == '+' || *str == '-') {
274 if (!listed) {
275 _cap_debug("for + & - must list capabilities");
276 goto bad;
277 }
278 flags = 0; /* reset the flags */
279 op = *str++;
280 if (!isalpha(*str))
281 goto bad;
282 }
283 } while (*str && !isspace(*str));
284 _cap_debug("next clause");
285 }
286
287 bad:
288 cap_free(res);
289 res = NULL;
290 errno = EINVAL;
291 return res;
292 }
293
294 /*
295 * lookup a capability name and return its numerical value
296 */
cap_from_name(const char * name,cap_value_t * value_p)297 int cap_from_name(const char *name, cap_value_t *value_p)
298 {
299 int n;
300
301 if (((n = lookupname(&name)) >= 0) && (value_p != NULL)) {
302 *value_p = (unsigned) n;
303 }
304 return -(n < 0);
305 }
306
307 /*
308 * Convert a single capability index number into a string representation
309 */
cap_to_name(cap_value_t cap)310 char *cap_to_name(cap_value_t cap)
311 {
312 if ((cap < 0) || (cap >= __CAP_BITS)) {
313 #if UINT_MAX != 4294967295U
314 # error Recompile with correctly sized numeric array
315 #endif
316 char *tmp, *result;
317
318 asprintf(&tmp, "%u", cap);
319 result = _libcap_strdup(tmp);
320 free(tmp);
321
322 return result;
323 } else {
324 return _libcap_strdup(_cap_names[cap]);
325 }
326 }
327
328 /*
329 * Convert an internal representation to a textual one. The textual
330 * representation is stored in static memory. It will be overwritten
331 * on the next occasion that this function is called.
332 */
333
getstateflags(cap_t caps,int capno)334 static int getstateflags(cap_t caps, int capno)
335 {
336 int f = 0;
337
338 if (isset_cap(caps, capno, CAP_EFFECTIVE)) {
339 f |= LIBCAP_EFF;
340 }
341 if (isset_cap(caps, capno, CAP_PERMITTED)) {
342 f |= LIBCAP_PER;
343 }
344 if (isset_cap(caps, capno, CAP_INHERITABLE)) {
345 f |= LIBCAP_INH;
346 }
347
348 return f;
349 }
350
351 #define CAP_TEXT_BUFFER_ZONE 100
352
cap_to_text(cap_t caps,ssize_t * length_p)353 char *cap_to_text(cap_t caps, ssize_t *length_p)
354 {
355 char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
356 char *p, *base;
357 int histo[8];
358 int m, t;
359 unsigned n;
360
361 /* Check arguments */
362 if (!good_cap_t(caps)) {
363 errno = EINVAL;
364 return NULL;
365 }
366
367 _cap_debugcap("e = ", *caps, CAP_EFFECTIVE);
368 _cap_debugcap("i = ", *caps, CAP_INHERITABLE);
369 _cap_debugcap("p = ", *caps, CAP_PERMITTED);
370
371 memset(histo, 0, sizeof(histo));
372
373 /* default prevailing state to the named bits */
374 cap_value_t cmb = cap_max_bits();
375 for (n = 0; n < cmb; n++)
376 histo[getstateflags(caps, n)]++;
377
378 /* find which combination of capability sets shares the most bits
379 we bias to preferring non-set (m=0) with the >= 0 test. Failing
380 to do this causes strange things to happen with older systems
381 that don't know about bits 32+. */
382 for (m=t=7; t--; )
383 if (histo[t] >= histo[m])
384 m = t;
385
386 /* blank is not a valid capability set */
387 base = buf;
388 p = sprintf(buf, "=%s%s%s",
389 (m & LIBCAP_EFF) ? "e" : "",
390 (m & LIBCAP_INH) ? "i" : "",
391 (m & LIBCAP_PER) ? "p" : "" ) + buf;
392
393 for (t = 8; t--; ) {
394 if (t == m || !histo[t]) {
395 continue;
396 }
397 *p++ = ' ';
398 for (n = 0; n < cmb; n++) {
399 if (getstateflags(caps, n) == t) {
400 char *this_cap_name = cap_to_name(n);
401 if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
402 cap_free(this_cap_name);
403 errno = ERANGE;
404 return NULL;
405 }
406 p += sprintf(p, "%s,", this_cap_name);
407 cap_free(this_cap_name);
408 }
409 }
410 p--;
411 n = t & ~m;
412 if (n) {
413 char op = '+';
414 if (base[0] == '=' && base[1] == ' ') {
415 /*
416 * Special case all lowered default "= foo,...+eip
417 * ..." as "foo,...=eip ...". (Equivalent but shorter.)
418 */
419 base += 2;
420 op = '=';
421 }
422 p += sprintf(p, "%c%s%s%s", op,
423 (n & LIBCAP_EFF) ? "e" : "",
424 (n & LIBCAP_INH) ? "i" : "",
425 (n & LIBCAP_PER) ? "p" : "");
426 }
427 n = ~t & m;
428 if (n) {
429 p += sprintf(p, "-%s%s%s",
430 (n & LIBCAP_EFF) ? "e" : "",
431 (n & LIBCAP_INH) ? "i" : "",
432 (n & LIBCAP_PER) ? "p" : "");
433 }
434 if (p - buf > CAP_TEXT_SIZE) {
435 errno = ERANGE;
436 return NULL;
437 }
438 }
439
440 /* capture remaining unnamed bits - which must all be +. */
441 memset(histo, 0, sizeof(histo));
442 for (n = cmb; n < __CAP_MAXBITS; n++)
443 histo[getstateflags(caps, n)]++;
444
445 for (t = 8; t-- > 1; ) {
446 if (!histo[t]) {
447 continue;
448 }
449 *p++ = ' ';
450 for (n = cmb; n < __CAP_MAXBITS; n++) {
451 if (getstateflags(caps, n) == t) {
452 char *this_cap_name = cap_to_name(n);
453 if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
454 cap_free(this_cap_name);
455 errno = ERANGE;
456 return NULL;
457 }
458 p += sprintf(p, "%s,", this_cap_name);
459 cap_free(this_cap_name);
460 }
461 }
462 p--;
463 p += sprintf(p, "+%s%s%s",
464 (t & LIBCAP_EFF) ? "e" : "",
465 (t & LIBCAP_INH) ? "i" : "",
466 (t & LIBCAP_PER) ? "p" : "");
467 if (p - buf > CAP_TEXT_SIZE) {
468 errno = ERANGE;
469 return NULL;
470 }
471 }
472
473 _cap_debug("%s", base);
474 if (length_p) {
475 *length_p = p - base;
476 }
477
478 return (_libcap_strdup(base));
479 }
480
481 /*
482 * cap_mode_name returns a text token naming the specified mode.
483 */
cap_mode_name(cap_mode_t flavor)484 const char *cap_mode_name(cap_mode_t flavor) {
485 switch (flavor) {
486 case CAP_MODE_NOPRIV:
487 return "NOPRIV";
488 case CAP_MODE_PURE1E_INIT:
489 return "PURE1E_INIT";
490 case CAP_MODE_PURE1E:
491 return "PURE1E";
492 case CAP_MODE_UNCERTAIN:
493 return "UNCERTAIN";
494 default:
495 return "UNKNOWN";
496 }
497 }
498
499 /*
500 * cap_iab_to_text serializes an iab into a canonical text
501 * representation.
502 */
cap_iab_to_text(cap_iab_t iab)503 char *cap_iab_to_text(cap_iab_t iab)
504 {
505 char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
506 char *p = buf;
507 cap_value_t c, cmb = cap_max_bits();
508 int first = 1;
509
510 if (good_cap_iab_t(iab)) {
511 for (c = 0; c < cmb; c++) {
512 int keep = 0;
513 int o = c >> 5;
514 __u32 bit = 1U << (c & 31);
515 __u32 ib = iab->i[o] & bit;
516 __u32 ab = iab->a[o] & bit;
517 __u32 nbb = iab->nb[o] & bit;
518 if (!(nbb | ab | ib)) {
519 continue;
520 }
521 if (!first) {
522 *p++ = ',';
523 }
524 if (nbb) {
525 *p++ = '!';
526 keep = 1;
527 }
528 if (ab) {
529 *p++ = '^';
530 keep = 1;
531 } else if (nbb && ib) {
532 *p++ = '%';
533 }
534 if (keep || ib) {
535 if (c < __CAP_BITS) {
536 strcpy(p, _cap_names[c]);
537 } else {
538 sprintf(p, "%u", c);
539 }
540 p += strlen(p);
541 first = 0;
542 }
543 }
544 }
545 *p = '\0';
546 return _libcap_strdup(buf);
547 }
548
cap_iab_from_text(const char * text)549 cap_iab_t cap_iab_from_text(const char *text)
550 {
551 cap_iab_t iab = cap_iab_init();
552 if (text != NULL) {
553 unsigned flags;
554 for (flags = 0; *text; text++) {
555 /* consume prefixes */
556 switch (*text) {
557 case '!':
558 flags |= LIBCAP_IAB_NB_FLAG;
559 continue;
560 case '^':
561 flags |= LIBCAP_IAB_IA_FLAG;
562 continue;
563 case '%':
564 flags |= LIBCAP_IAB_I_FLAG;
565 continue;
566 default:
567 break;
568 }
569 if (!flags) {
570 flags = LIBCAP_IAB_I_FLAG;
571 }
572
573 /* consume cap name */
574 cap_value_t c = lookupname(&text);
575 if (c == -1) {
576 goto cleanup;
577 }
578 unsigned o = c >> 5;
579 __u32 mask = 1U << (c & 31);
580 if (flags & LIBCAP_IAB_I_FLAG) {
581 iab->i[o] |= mask;
582 }
583 if (flags & LIBCAP_IAB_A_FLAG) {
584 iab->a[o] |= mask;
585 }
586 if (flags & LIBCAP_IAB_NB_FLAG) {
587 iab->nb[o] |= mask;
588 }
589
590 /* rest should be end or comma */
591 if (*text == '\0') {
592 break;
593 }
594 if (*text != ',') {
595 goto cleanup;
596 }
597 flags = 0;
598 }
599 }
600 return iab;
601
602 cleanup:
603 cap_free(iab);
604 errno = EINVAL;
605 return NULL;
606 }
607