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