xref: /openbmc/linux/fs/xfs/xfs_xattr.c (revision 8e774e02)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Copyright (C) 2008 Christoph Hellwig.
4   * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
5   */
6  
7  #include "xfs.h"
8  #include "xfs_shared.h"
9  #include "xfs_format.h"
10  #include "xfs_log_format.h"
11  #include "xfs_da_format.h"
12  #include "xfs_inode.h"
13  #include "xfs_attr.h"
14  
15  #include <linux/posix_acl_xattr.h>
16  #include <linux/xattr.h>
17  
18  
19  static int
20  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
21  		struct inode *inode, const char *name, void *value, size_t size)
22  {
23  	int xflags = handler->flags;
24  	struct xfs_inode *ip = XFS_I(inode);
25  	int error, asize = size;
26  
27  	/* Convert Linux syscall to XFS internal ATTR flags */
28  	if (!size) {
29  		xflags |= ATTR_KERNOVAL;
30  		value = NULL;
31  	}
32  
33  	error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
34  	if (error)
35  		return error;
36  	return asize;
37  }
38  
39  void
40  xfs_forget_acl(
41  	struct inode		*inode,
42  	const char		*name,
43  	int			xflags)
44  {
45  	/*
46  	 * Invalidate any cached ACLs if the user has bypassed the ACL
47  	 * interface. We don't validate the content whatsoever so it is caller
48  	 * responsibility to provide data in valid format and ensure i_mode is
49  	 * consistent.
50  	 */
51  	if (xflags & ATTR_ROOT) {
52  #ifdef CONFIG_XFS_POSIX_ACL
53  		if (!strcmp(name, SGI_ACL_FILE))
54  			forget_cached_acl(inode, ACL_TYPE_ACCESS);
55  		else if (!strcmp(name, SGI_ACL_DEFAULT))
56  			forget_cached_acl(inode, ACL_TYPE_DEFAULT);
57  #endif
58  	}
59  }
60  
61  static int
62  xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
63  		struct inode *inode, const char *name, const void *value,
64  		size_t size, int flags)
65  {
66  	int			xflags = handler->flags;
67  	struct xfs_inode	*ip = XFS_I(inode);
68  	int			error;
69  
70  	/* Convert Linux syscall to XFS internal ATTR flags */
71  	if (flags & XATTR_CREATE)
72  		xflags |= ATTR_CREATE;
73  	if (flags & XATTR_REPLACE)
74  		xflags |= ATTR_REPLACE;
75  
76  	if (!value)
77  		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
78  	error = xfs_attr_set(ip, (unsigned char *)name,
79  				(void *)value, size, xflags);
80  	if (!error)
81  		xfs_forget_acl(inode, name, xflags);
82  
83  	return error;
84  }
85  
86  static const struct xattr_handler xfs_xattr_user_handler = {
87  	.prefix	= XATTR_USER_PREFIX,
88  	.flags	= 0, /* no flags implies user namespace */
89  	.get	= xfs_xattr_get,
90  	.set	= xfs_xattr_set,
91  };
92  
93  static const struct xattr_handler xfs_xattr_trusted_handler = {
94  	.prefix	= XATTR_TRUSTED_PREFIX,
95  	.flags	= ATTR_ROOT,
96  	.get	= xfs_xattr_get,
97  	.set	= xfs_xattr_set,
98  };
99  
100  static const struct xattr_handler xfs_xattr_security_handler = {
101  	.prefix	= XATTR_SECURITY_PREFIX,
102  	.flags	= ATTR_SECURE,
103  	.get	= xfs_xattr_get,
104  	.set	= xfs_xattr_set,
105  };
106  
107  const struct xattr_handler *xfs_xattr_handlers[] = {
108  	&xfs_xattr_user_handler,
109  	&xfs_xattr_trusted_handler,
110  	&xfs_xattr_security_handler,
111  #ifdef CONFIG_XFS_POSIX_ACL
112  	&posix_acl_access_xattr_handler,
113  	&posix_acl_default_xattr_handler,
114  #endif
115  	NULL
116  };
117  
118  static void
119  __xfs_xattr_put_listent(
120  	struct xfs_attr_list_context *context,
121  	char *prefix,
122  	int prefix_len,
123  	unsigned char *name,
124  	int namelen)
125  {
126  	char *offset;
127  	int arraytop;
128  
129  	if (context->count < 0 || context->seen_enough)
130  		return;
131  
132  	if (!context->alist)
133  		goto compute_size;
134  
135  	arraytop = context->count + prefix_len + namelen + 1;
136  	if (arraytop > context->firstu) {
137  		context->count = -1;	/* insufficient space */
138  		context->seen_enough = 1;
139  		return;
140  	}
141  	offset = (char *)context->alist + context->count;
142  	strncpy(offset, prefix, prefix_len);
143  	offset += prefix_len;
144  	strncpy(offset, (char *)name, namelen);			/* real name */
145  	offset += namelen;
146  	*offset = '\0';
147  
148  compute_size:
149  	context->count += prefix_len + namelen + 1;
150  	return;
151  }
152  
153  static void
154  xfs_xattr_put_listent(
155  	struct xfs_attr_list_context *context,
156  	int		flags,
157  	unsigned char	*name,
158  	int		namelen,
159  	int		valuelen)
160  {
161  	char *prefix;
162  	int prefix_len;
163  
164  	ASSERT(context->count >= 0);
165  
166  	if (flags & XFS_ATTR_ROOT) {
167  #ifdef CONFIG_XFS_POSIX_ACL
168  		if (namelen == SGI_ACL_FILE_SIZE &&
169  		    strncmp(name, SGI_ACL_FILE,
170  			    SGI_ACL_FILE_SIZE) == 0) {
171  			__xfs_xattr_put_listent(
172  					context, XATTR_SYSTEM_PREFIX,
173  					XATTR_SYSTEM_PREFIX_LEN,
174  					XATTR_POSIX_ACL_ACCESS,
175  					strlen(XATTR_POSIX_ACL_ACCESS));
176  		} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
177  			 strncmp(name, SGI_ACL_DEFAULT,
178  				 SGI_ACL_DEFAULT_SIZE) == 0) {
179  			__xfs_xattr_put_listent(
180  					context, XATTR_SYSTEM_PREFIX,
181  					XATTR_SYSTEM_PREFIX_LEN,
182  					XATTR_POSIX_ACL_DEFAULT,
183  					strlen(XATTR_POSIX_ACL_DEFAULT));
184  		}
185  #endif
186  
187  		/*
188  		 * Only show root namespace entries if we are actually allowed to
189  		 * see them.
190  		 */
191  		if (!capable(CAP_SYS_ADMIN))
192  			return;
193  
194  		prefix = XATTR_TRUSTED_PREFIX;
195  		prefix_len = XATTR_TRUSTED_PREFIX_LEN;
196  	} else if (flags & XFS_ATTR_SECURE) {
197  		prefix = XATTR_SECURITY_PREFIX;
198  		prefix_len = XATTR_SECURITY_PREFIX_LEN;
199  	} else {
200  		prefix = XATTR_USER_PREFIX;
201  		prefix_len = XATTR_USER_PREFIX_LEN;
202  	}
203  
204  	__xfs_xattr_put_listent(context, prefix, prefix_len, name,
205  				namelen);
206  	return;
207  }
208  
209  ssize_t
210  xfs_vn_listxattr(
211  	struct dentry	*dentry,
212  	char		*data,
213  	size_t		size)
214  {
215  	struct xfs_attr_list_context context;
216  	struct attrlist_cursor_kern cursor = { 0 };
217  	struct inode	*inode = d_inode(dentry);
218  	int		error;
219  
220  	/*
221  	 * First read the regular on-disk attributes.
222  	 */
223  	memset(&context, 0, sizeof(context));
224  	context.dp = XFS_I(inode);
225  	context.cursor = &cursor;
226  	context.resynch = 1;
227  	context.alist = size ? data : NULL;
228  	context.bufsize = size;
229  	context.firstu = context.bufsize;
230  	context.put_listent = xfs_xattr_put_listent;
231  
232  	error = xfs_attr_list_int(&context);
233  	if (error)
234  		return error;
235  	if (context.count < 0)
236  		return -ERANGE;
237  
238  	return context.count;
239  }
240