X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzpl_xattr.c;h=d79d35bce75b85ca76adcc5f931ad3d284de9d8f;hb=refs%2Fheads%2Frertzinger%2Ffeature-zpool-get--p;hp=9117b7bc14ccde96ed36ba84f9da2456c46dec90;hpb=82a37189aac955c81a59a5ecc3400475adb56355;p=zfs.git diff --git a/module/zfs/zpl_xattr.c b/module/zfs/zpl_xattr.c index 9117b7b..d79d35b 100644 --- a/module/zfs/zpl_xattr.c +++ b/module/zfs/zpl_xattr.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -91,11 +92,8 @@ typedef struct xattr_filldir { } xattr_filldir_t; static int -zpl_xattr_filldir(void *arg, const char *name, int name_len, - loff_t offset, uint64_t objnum, unsigned int d_type) +zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len) { - xattr_filldir_t *xf = arg; - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR)) return (0); @@ -118,12 +116,46 @@ zpl_xattr_filldir(void *arg, const char *name, int name_len, return (0); } +/* + * Read as many directory entry names as will fit in to the provided buffer, + * or when no buffer is provided calculate the required buffer size. + */ +int +zpl_xattr_readdir(struct inode *dxip, xattr_filldir_t *xf) +{ + zap_cursor_t zc; + zap_attribute_t zap; + int error; + + zap_cursor_init(&zc, ITOZSB(dxip)->z_os, ITOZ(dxip)->z_id); + + while ((error = -zap_cursor_retrieve(&zc, &zap)) == 0) { + + if (zap.za_integer_length != 8 || zap.za_num_integers != 1) { + error = -ENXIO; + break; + } + + error = zpl_xattr_filldir(xf, zap.za_name, strlen(zap.za_name)); + if (error) + break; + + zap_cursor_advance(&zc); + } + + zap_cursor_fini(&zc); + + if (error == -ENOENT) + error = 0; + + return (error); +} + static ssize_t zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr) { struct inode *ip = xf->inode; struct inode *dxip = NULL; - loff_t pos = 3; /* skip '.', '..', and '.zfs' entries. */ int error; /* Lookup the xattr directory */ @@ -135,8 +167,7 @@ zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr) return (error); } - /* Fill provided buffer via zpl_zattr_filldir helper */ - error = -zfs_readdir(dxip, (void *)xf, zpl_xattr_filldir, &pos, cr); + error = zpl_xattr_readdir(dxip, xf); iput(dxip); return (error); @@ -162,8 +193,8 @@ zpl_xattr_list_sa(xattr_filldir_t *xf) while ((nvp = nvlist_next_nvpair(zp->z_xattr_cached, nvp)) != NULL) { ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY); - error = zpl_xattr_filldir((void *)xf, nvpair_name(nvp), - strlen(nvpair_name(nvp)), 0, 0, 0); + error = zpl_xattr_filldir(xf, nvpair_name(nvp), + strlen(nvpair_name(nvp))); if (error) return (error); } @@ -225,6 +256,11 @@ zpl_xattr_get_dir(struct inode *ip, const char *name, void *value, goto out; } + if (size < i_size_read(xip)) { + error = -ERANGE; + goto out; + } + error = zpl_read_common(xip, value, size, 0, UIO_SYSSPACE, 0, cr); out: if (xip) @@ -263,9 +299,12 @@ zpl_xattr_get_sa(struct inode *ip, const char *name, void *value, size_t size) if (!size) return (nv_size); - memcpy(value, nv_value, MIN(size, nv_size)); + if (size < nv_size) + return (-ERANGE); - return (MIN(size, nv_size)); + memcpy(value, nv_value, nv_size); + + return (nv_size); } static int @@ -280,7 +319,7 @@ __zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size, if (zsb->z_use_sa && zp->z_is_sa) { error = zpl_xattr_get_sa(ip, name, value, size); - if (error >= 0) + if (error != -ENOENT) goto out; } @@ -399,6 +438,10 @@ zpl_xattr_set_sa(struct inode *ip, const char *name, const void *value, if (error == -ENOENT) error = zpl_xattr_set_dir(ip, name, NULL, 0, flags, cr); } else { + /* Do not allow SA xattrs in symlinks (issue #1648) */ + if (S_ISLNK(ip->i_mode)) + return (-EMLINK); + /* Limited to 32k to keep nvpair memory allocations small */ if (size > DXATTR_MAX_ENTRY_SIZE) return (-EFBIG); @@ -606,31 +649,59 @@ __zpl_xattr_security_set(struct inode *ip, const char *name, } ZPL_XATTR_SET_WRAPPER(zpl_xattr_security_set); +#ifdef HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY +static int +__zpl_xattr_security_init(struct inode *ip, const struct xattr *xattrs, + void *fs_info) +{ + const struct xattr *xattr; + int error = 0; + + for (xattr = xattrs; xattr->name != NULL; xattr++) { + error = __zpl_xattr_security_set(ip, + xattr->name, xattr->value, xattr->value_len, 0); + + if (error < 0) + break; + } + + return (error); +} + int zpl_xattr_security_init(struct inode *ip, struct inode *dip, const struct qstr *qstr) { - int error; - size_t len; - void *value; - char *name; + return security_inode_init_security(ip, dip, qstr, + &__zpl_xattr_security_init, NULL); +} - error = zpl_security_inode_init_security(ip, dip, qstr, - &name, &value, &len); - if (error) { - if (error == -EOPNOTSUPP) - return 0; +#else +int +zpl_xattr_security_init(struct inode *ip, struct inode *dip, + const struct qstr *qstr) +{ + int error; + size_t len; + void *value; + char *name; - return (error); - } + error = zpl_security_inode_init_security(ip, dip, qstr, + &name, &value, &len); + if (error) { + if (error == -EOPNOTSUPP) + return 0; + return (error); + } error = __zpl_xattr_security_set(ip, name, value, len, 0); - kfree(name); - kfree(value); + kfree(name); + kfree(value); - return (error); + return (error); } +#endif /* HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY */ xattr_handler_t zpl_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, @@ -644,6 +715,7 @@ xattr_handler_t *zpl_xattr_handlers[] = { &zpl_xattr_user_handler, #ifdef HAVE_POSIX_ACLS &zpl_xattr_acl_access_handler, - &zpl_xattr_acl_default_handler, + &zpl_xattr_acl_default_handler, #endif /* HAVE_POSIX_ACLS */ + NULL };