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 * Scrub and then liberate an internal capability set.
151 */
152
cap_free(void * data_p)153 int cap_free(void *data_p)
154 {
155 if (!data_p)
156 return 0;
157
158 if (good_cap_t(data_p)) {
159 data_p = -1 + (__u32 *) data_p;
160 memset(data_p, 0, sizeof(__u32) + sizeof(struct _cap_struct));
161 free(data_p);
162 data_p = NULL;
163 return 0;
164 }
165
166 if (good_cap_string(data_p)) {
167 size_t length = strlen(data_p) + sizeof(__u32);
168 data_p = -1 + (__u32 *) data_p;
169 memset(data_p, 0, length);
170 free(data_p);
171 data_p = NULL;
172 return 0;
173 }
174
175 if (good_cap_iab_t(data_p)) {
176 size_t length = sizeof(struct cap_iab_s) + sizeof(__u32);
177 data_p = -1 + (__u32 *) data_p;
178 memset(data_p, 0, length);
179 free(data_p);
180 data_p = NULL;
181 return 0;
182 }
183
184 if (good_cap_launch_t(data_p)) {
185 cap_launch_t launcher = data_p;
186 if (launcher->iab) {
187 cap_free(launcher->iab);
188 }
189 if (launcher->chroot) {
190 cap_free(launcher->chroot);
191 }
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 _cap_debug("don't recognize what we're supposed to liberate");
201 errno = EINVAL;
202 return -1;
203 }
204