1 /*
2  * Copyright (c) 1997-8,2008,20 Andrew G. Morgan <morgan@kernel.org>
3  *
4  * This file deals with flipping of capabilities on internal
5  * capability sets as specified by POSIX.1e (formerlly, POSIX 6).
6  *
7  * It also contains similar code for bit flipping cap_iab_t values.
8  */
9 
10 #include "libcap.h"
11 
12 /*
13  * Return the state of a specified capability flag.  The state is
14  * returned as the contents of *raised.  The capability is from one of
15  * the sets stored in cap_d as specified by set and value
16  */
17 
cap_get_flag(cap_t cap_d,cap_value_t value,cap_flag_t set,cap_flag_value_t * raised)18 int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set,
19 		 cap_flag_value_t *raised)
20 {
21     /*
22      * Do we have a set and a place to store its value?
23      * Is it a known capability?
24      */
25 
26     if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_MAXBITS
27 	&& set >= 0 && set < NUMBER_OF_CAP_SETS) {
28 	*raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR;
29 	return 0;
30     } else {
31 	_cap_debug("invalid arguments");
32 	errno = EINVAL;
33 	return -1;
34     }
35 }
36 
37 /*
38  * raise/lower a selection of capabilities
39  */
40 
cap_set_flag(cap_t cap_d,cap_flag_t set,int no_values,const cap_value_t * array_values,cap_flag_value_t raise)41 int cap_set_flag(cap_t cap_d, cap_flag_t set,
42 		 int no_values, const cap_value_t *array_values,
43 		 cap_flag_value_t raise)
44 {
45     /*
46      * Do we have a set and a place to store its value?
47      * Is it a known capability?
48      */
49 
50     if (good_cap_t(cap_d) && no_values > 0 && no_values < __CAP_MAXBITS
51 	&& (set >= 0) && (set < NUMBER_OF_CAP_SETS)
52 	&& (raise == CAP_SET || raise == CAP_CLEAR) ) {
53 	int i;
54 	for (i=0; i<no_values; ++i) {
55 	    if (array_values[i] < 0 || array_values[i] >= __CAP_MAXBITS) {
56 		_cap_debug("weird capability (%d) - skipped", array_values[i]);
57 	    } else {
58 		int value = array_values[i];
59 
60 		if (raise == CAP_SET) {
61 		    cap_d->raise_cap(value,set);
62 		} else {
63 		    cap_d->lower_cap(value,set);
64 		}
65 	    }
66 	}
67 	return 0;
68 
69     } else {
70 
71 	_cap_debug("invalid arguments");
72 	errno = EINVAL;
73 	return -1;
74 
75     }
76 }
77 
78 /*
79  *  Reset the capability to be empty (nothing raised)
80  */
81 
cap_clear(cap_t cap_d)82 int cap_clear(cap_t cap_d)
83 {
84     if (good_cap_t(cap_d)) {
85 	memset(&(cap_d->u), 0, sizeof(cap_d->u));
86 	return 0;
87     } else {
88 	_cap_debug("invalid pointer");
89 	errno = EINVAL;
90 	return -1;
91     }
92 }
93 
94 /*
95  *  Reset the all of the capability bits for one of the flag sets
96  */
97 
cap_clear_flag(cap_t cap_d,cap_flag_t flag)98 int cap_clear_flag(cap_t cap_d, cap_flag_t flag)
99 {
100     switch (flag) {
101     case CAP_EFFECTIVE:
102     case CAP_PERMITTED:
103     case CAP_INHERITABLE:
104 	if (good_cap_t(cap_d)) {
105 	    unsigned i;
106 
107 	    for (i=0; i<_LIBCAP_CAPABILITY_U32S; i++) {
108 		cap_d->u[i].flat[flag] = 0;
109 	    }
110 	    return 0;
111 	}
112 	/*
113 	 * fall through
114 	 */
115 
116     default:
117 	_cap_debug("invalid pointer");
118 	errno = EINVAL;
119 	return -1;
120     }
121 }
122 
123 /*
124  * Compare two capability sets
125  */
cap_compare(cap_t a,cap_t b)126 int cap_compare(cap_t a, cap_t b)
127 {
128     unsigned i;
129     int result;
130 
131     if (!(good_cap_t(a) && good_cap_t(b))) {
132 	_cap_debug("invalid arguments");
133 	errno = EINVAL;
134 	return -1;
135     }
136 
137     for (i=0, result=0; i<_LIBCAP_CAPABILITY_U32S; i++) {
138 	result |=
139 	    ((a->u[i].flat[CAP_EFFECTIVE] != b->u[i].flat[CAP_EFFECTIVE])
140 	     ? LIBCAP_EFF : 0)
141 	    | ((a->u[i].flat[CAP_INHERITABLE] != b->u[i].flat[CAP_INHERITABLE])
142 	       ? LIBCAP_INH : 0)
143 	    | ((a->u[i].flat[CAP_PERMITTED] != b->u[i].flat[CAP_PERMITTED])
144 	       ? LIBCAP_PER : 0);
145     }
146     return result;
147 }
148 
149 /*
150  * cap_iab_get_vector reads the single bit value from an IAB vector set.
151  */
cap_iab_get_vector(cap_iab_t iab,cap_iab_vector_t vec,cap_value_t bit)152 cap_flag_value_t cap_iab_get_vector(cap_iab_t iab, cap_iab_vector_t vec,
153 				    cap_value_t bit)
154 {
155     if (!good_cap_iab_t(iab) || bit >= cap_max_bits()) {
156 	return 0;
157     }
158 
159     unsigned o = (bit >> 5);
160     __u32 mask = 1u << (bit & 31);
161 
162     switch (vec) {
163     case CAP_IAB_INH:
164 	return !!(iab->i[o] & mask);
165 	break;
166     case CAP_IAB_AMB:
167 	return !!(iab->a[o] & mask);
168 	break;
169     case CAP_IAB_BOUND:
170 	return !!(iab->nb[o] & mask);
171 	break;
172     default:
173 	return 0;
174     }
175 }
176 
177 /*
178  * cap_iab_set_vector sets the bits in an IAB to the value
179  * raised. Note, setting A implies setting I too, lowering I implies
180  * lowering A too.  The B bits are, however, independently settable.
181  */
cap_iab_set_vector(cap_iab_t iab,cap_iab_vector_t vec,cap_value_t bit,cap_flag_value_t raised)182 int cap_iab_set_vector(cap_iab_t iab, cap_iab_vector_t vec, cap_value_t bit,
183 		       cap_flag_value_t raised)
184 {
185     if (!good_cap_iab_t(iab) || (raised >> 1) || bit >= cap_max_bits()) {
186 	errno = EINVAL;
187 	return -1;
188     }
189 
190     unsigned o = (bit >> 5);
191     __u32 on = 1u << (bit & 31);
192     __u32 mask = ~on;
193 
194     switch (vec) {
195     case CAP_IAB_INH:
196 	iab->i[o] = (iab->i[o] & mask) | (raised ? on : 0);
197 	iab->a[o] &= iab->i[o];
198 	break;
199     case CAP_IAB_AMB:
200 	iab->a[o] = (iab->a[o] & mask) | (raised ? on : 0);
201 	iab->i[o] |= iab->a[o];
202 	break;
203     case CAP_IAB_BOUND:
204 	iab->nb[o] = (iab->nb[o] & mask) | (raised ? on : 0);
205 	break;
206     default:
207 	errno = EINVAL;
208 	return -1;
209     }
210 
211     return 0;
212 }
213 
214 /*
215  * cap_iab_fill copies a bit-vector of capability state from a cap_t
216  * to a cap_iab_t. Note, because the bounding bits in an iab are to be
217  * dropped when applied, the copying process, when to a CAP_IAB_BOUND
218  * vector involves inverting the bits. Also, adjusting I will mask
219  * bits in A, and adjusting A may implicitly raise bits in I.
220  */
cap_iab_fill(cap_iab_t iab,cap_iab_vector_t vec,cap_t cap_d,cap_flag_t flag)221 int cap_iab_fill(cap_iab_t iab, cap_iab_vector_t vec,
222 		 cap_t cap_d, cap_flag_t flag)
223 {
224     if (!good_cap_t(cap_d) || !good_cap_iab_t(iab)) {
225 	errno = EINVAL;
226 	return -1;
227     }
228 
229     switch (flag) {
230     case CAP_EFFECTIVE:
231     case CAP_INHERITABLE:
232     case CAP_PERMITTED:
233 	break;
234     default:
235 	errno = EINVAL;
236 	return -1;
237     }
238 
239     int i;
240     for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) {
241 	switch (vec) {
242 	case CAP_IAB_INH:
243 	    iab->i[i] = cap_d->u[i].flat[flag];
244 	    iab->a[i] &= iab->i[i];
245 	    break;
246 	case CAP_IAB_AMB:
247 	    iab->a[i] = cap_d->u[i].flat[flag];
248 	    iab->i[i] |= cap_d->u[i].flat[flag];
249 	    break;
250 	case CAP_IAB_BOUND:
251 	    iab->nb[i] = ~cap_d->u[i].flat[flag];
252 	    break;
253 	default:
254 	    errno = EINVAL;
255 	    return -1;
256 	}
257     }
258 
259     return 0;
260 }
261