xref: /aosp_15_r20/external/libcap/libcap/cap_alloc.c (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
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