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