• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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