1 /*
2 * Copyright (c) 1997,2007,2016 Andrew G Morgan <[email protected]>
3 *
4 * This file deals with getting/setting capabilities from/on files.
5 */
6
7 #ifndef _DEFAULT_SOURCE
8 #define _DEFAULT_SOURCE
9 #endif
10
11 #include <sys/types.h>
12 #include <byteswap.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
16 /*
17 * We hardcode the prototypes for the Linux system calls here since
18 * there are no libcap library APIs that expose the user to these
19 * details, and that way we don't need to force clients to link any
20 * other libraries to access them.
21 */
22 extern ssize_t getxattr(const char *, const char *, void *, size_t);
23 extern ssize_t fgetxattr(int, const char *, void *, size_t);
24 extern int setxattr(const char *, const char *, const void *, size_t, int);
25 extern int fsetxattr(int, const char *, const void *, size_t, int);
26 extern int removexattr(const char *, const char *);
27 extern int fremovexattr(int, const char *);
28
29 /*
30 * This public API was moved to include/uapi/linux/xattr.h . For just
31 * these definitions, it isn't really worth managing this in our build
32 * system with yet another copy of a header file. We just, provide
33 * fallback definitions here.
34 */
35 #ifndef XATTR_CAPS_SUFFIX
36 #define XATTR_CAPS_SUFFIX "capability"
37 #endif
38 #ifndef XATTR_SECURITY_PREFIX
39 #define XATTR_SECURITY_PREFIX "security."
40 #endif
41 #ifndef XATTR_NAME_CAPS
42 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
43 #endif
44
45 #include "libcap.h"
46
47 #ifdef VFS_CAP_U32
48
49 #if VFS_CAP_U32 != __CAP_BLKS
50 # error VFS representation of capabilities is not the same size as kernel
51 #endif
52
53 #if __BYTE_ORDER == __BIG_ENDIAN
54 #define FIXUP_32BITS(x) bswap_32(x)
55 #else
56 #define FIXUP_32BITS(x) (x)
57 #endif
58
_fcaps_load(struct vfs_ns_cap_data * rawvfscap,cap_t result,int bytes)59 static cap_t _fcaps_load(struct vfs_ns_cap_data *rawvfscap, cap_t result,
60 int bytes)
61 {
62 __u32 magic_etc;
63 unsigned tocopy, i;
64
65 magic_etc = FIXUP_32BITS(rawvfscap->magic_etc);
66 switch (magic_etc & VFS_CAP_REVISION_MASK) {
67 case VFS_CAP_REVISION_1:
68 tocopy = VFS_CAP_U32_1;
69 bytes -= XATTR_CAPS_SZ_1;
70 break;
71
72 case VFS_CAP_REVISION_2:
73 tocopy = VFS_CAP_U32_2;
74 bytes -= XATTR_CAPS_SZ_2;
75 break;
76
77 case VFS_CAP_REVISION_3:
78 tocopy = VFS_CAP_U32_3;
79 bytes -= XATTR_CAPS_SZ_3;
80 result->rootid = FIXUP_32BITS(rawvfscap->rootid);
81 break;
82
83 default:
84 cap_free(result);
85 result = NULL;
86 return result;
87 }
88
89 /*
90 * Verify that we loaded exactly the right number of bytes
91 */
92 if (bytes != 0) {
93 cap_free(result);
94 result = NULL;
95 return result;
96 }
97
98 for (i=0; i < tocopy; i++) {
99 result->u[i].flat[CAP_INHERITABLE]
100 = FIXUP_32BITS(rawvfscap->data[i].inheritable);
101 result->u[i].flat[CAP_PERMITTED]
102 = FIXUP_32BITS(rawvfscap->data[i].permitted);
103 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
104 result->u[i].flat[CAP_EFFECTIVE]
105 = result->u[i].flat[CAP_INHERITABLE]
106 | result->u[i].flat[CAP_PERMITTED];
107 }
108 }
109 while (i < __CAP_BLKS) {
110 result->u[i].flat[CAP_INHERITABLE]
111 = result->u[i].flat[CAP_PERMITTED]
112 = result->u[i].flat[CAP_EFFECTIVE] = 0;
113 i++;
114 }
115
116 return result;
117 }
118
_fcaps_save(struct vfs_ns_cap_data * rawvfscap,cap_t cap_d,int * bytes_p)119 static int _fcaps_save(struct vfs_ns_cap_data *rawvfscap, cap_t cap_d,
120 int *bytes_p)
121 {
122 __u32 eff_not_zero, magic;
123 unsigned tocopy, i;
124
125 if (!good_cap_t(cap_d)) {
126 errno = EINVAL;
127 return -1;
128 }
129 _cap_mu_lock(&cap_d->mutex);
130
131 switch (cap_d->head.version) {
132 case _LINUX_CAPABILITY_VERSION_1:
133 magic = VFS_CAP_REVISION_1;
134 tocopy = VFS_CAP_U32_1;
135 *bytes_p = XATTR_CAPS_SZ_1;
136 break;
137
138 case _LINUX_CAPABILITY_VERSION_2:
139 case _LINUX_CAPABILITY_VERSION_3:
140 magic = VFS_CAP_REVISION_2;
141 tocopy = VFS_CAP_U32_2;
142 *bytes_p = XATTR_CAPS_SZ_2;
143 break;
144
145 default:
146 errno = EINVAL;
147 _cap_mu_unlock_return(&cap_d->mutex, -1);
148 }
149
150 if (cap_d->rootid != 0) {
151 if (cap_d->head.version < _LINUX_CAPABILITY_VERSION_3) {
152 _cap_debug("namespaces with non-0 rootid unsupported by kernel");
153 errno = EINVAL;
154 _cap_mu_unlock_return(&cap_d->mutex, -1);
155 }
156 magic = VFS_CAP_REVISION_3;
157 tocopy = VFS_CAP_U32_3;
158 *bytes_p = XATTR_CAPS_SZ_3;
159 rawvfscap->rootid = FIXUP_32BITS(cap_d->rootid);
160 }
161
162 _cap_debug("setting named file capabilities");
163
164 for (eff_not_zero = 0, i = 0; i < tocopy; i++) {
165 eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE];
166 }
167 while (i < __CAP_BLKS) {
168 if ((cap_d->u[i].flat[CAP_EFFECTIVE]
169 || cap_d->u[i].flat[CAP_INHERITABLE]
170 || cap_d->u[i].flat[CAP_PERMITTED])) {
171 /*
172 * System does not support these capabilities
173 */
174 errno = EINVAL;
175 _cap_mu_unlock_return(&cap_d->mutex, -1);
176 }
177 i++;
178 }
179
180 for (i=0; i < tocopy; i++) {
181 rawvfscap->data[i].permitted
182 = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]);
183 rawvfscap->data[i].inheritable
184 = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]);
185
186 if (eff_not_zero
187 && ((~(cap_d->u[i].flat[CAP_EFFECTIVE]))
188 & (cap_d->u[i].flat[CAP_PERMITTED]
189 | cap_d->u[i].flat[CAP_INHERITABLE]))) {
190 errno = EINVAL;
191 _cap_mu_unlock_return(&cap_d->mutex, -1);
192 }
193 }
194
195 if (eff_not_zero == 0) {
196 rawvfscap->magic_etc = FIXUP_32BITS(magic);
197 } else {
198 rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE);
199 }
200
201 _cap_mu_unlock_return(&cap_d->mutex, 0); /* success */
202 }
203
204 /*
205 * Get the capabilities of an open file, as specified by its file
206 * descriptor.
207 */
208
cap_get_fd(int fildes)209 cap_t cap_get_fd(int fildes)
210 {
211 cap_t result;
212
213 /* allocate a new capability set */
214 result = cap_init();
215 if (result) {
216 struct vfs_ns_cap_data rawvfscap;
217 int sizeofcaps;
218
219 _cap_debug("getting fildes capabilities");
220
221 /* fill the capability sets via a system call */
222 sizeofcaps = fgetxattr(fildes, XATTR_NAME_CAPS,
223 &rawvfscap, sizeof(rawvfscap));
224 if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
225 cap_free(result);
226 result = NULL;
227 } else {
228 result = _fcaps_load(&rawvfscap, result, sizeofcaps);
229 }
230 }
231
232 return result;
233 }
234
235 /*
236 * Get the capabilities from a named file.
237 */
238
cap_get_file(const char * filename)239 cap_t cap_get_file(const char *filename)
240 {
241 cap_t result;
242
243 /* allocate a new capability set */
244 result = cap_init();
245 if (result) {
246 struct vfs_ns_cap_data rawvfscap;
247 int sizeofcaps;
248
249 _cap_debug("getting filename capabilities");
250
251 /* fill the capability sets via a system call */
252 sizeofcaps = getxattr(filename, XATTR_NAME_CAPS,
253 &rawvfscap, sizeof(rawvfscap));
254 if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
255 cap_free(result);
256 result = NULL;
257 } else {
258 result = _fcaps_load(&rawvfscap, result, sizeofcaps);
259 }
260 }
261
262 return result;
263 }
264
265 /*
266 * Get rootid as seen in the current user namespace for the file capability
267 * sets.
268 */
269
cap_get_nsowner(cap_t cap_d)270 uid_t cap_get_nsowner(cap_t cap_d)
271 {
272 uid_t nsowner;
273 if (!good_cap_t(cap_d)) {
274 errno = EINVAL;
275 return -1;
276 }
277 _cap_mu_lock(&cap_d->mutex);
278 nsowner = cap_d->rootid;
279 _cap_mu_unlock(&cap_d->mutex);
280 return nsowner;
281 }
282
283 /*
284 * Set the capabilities of an open file, as specified by its file
285 * descriptor.
286 */
287
cap_set_fd(int fildes,cap_t cap_d)288 int cap_set_fd(int fildes, cap_t cap_d)
289 {
290 struct vfs_ns_cap_data rawvfscap;
291 int sizeofcaps;
292 struct stat buf;
293
294 if (fstat(fildes, &buf) != 0) {
295 _cap_debug("unable to stat file descriptor %d", fildes);
296 return -1;
297 }
298 if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
299 _cap_debug("file descriptor %d for non-regular file", fildes);
300 errno = EINVAL;
301 return -1;
302 }
303
304 if (cap_d == NULL) {
305 _cap_debug("deleting fildes capabilities");
306 return fremovexattr(fildes, XATTR_NAME_CAPS);
307 } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
308 return -1;
309 }
310
311 _cap_debug("setting fildes capabilities");
312
313 return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
314 }
315
316 /*
317 * Set the capabilities of a named file.
318 */
319
cap_set_file(const char * filename,cap_t cap_d)320 int cap_set_file(const char *filename, cap_t cap_d)
321 {
322 struct vfs_ns_cap_data rawvfscap;
323 int sizeofcaps;
324 struct stat buf;
325
326 if (lstat(filename, &buf) != 0) {
327 _cap_debug("unable to stat file [%s]", filename);
328 return -1;
329 }
330 if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
331 _cap_debug("file [%s] is not a regular file", filename);
332 errno = EINVAL;
333 return -1;
334 }
335
336 if (cap_d == NULL) {
337 _cap_debug("removing filename capabilities");
338 return removexattr(filename, XATTR_NAME_CAPS);
339 } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
340 return -1;
341 }
342
343 _cap_debug("setting filename capabilities");
344 return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
345 }
346
347 /*
348 * Set nsowner for the file capability set.
349 */
cap_set_nsowner(cap_t cap_d,uid_t rootuid)350 int cap_set_nsowner(cap_t cap_d, uid_t rootuid)
351 {
352 if (!good_cap_t(cap_d)) {
353 errno = EINVAL;
354 return -1;
355 }
356 _cap_mu_lock(&cap_d->mutex);
357 cap_d->rootid = rootuid;
358 _cap_mu_unlock_return(&cap_d->mutex, 0);
359 }
360
361 #else /* ie. ndef VFS_CAP_U32 */
362
cap_get_fd(int fildes)363 cap_t cap_get_fd(int fildes)
364 {
365 errno = EINVAL;
366 return NULL;
367 }
368
cap_get_file(const char * filename)369 cap_t cap_get_file(const char *filename)
370 {
371 errno = EINVAL;
372 return NULL;
373 }
374
cap_get_nsowner(cap_t cap_d)375 uid_t cap_get_nsowner(cap_t cap_d)
376 {
377 errno = EINVAL;
378 return -1;
379 }
380
cap_set_fd(int fildes,cap_t cap_d)381 int cap_set_fd(int fildes, cap_t cap_d)
382 {
383 errno = EINVAL;
384 return -1;
385 }
386
cap_set_file(const char * filename,cap_t cap_d)387 int cap_set_file(const char *filename, cap_t cap_d)
388 {
389 errno = EINVAL;
390 return -1;
391 }
392
cap_set_nsowner(cap_t cap_d,uid_t rootuid)393 int cap_set_nsowner(cap_t cap_d, uid_t rootuid)
394 {
395 errno = EINVAL;
396 return -1;
397 }
398
399 #endif /* def VFS_CAP_U32 */
400