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