mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	xfs: Change how listxattr generates synthetic attributes
Instead of adding the synthesized POSIX ACL attribute names after listing all non-synthesized attributes, generate them immediately when listing the non-synthesized attributes. In addition, merge xfs_xattr_put_listent and xfs_xattr_put_listent_sizes to ensure that the list size is computed correctly; the split version was overestimating the list size for non-root users. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Cc: Dave Chinner <david@fromorbit.com> Cc: xfs@oss.sgi.com Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									786534b92f
								
							
						
					
					
						commit
						5d92b75c75
					
				
					 3 changed files with 72 additions and 118 deletions
				
			
		|  | @ -252,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode) | |||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| xfs_acl_exists(struct inode *inode, unsigned char *name) | ||||
| { | ||||
| 	int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb)); | ||||
| 
 | ||||
| 	return (xfs_attr_get(XFS_I(inode), name, NULL, &len, | ||||
| 			    ATTR_ROOT|ATTR_KERNOVAL) == 0); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| posix_acl_access_exists(struct inode *inode) | ||||
| { | ||||
| 	return xfs_acl_exists(inode, SGI_ACL_FILE); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| posix_acl_default_exists(struct inode *inode) | ||||
| { | ||||
| 	if (!S_ISDIR(inode->i_mode)) | ||||
| 		return 0; | ||||
| 	return xfs_acl_exists(inode, SGI_ACL_DEFAULT); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) | ||||
| { | ||||
|  |  | |||
|  | @ -24,16 +24,12 @@ struct posix_acl; | |||
| #ifdef CONFIG_XFS_POSIX_ACL | ||||
| extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); | ||||
| extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); | ||||
| extern int posix_acl_access_exists(struct inode *inode); | ||||
| extern int posix_acl_default_exists(struct inode *inode); | ||||
| #else | ||||
| static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| # define xfs_set_acl					NULL | ||||
| # define posix_acl_access_exists(inode)			0 | ||||
| # define posix_acl_default_exists(inode)		0 | ||||
| #endif /* CONFIG_XFS_POSIX_ACL */ | ||||
| 
 | ||||
| extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags); | ||||
|  |  | |||
|  | @ -129,24 +129,35 @@ const struct xattr_handler *xfs_xattr_handlers[] = { | |||
| 	NULL | ||||
| }; | ||||
| 
 | ||||
| static unsigned int xfs_xattr_prefix_len(int flags) | ||||
| static int | ||||
| __xfs_xattr_put_listent( | ||||
| 	struct xfs_attr_list_context *context, | ||||
| 	char *prefix, | ||||
| 	int prefix_len, | ||||
| 	unsigned char *name, | ||||
| 	int namelen) | ||||
| { | ||||
| 	if (flags & XFS_ATTR_SECURE) | ||||
| 		return sizeof("security"); | ||||
| 	else if (flags & XFS_ATTR_ROOT) | ||||
| 		return sizeof("trusted"); | ||||
| 	else | ||||
| 		return sizeof("user"); | ||||
| } | ||||
| 	char *offset; | ||||
| 	int arraytop; | ||||
| 
 | ||||
