1 /* 2 * Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan (at) 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 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 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 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 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 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 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 308 cap_t cap_get_fd(int fildes) 309 { 310 errno = EINVAL; 311 return NULL; 312 } 313 314 cap_t cap_get_file(const char *filename) 315 { 316 errno = EINVAL; 317 return NULL; 318 } 319 320 int cap_set_fd(int fildes, cap_t cap_d) 321 { 322 errno = EINVAL; 323 return -1; 324 } 325 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