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