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