| static const char *xfs_xattr_prefix(int flags) | ||||
| { | ||||
| 	if (flags & XFS_ATTR_SECURE) | ||||
| 		return xfs_xattr_security_handler.prefix; | ||||
| 	else if (flags & XFS_ATTR_ROOT) | ||||
| 		return xfs_xattr_trusted_handler.prefix; | ||||
| 	else | ||||
| 		return xfs_xattr_user_handler.prefix; | ||||
| 	if (!context->alist) | ||||
| 		goto compute_size; | ||||
| 
 | ||||
| 	arraytop = context->count + prefix_len + namelen + 1; | ||||
| 	if (arraytop > context->firstu) { | ||||
| 		context->count = -1;	/* insufficient space */ | ||||
| 		return 1; | ||||
| 	} | ||||
| 	offset = (char *)context->alist + context->count; | ||||
| 	strncpy(offset, prefix, prefix_len); | ||||
| 	offset += prefix_len; | ||||
| 	strncpy(offset, (char *)name, namelen);			/* real name */ | ||||
| 	offset += namelen; | ||||
| 	*offset = '\0'; | ||||
| 
 | ||||
| compute_size: | ||||
| 	context->count += prefix_len + namelen + 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
|  | @ -158,61 +169,55 @@ xfs_xattr_put_listent( | |||
| 	int		valuelen, | ||||
| 	unsigned char	*value) | ||||
| { | ||||
| 	unsigned int prefix_len = xfs_xattr_prefix_len(flags); | ||||
| 	char *offset; | ||||
| 	int arraytop; | ||||
| 	char *prefix; | ||||
| 	int prefix_len; | ||||
| 
 | ||||
| 	ASSERT(context->count >= 0); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Only show root namespace entries if we are actually allowed to | ||||
| 	 * see them. | ||||
| 	 */ | ||||
| 	if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN)) | ||||
| 		return 0; | ||||
| 	if (flags & XFS_ATTR_ROOT) { | ||||
| #ifdef CONFIG_XFS_POSIX_ACL | ||||
| 		if (namelen == SGI_ACL_FILE_SIZE && | ||||
| 		    strncmp(name, SGI_ACL_FILE, | ||||
| 			    SGI_ACL_FILE_SIZE) == 0) { | ||||
| 			int ret = __xfs_xattr_put_listent( | ||||
| 					context, XATTR_SYSTEM_PREFIX, | ||||
| 					XATTR_SYSTEM_PREFIX_LEN, | ||||
| 					XATTR_POSIX_ACL_ACCESS, | ||||
| 					strlen(XATTR_POSIX_ACL_ACCESS)); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} else if (namelen == SGI_ACL_DEFAULT_SIZE && | ||||
| 			 strncmp(name, SGI_ACL_DEFAULT, | ||||
| 				 SGI_ACL_DEFAULT_SIZE) == 0) { | ||||
| 			int ret = __xfs_xattr_put_listent( | ||||
| 					context, XATTR_SYSTEM_PREFIX, | ||||
| 					XATTR_SYSTEM_PREFIX_LEN, | ||||
| 					XATTR_POSIX_ACL_DEFAULT, | ||||
| 					strlen(XATTR_POSIX_ACL_DEFAULT)); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 	arraytop = context->count + prefix_len + namelen + 1; | ||||
| 	if (arraytop > context->firstu) { | ||||
| 		context->count = -1;	/* insufficient space */ | ||||
| 		return 1; | ||||
| 		/*
 | ||||
| 		 * Only show root namespace entries if we are actually allowed to | ||||
| 		 * see them. | ||||
| 		 */ | ||||
| 		if (!capable(CAP_SYS_ADMIN)) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		prefix = XATTR_TRUSTED_PREFIX; | ||||
| 		prefix_len = XATTR_TRUSTED_PREFIX_LEN; | ||||
| 	} else if (flags & XFS_ATTR_SECURE) { | ||||
| 		prefix = XATTR_SECURITY_PREFIX; | ||||
| 		prefix_len = XATTR_SECURITY_PREFIX_LEN; | ||||
| 	} else { | ||||
| 		prefix = XATTR_USER_PREFIX; | ||||
| 		prefix_len = XATTR_USER_PREFIX_LEN; | ||||
| 	} | ||||
| 	offset = (char *)context->alist + context->count; | ||||
| 	strncpy(offset, xfs_xattr_prefix(flags), prefix_len); | ||||
| 	offset += prefix_len; | ||||
| 	strncpy(offset, (char *)name, namelen);			/* real name */ | ||||
| 	offset += namelen; | ||||
| 	*offset = '\0'; | ||||
| 	context->count += prefix_len + namelen + 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| xfs_xattr_put_listent_sizes( | ||||
| 	struct xfs_attr_list_context *context, | ||||
| 	int		flags, | ||||
| 	unsigned char	*name, | ||||
| 	int		namelen, | ||||
| 	int		valuelen, | ||||
| 	unsigned char	*value) | ||||
| { | ||||
| 	context->count += xfs_xattr_prefix_len(flags) + namelen + 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| list_one_attr(const char *name, const size_t len, void *data, | ||||
| 		size_t size, ssize_t *result) | ||||
| { | ||||
| 	char *p = data + *result; | ||||
| 
 | ||||
| 	*result += len; | ||||
| 	if (!size) | ||||
| 		return 0; | ||||
| 	if (*result > size) | ||||
| 		return -ERANGE; | ||||
| 
 | ||||
| 	strcpy(p, name); | ||||
| 	return 0; | ||||
| 	return __xfs_xattr_put_listent(context, prefix, prefix_len, name, | ||||
| 				       namelen); | ||||
| } | ||||
| 
 | ||||
| ssize_t | ||||
|  | @ -221,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) | |||
| 	struct xfs_attr_list_context context; | ||||
| 	struct attrlist_cursor_kern cursor = { 0 }; | ||||
| 	struct inode		*inode = d_inode(dentry); | ||||
| 	int			error; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * First read the regular on-disk attributes. | ||||
|  | @ -230,37 +234,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) | |||
| 	context.dp = XFS_I(inode); | ||||
| 	context.cursor = &cursor; | ||||
| 	context.resynch = 1; | ||||
| 	context.alist = data; | ||||
| 	context.alist = size ? data : NULL; | ||||
| 	context.bufsize = size; | ||||
| 	context.firstu = context.bufsize; | ||||
| 
 | ||||
| 	if (size) | ||||
| 		context.put_listent = xfs_xattr_put_listent; | ||||
| 	else | ||||
| 		context.put_listent = xfs_xattr_put_listent_sizes; | ||||
| 	context.put_listent = xfs_xattr_put_listent; | ||||
| 
 | ||||
| 	xfs_attr_list_int(&context); | ||||
| 	if (context.count < 0) | ||||
| 		return -ERANGE; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Then add the two synthetic ACL attributes. | ||||
| 	 */ | ||||
| 	if (posix_acl_access_exists(inode)) { | ||||
| 		error = list_one_attr(XATTR_NAME_POSIX_ACL_ACCESS, | ||||
| 				strlen(XATTR_NAME_POSIX_ACL_ACCESS) + 1, | ||||
| 				data, size, &context.count); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 	} | ||||
| 
 | ||||
| 	if (posix_acl_default_exists(inode)) { | ||||
| 		error = list_one_attr(XATTR_NAME_POSIX_ACL_DEFAULT, | ||||
| 				strlen(XATTR_NAME_POSIX_ACL_DEFAULT) + 1, | ||||
| 				data, size, &context.count); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 	} | ||||
| 
 | ||||
| 	return context.count; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Andreas Gruenbacher
						Andreas Gruenbacher