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 31static 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 89static 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 177cap_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 207cap_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 238int 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 270int 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 299cap_t cap_get_fd(int fildes) 300{ 301 errno = EINVAL; 302 return NULL; 303} 304 305cap_t cap_get_file(const char *filename) 306{ 307 errno = EINVAL; 308 return NULL; 309} 310 311int cap_set_fd(int fildes, cap_t cap_d) 312{ 313 errno = EINVAL; 314 return -1; 315} 316 317int 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