• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1997-8,2019 Andrew G Morgan <morgan@kernel.org>
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  * This gets set via the pre-main() executed constructor function below it.
12  */
13 static cap_value_t _cap_max_bits;
14 
_initialize_libcap(void)15 __attribute__((constructor (300))) static void _initialize_libcap(void) {
16     if (_cap_max_bits) {
17 	return;
18     }
19     cap_set_syscall(NULL, NULL);
20     _binary_search(_cap_max_bits, cap_get_bound, 0, __CAP_MAXBITS, __CAP_BITS);
21 }
22 
cap_max_bits(void)23 cap_value_t cap_max_bits(void) {
24     return _cap_max_bits;
25 }
26 
27 /*
28  * Obtain a blank set of capabilities
29  */
30 
cap_init(void)31 cap_t cap_init(void)
32 {
33     __u32 *raw_data;
34     cap_t result;
35 
36     raw_data = calloc(1, sizeof(__u32) + sizeof(*result));
37     if (raw_data == NULL) {
38 	_cap_debug("out of memory");
39 	errno = ENOMEM;
40 	return NULL;
41     }
42 
43     *raw_data = CAP_T_MAGIC;
44     result = (cap_t) (raw_data + 1);
45 
46     result->head.version = _LIBCAP_CAPABILITY_VERSION;
47     capget(&result->head, NULL);      /* load the kernel-capability version */
48 
49     switch (result->head.version) {
50 #ifdef _LINUX_CAPABILITY_VERSION_1
51     case _LINUX_CAPABILITY_VERSION_1:
52 	break;
53 #endif
54 #ifdef _LINUX_CAPABILITY_VERSION_2
55     case _LINUX_CAPABILITY_VERSION_2:
56 	break;
57 #endif
58 #ifdef _LINUX_CAPABILITY_VERSION_3
59     case _LINUX_CAPABILITY_VERSION_3:
60 	break;
61 #endif
62     default:                          /* No idea what to do */
63 	cap_free(result);
64 	result = NULL;
65 	break;
66     }
67 
68     return result;
69 }
70 
71 /*
72  * This is an internal library function to duplicate a string and
73  * tag the result as something cap_free can handle.
74  */
75 
_libcap_strdup(const char * old)76 char *_libcap_strdup(const char *old)
77 {
78     __u32 *raw_data;
79 
80     if (old == NULL) {
81 	errno = EINVAL;
82 	return NULL;
83     }
84 
85     raw_data = malloc( sizeof(__u32) + strlen(old) + 1 );
86     if (raw_data == NULL) {
87 	errno = ENOMEM;
88 	return NULL;
89     }
90 
91     *(raw_data++) = CAP_S_MAGIC;
92     strcpy((char *) raw_data, old);
93 
94     return ((char *) raw_data);
95 }
96 
97 /*
98  * This function duplicates an internal capability set with
99  * malloc()'d memory. It is the responsibility of the user to call
100  * cap_free() to liberate it.
101  */
102 
cap_dup(cap_t cap_d)103 cap_t cap_dup(cap_t cap_d)
104 {
105     cap_t result;
106 
107     if (!good_cap_t(cap_d)) {
108 	_cap_debug("bad argument");
109 	errno = EINVAL;
110 	return NULL;
111     }
112 
113     result = cap_init();
114     if (result == NULL) {
115 	_cap_debug("out of memory");
116 	return NULL;
117     }
118 
119     memcpy(result, cap_d, sizeof(*cap_d));
120 
121     return result;
122 }
123 
cap_iab_init(void)124 cap_iab_t cap_iab_init(void) {
125     __u32 *base = calloc(1, sizeof(__u32) + sizeof(struct cap_iab_s));
126     *(base++) = CAP_IAB_MAGIC;
127     return (cap_iab_t) base;
128 }
129 
130 /*
131  * cap_new_launcher allocates some memory for a launcher and
132  * initializes it.  To actually launch a program with this launcher,
133  * use cap_launch(). By default, the launcher is a no-op from a
134  * security perspective and will act just as fork()/execve()
135  * would. Use cap_launcher_setuid() etc to override this.
136  */
cap_new_launcher(const char * arg0,const char * const * argv,const char * const * envp)137 cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv,
138 			      const char * const *envp)
139 {
140     __u32 *data = calloc(1, sizeof(__u32) + sizeof(struct cap_launch_s));
141     *(data++) = CAP_LAUNCH_MAGIC;
142     struct cap_launch_s *attr = (struct cap_launch_s *) data;
143     attr->arg0 = arg0;
144     attr->argv = argv;
145     attr->envp = envp;
146     return attr;
147 }
148 
149 /*
150  * cap_func_launcher allocates some memory for a launcher and
151  * initializes it. The purpose of this launcher, unlike one created
152  * with cap_new_launcher(), is to execute some function code from a
153  * forked copy of the program. The forked process will exit when the
154  * callback function, func, returns.
155  */
cap_func_launcher(int (callback_fn)(void * detail))156 cap_launch_t cap_func_launcher(int (callback_fn)(void *detail))
157 {
158     __u32 *data = calloc(1, sizeof(__u32) + sizeof(struct cap_launch_s));
159     *(data++) = CAP_LAUNCH_MAGIC;
160     struct cap_launch_s *attr = (struct cap_launch_s *) data;
161     attr->custom_setup_fn = callback_fn;
162     return attr;
163 }
164 
165 /*
166  * Scrub and then liberate an internal capability set.
167  */
168 
cap_free(void * data_p)169 int cap_free(void *data_p)
170 {
171     if (!data_p)
172 	return 0;
173 
174     if (good_cap_t(data_p)) {
175 	data_p = -1 + (__u32 *) data_p;
176 	memset(data_p, 0, sizeof(__u32) + sizeof(struct _cap_struct));
177 	free(data_p);
178 	data_p = NULL;
179 	return 0;
180     }
181 
182     if (good_cap_string(data_p)) {
183 	size_t length = strlen(data_p) + sizeof(__u32);
184      	data_p = -1 + (__u32 *) data_p;
185      	memset(data_p, 0, length);
186      	free(data_p);
187      	data_p = NULL;
188      	return 0;
189     }
190 
191     if (good_cap_iab_t(data_p)) {
192 	size_t length = sizeof(struct cap_iab_s) + sizeof(__u32);
193 	data_p = -1 + (__u32 *) data_p;
194 	memset(data_p, 0, length);
195 	free(data_p);
196 	data_p = NULL;
197 	return 0;
198     }
199 
200     if (good_cap_launch_t(data_p)) {
201 	cap_launch_t launcher = data_p;
202 	if (launcher->iab) {
203 	    cap_free(launcher->iab);
204 	}
205 	if (launcher->chroot) {
206 	    cap_free(launcher->chroot);
207 	}
208 	size_t length = sizeof(struct cap_iab_s) + sizeof(__u32);
209 	data_p = -1 + (__u32 *) data_p;
210 	memset(data_p, 0, length);
211 	free(data_p);
212 	data_p = NULL;
213 	return 0;
214     }
215 
216     _cap_debug("don't recognize what we're supposed to liberate");
217     errno = EINVAL;
218     return -1;
219 }
220