xref: /openbmc/linux/fs/xfs/xfs_xattr.c (revision 0f3dcf3b)
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_trans_resv.h"
13 #include "xfs_mount.h"
14 #include "xfs_inode.h"
15 #include "xfs_attr.h"
16 #include "xfs_acl.h"
17 #include "xfs_da_btree.h"
18 
19 #include <linux/posix_acl_xattr.h>
20 
21 
22 static int
23 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
24 		struct inode *inode, const char *name, void *value, size_t size)
25 {
26 	struct xfs_da_args	args = {
27 		.dp		= XFS_I(inode),
28 		.attr_filter	= handler->flags,
29 		.name		= name,
30 		.namelen	= strlen(name),
31 		.value		= value,
32 		.valuelen	= size,
33 	};
34 	int			error;
35 
36 	error = xfs_attr_get(&args);
37 	if (error)
38 		return error;
39 	return args.valuelen;
40 }
41 
42 static int
43 xfs_xattr_set(const struct xattr_handler *handler,
44 	      struct user_namespace *mnt_userns, struct dentry *unused,
45 	      struct inode *inode, const char *name, const void *value,
46 	      size_t size, int flags)
47 {
48 	struct xfs_da_args	args = {
49 		.dp		= XFS_I(inode),
50 		.attr_filter	= handler->flags,
51 		.attr_flags	= flags,
52 		.name		= name,
53 		.namelen	= strlen(name),
54 		.value		= (void *)value,
55 		.valuelen	= size,
56 	};
57 	int			error;
58 
59 	error = xfs_attr_set(&args);
60 	if (!error && (handler->flags & XFS_ATTR_ROOT))
61 		xfs_forget_acl(inode, name);
62 	return error;
63 }
64 
65 static const struct xattr_handler xfs_xattr_user_handler = {
66 	.prefix	= XATTR_USER_PREFIX,
67 	.flags	= 0, /* no flags implies user namespace */
68 	.get	= xfs_xattr_get,
69 	.set	= xfs_xattr_set,
70 };
71 
72 static const struct xattr_handler xfs_xattr_trusted_handler = {
73 	.prefix	= XATTR_TRUSTED_PREFIX,
74 	.flags	= XFS_ATTR_ROOT,
75 	.get	= xfs_xattr_get,
76 	.set	= xfs_xattr_set,
77 };
78 
79 static const struct xattr_handler xfs_xattr_security_handler = {
80 	.prefix	= XATTR_SECURITY_PREFIX,
81 	.flags	= XFS_ATTR_SECURE,
82 	.get	= xfs_xattr_get,
83 	.set	= xfs_xattr_set,
84 };
85 
86 const struct xattr_handler *xfs_xattr_handlers[] = {
87 	&xfs_xattr_user_handler,
88 	&xfs_xattr_trusted_handler,
89 	&xfs_xattr_security_handler,
90 #ifdef CONFIG_XFS_POSIX_ACL
91 	&posix_acl_access_xattr_handler,
92 	&posix_acl_default_xattr_handler,
93 #endif
94 	NULL
95 };
96 
97 static void
98 __xfs_xattr_put_listent(
99 	struct xfs_attr_list_context *context,
100 	char *prefix,
101 	int prefix_len,
102 	unsigned char *name,
103 	int namelen)
104 {
105 	char *offset;
106 	int arraytop;
107 
108 	if (context->count < 0 || context->seen_enough)
109 		return;
110 
111 	if (!context->buffer)
112 		goto compute_size;
113 
114 	arraytop = context->count + prefix_len + namelen + 1;
115 	if (arraytop > context->firstu) {
116 		context->count = -1;	/* insufficient space */
117 		context->seen_enough = 1;
118 		return;
119 	}
120 	offset = context->buffer + context->count;
121 	strncpy(offset, prefix, prefix_len);
122 	offset += prefix_len;
123 	strncpy(offset, (char *)name, namelen);			/* real name */
124 	offset += namelen;
125 	*offset = '\0';
126 
127 compute_size:
128 	context->count += prefix_len + namelen + 1;
129 	return;
130 }
131 
132 static void
133 xfs_xattr_put_listent(
134 	struct xfs_attr_list_context *context,
135 	int		flags,
136 	unsigned char	*name,
137 	int		namelen,
138 	int		valuelen)
139 {
140 	char *prefix;
141 	int prefix_len;
142 
143 	ASSERT(context->count >= 0);
144 
145 	if (flags & XFS_ATTR_ROOT) {
146 #ifdef CONFIG_XFS_POSIX_ACL
147 		if (namelen == SGI_ACL_FILE_SIZE &&
148 		    strncmp(name, SGI_ACL_FILE,
149 			    SGI_ACL_FILE_SIZE) == 0) {
150 			__xfs_xattr_put_listent(
151 					context, XATTR_SYSTEM_PREFIX,
152 					XATTR_SYSTEM_PREFIX_LEN,
153 					XATTR_POSIX_ACL_ACCESS,
154 					strlen(XATTR_POSIX_ACL_ACCESS));
155 		} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
156 			 strncmp(name, SGI_ACL_DEFAULT,
157 				 SGI_ACL_DEFAULT_SIZE) == 0) {
158 			__xfs_xattr_put_listent(
159 					context, XATTR_SYSTEM_PREFIX,
160 					XATTR_SYSTEM_PREFIX_LEN,
161 					XATTR_POSIX_ACL_DEFAULT,
162 					strlen(XATTR_POSIX_ACL_DEFAULT));
163 		}
164 #endif
165 
166 		/*
167 		 * Only show root namespace entries if we are actually allowed to
168 		 * see them.
169 		 */
170 		if (!capable(CAP_SYS_ADMIN))
171 			return;
172 
173 		prefix = XATTR_TRUSTED_PREFIX;
174 		prefix_len = XATTR_TRUSTED_PREFIX_LEN;
175 	} else if (flags & XFS_ATTR_SECURE) {
176 		prefix = XATTR_SECURITY_PREFIX;
177 		prefix_len = XATTR_SECURITY_PREFIX_LEN;
178 	} else {
179 		prefix = XATTR_USER_PREFIX;
180 		prefix_len = XATTR_USER_PREFIX_LEN;
181 	}
182 
183 	__xfs_xattr_put_listent(context, prefix, prefix_len, name,
184 				namelen);
185 	return;
186 }
187 
188 ssize_t
189 xfs_vn_listxattr(
190 	struct dentry	*dentry,
191 	char		*data,
192 	size_t		size)
193 {
194 	struct xfs_attr_list_context context;
195 	struct inode	*inode = d_inode(dentry);
196 	int		error;
197 
198 	/*
199 	 * First read the regular on-disk attributes.
200 	 */
201 	memset(&context, 0, sizeof(context));
202 	context.dp = XFS_I(inode);
203 	context.resynch = 1;
204 	context.buffer = size ? data : NULL;
205 	context.bufsize = size;
206 	context.firstu = context.bufsize;
207 	context.put_listent = xfs_xattr_put_listent;
208 
209 	error = xfs_attr_list(&context);
210 	if (error)
211 		return error;
212 	if (context.count < 0)
213 		return -ERANGE;
214 
215 	return context.count;
216 }
217