1 /*
2 * Copyright (c) 1997-8,2019,2021 Andrew G Morgan <[email protected]>
3 *
4 * This file deals with allocation and deallocation of internal
5 * capability sets as specified by POSIX.1e (formerlly, POSIX 6).
6 */
7
8 #include "libcap.h"
9
10 /*
11 * Make start up atomic.
12 */
13 static __u8 __libcap_mutex;
14
15 /*
16 * These get set via the pre-main() executed constructor function below it.
17 */
18 static cap_value_t _cap_max_bits;
19
20 __attribute__((visibility ("hidden")))
_libcap_initialize(void)21 __attribute__((constructor (300))) void _libcap_initialize(void)
22 {
23 int errno_saved = errno;
24 _cap_mu_lock(&__libcap_mutex);
25 if (!_cap_max_bits) {
26 cap_set_syscall(NULL, NULL);
27 _binary_search(_cap_max_bits, cap_get_bound, 0, __CAP_MAXBITS,
28 __CAP_BITS);
29 }
30 _cap_mu_unlock(&__libcap_mutex);
31 errno = errno_saved;
32 }
33
cap_max_bits(void)34 cap_value_t cap_max_bits(void)
35 {
36 return _cap_max_bits;
37 }
38
39 /*
40 * capability allocation is all done in terms of this structure.
41 */
42 struct _cap_alloc_s {
43 __u32 magic;
44 __u32 size;
45 union {
46 struct _cap_struct set;
47 struct cap_iab_s iab;
48 struct cap_launch_s launcher;
49 } u;
50 };
51
52 /*
53 * Obtain a blank set of capabilities
54 */
cap_init(void)55 cap_t cap_init(void)
56 {
57 struct _cap_alloc_s *raw_data;
58 cap_t result;
59
60 raw_data = calloc(1, sizeof(struct _cap_alloc_s));
61 if (raw_data == NULL) {
62 _cap_debug("out of memory");
63 errno = ENOMEM;
64 return NULL;
65 }
66 raw_data->magic = CAP_T_MAGIC;
67 raw_data->size = sizeof(struct _cap_alloc_s);
68
69 result = &raw_data->u.set;
70 result->head.version = _LIBCAP_CAPABILITY_VERSION;
71 capget(&result->head, NULL); /* load the kernel-capability version */
72
73 switch (result->head.version) {
74 #ifdef _LINUX_CAPABILITY_VERSION_1
75 case _LINUX_CAPABILITY_VERSION_1:
76 break;
77 #endif
78 #ifdef _LINUX_CAPABILITY_VERSION_2
79 case _LINUX_CAPABILITY_VERSION_2:
80 break;
81 #endif
82 #ifdef _LINUX_CAPABILITY_VERSION_3
83 case _LINUX_CAPABILITY_VERSION_3:
84 break;
85 #endif
86 default: /* No idea what to do */
87 cap_free(result);
88 result = NULL;
89 break;
90 }
91
92 return result;
93 }
94
95 /*
96 * This is an internal library function to duplicate a string and
97 * tag the result as something cap_free can handle.
98 */
_libcap_strdup(const char * old)99 __attribute__((visibility ("hidden"))) char *_libcap_strdup(const char *old)
100 {
101 struct _cap_alloc_s *header;
102 char *raw_data;
103 size_t len;
104
105 if (old == NULL) {
106 errno = EINVAL;
107 return NULL;
108 }
109
110 len = strlen(old);
111 if ((len & 0x3fffffff) != len) {
112 _cap_debug("len is too long for libcap to manage");
113 errno = EINVAL;
114 return NULL;
115 }
116 len += 1 + 2*sizeof(__u32);
117 if (len < sizeof(struct _cap_alloc_s)) {
118 len = sizeof(struct _cap_alloc_s);
119 }
120
121 raw_data = calloc(1, len);
122 if (raw_data == NULL) {
123 errno = ENOMEM;
124 return NULL;
125 }
126 header = (void *) raw_data;
127 header->magic = CAP_S_MAGIC;
128 header->size = (__u32) len;
129
130 raw_data += 2*sizeof(__u32);
131 strcpy(raw_data, old);
132 return raw_data;
133 }
134
135 /*
136 * This function duplicates an internal capability set with
137 * calloc()'d memory. It is the responsibility of the user to call
138 * cap_free() to liberate it.
139 */
cap_dup(cap_t cap_d)140 cap_t cap_dup(cap_t cap_d)
141 {
142 cap_t result;
143
144 if (!good_cap_t(cap_d)) {
145 _cap_debug("bad argument");
146 errno = EINVAL;
147 return NULL;
148 }
149
150 result = cap_init();
151 if (result == NULL) {
152 _cap_debug("out of memory");
153 return NULL;
154 }
155
156 _cap_mu_lock(&cap_d->mutex);
157 memcpy(result, cap_d, sizeof(*cap_d));
158 _cap_mu_unlock(&cap_d->mutex);
159 _cap_mu_unlock(&result->mutex);
160
161 return result;
162 }
163
cap_iab_init(void)164 cap_iab_t cap_iab_init(void)
165 {
166 struct _cap_alloc_s *base = calloc(1, sizeof(struct _cap_alloc_s));
167 if (base == NULL) {
168 _cap_debug("out of memory");
169 return NULL;
170 }
171 base->magic = CAP_IAB_MAGIC;
172 base->size = sizeof(struct _cap_alloc_s);
173 return &base->u.iab;
174 }
175
176 /*
177 * This function duplicates an internal iab tuple with calloc()'d
178 * memory. It is the responsibility of the user to call cap_free() to
179 * liberate it.
180 */
cap_iab_dup(cap_iab_t iab)181 cap_iab_t cap_iab_dup(cap_iab_t iab)
182 {
183 cap_iab_t result;
184
185 if (!good_cap_iab_t(iab)) {
186 _cap_debug("bad argument");
187 errno = EINVAL;
188 return NULL;
189 }
190
191 result = cap_iab_init();
192 if (result == NULL) {
193 _cap_debug("out of memory");
194 return NULL;
195 }
196
197 _cap_mu_lock(&iab->mutex);
198 memcpy(result, iab, sizeof(*iab));
199 _cap_mu_unlock(&iab->mutex);
200 _cap_mu_unlock(&result->mutex);
201
202 return result;
203 }
204
205 /*
206 * cap_new_launcher allocates some memory for a launcher and
207 * initializes it. To actually launch a program with this launcher,
208 * use cap_launch(). By default, the launcher is a no-op from a
209 * security perspective and will act just as fork()/execve()
210 * would. Use cap_launcher_setuid() etc to override this.
211 */
cap_new_launcher(const char * arg0,const char * const * argv,const char * const * envp)212 cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv,
213 const char * const *envp)
214 {
215 struct _cap_alloc_s *data = calloc(1, sizeof(struct _cap_alloc_s));
216 if (data == NULL) {
217 _cap_debug("out of memory");
218 return NULL;
219 }
220 data->magic = CAP_LAUNCH_MAGIC;
221 data->size = sizeof(struct _cap_alloc_s);
222
223 struct cap_launch_s *attr = &data->u.launcher;
224 attr->arg0 = arg0;
225 attr->argv = argv;
226 attr->envp = envp;
227 return attr;
228 }
229
230 /*
231 * cap_func_launcher allocates some memory for a launcher and
232 * initializes it. The purpose of this launcher, unlike one created
233 * with cap_new_launcher(), is to execute some function code from a
234 * forked copy of the program. The forked process will exit when the
235 * callback function, func, returns.
236 */
cap_func_launcher(int (callback_fn)(void * detail))237 cap_launch_t cap_func_launcher(int (callback_fn)(void *detail))
238 {
239 struct _cap_alloc_s *data = calloc(1, sizeof(struct _cap_alloc_s));
240 if (data == NULL) {
241 _cap_debug("out of memory");
242 return NULL;
243 }
244 data->magic = CAP_LAUNCH_MAGIC;
245 data->size = sizeof(struct _cap_alloc_s);
246
247 struct cap_launch_s *attr = &data->u.launcher;
248 attr->custom_setup_fn = callback_fn;
249 return attr;
250 }
251
252 /*
253 * Scrub and then liberate the recognized allocated object.
254 */
cap_free(void * data_p)255 int cap_free(void *data_p)
256 {
257 if (!data_p) {
258 return 0;
259 }
260
261 /* confirm alignment */
262 if ((sizeof(uintptr_t)-1) & (uintptr_t) data_p) {
263 _cap_debug("whatever we're cap_free()ing it isn't aligned right: %p",
264 data_p);
265 errno = EINVAL;
266 return -1;
267 }
268
269 void *base = (void *) (-2 + (__u32 *) data_p);
270 struct _cap_alloc_s *data = base;
271 switch (data->magic) {
272 case CAP_T_MAGIC:
273 _cap_mu_lock(&data->u.set.mutex);
274 break;
275 case CAP_S_MAGIC:
276 case CAP_IAB_MAGIC:
277 break;
278 case CAP_LAUNCH_MAGIC:
279 if (data->u.launcher.iab != NULL) {
280 _cap_mu_unlock(&data->u.launcher.iab->mutex);
281 if (cap_free(data->u.launcher.iab) != 0) {
282 return -1;
283 }
284 }
285 data->u.launcher.iab = NULL;
286 if (cap_free(data->u.launcher.chroot) != 0) {
287 return -1;
288 }
289 data->u.launcher.chroot = NULL;
290 break;
291 default:
292 _cap_debug("don't recognize what we're supposed to liberate");
293 errno = EINVAL;
294 return -1;
295 }
296
297 /*
298 * operate here with respect to base, to avoid tangling with the
299 * automated buffer overflow detection.
300 */
301 memset(base, 0, data->size);
302 free(base);
303 data_p = NULL;
304 data = NULL;
305 base = NULL;
306 return 0;
307 }
308