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