Home | History | Annotate | Download | only in libcap
      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