aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2015-12-02 08:44:40 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-12-06 21:34:16 -0500
commit5d92b75c753ae27578ee764df3be650c67fa5877 (patch)
tree360e7bbd6446de9e9b59ab33515274cb5561ec4b
parent786534b92f3ce68f4afc8a761c80b76887797b0a (diff)
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>
-rw-r--r--fs/xfs/xfs_acl.c23
-rw-r--r--fs/xfs/xfs_acl.h4
-rw-r--r--fs/xfs/xfs_xattr.c137
3 files changed, 59 insertions, 105 deletions
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 6bb470fbb8e8..2d5df1f23bbc 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -252,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode)
252 return error; 252 return error;
253} 253}
254 254
255static int
256xfs_acl_exists(struct inode *inode, unsigned char *name)
257{
258 int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
259
260 return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
261 ATTR_ROOT|ATTR_KERNOVAL) == 0);
262}
263
264int
265posix_acl_access_exists(struct inode *inode)
266{
267 return xfs_acl_exists(inode, SGI_ACL_FILE);
268}
269
270int
271posix_acl_default_exists(struct inode *inode)
272{
273 if (!S_ISDIR(inode->i_mode))
274 return 0;
275 return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
276}
277
278int 255int
279xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 256xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
280{ 257{
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 52f8255d6bdf..286fa89217f5 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -24,16 +24,12 @@ struct posix_acl;
24#ifdef CONFIG_XFS_POSIX_ACL 24#ifdef CONFIG_XFS_POSIX_ACL
25extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); 25extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
26extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); 26extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
27extern int posix_acl_access_exists(struct inode *inode);
28extern int posix_acl_default_exists(struct inode *inode);
29#else 27#else
30static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) 28static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
31{ 29{
32 return NULL; 30 return NULL;
33} 31}
34# define xfs_set_acl NULL 32# define xfs_set_acl NULL
35# define posix_acl_access_exists(inode) 0
36# define posix_acl_default_exists(inode) 0
37#endif /* CONFIG_XFS_POSIX_ACL */ 33#endif /* CONFIG_XFS_POSIX_ACL */
38 34
39extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags); 35extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 36a43851aac0..110f1d7d86b0 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -129,47 +129,19 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
129 NULL 129 NULL
130}; 130};
131 131
132static unsigned int xfs_xattr_prefix_len(int flags)
133{
134 if (flags & XFS_ATTR_SECURE)
135 return sizeof("security");
136 else if (flags & XFS_ATTR_ROOT)
137 return sizeof("trusted");
138 else
139 return sizeof("user");
140}
141
142static const char *xfs_xattr_prefix(int flags)
143{
144 if (flags & XFS_ATTR_SECURE)
145 return xfs_xattr_security_handler.prefix;
146 else if (flags & XFS_ATTR_ROOT)
147 return xfs_xattr_trusted_handler.prefix;
148 else
149 return xfs_xattr_user_handler.prefix;
150}
151
152static int 132static int
153xfs_xattr_put_listent( 133__xfs_xattr_put_listent(
154 struct xfs_attr_list_context *context, 134 struct xfs_attr_list_context *context,
155 int flags, 135 char *prefix,
156 unsigned char *name, 136 int prefix_len,
157 int namelen, 137 unsigned char *name,
158 int valuelen, 138 int namelen)
159 unsigned char *value)
160{ 139{
161 unsigned int prefix_len = xfs_xattr_prefix_len(flags);
162 char *offset; 140 char *offset;
163 int arraytop; 141 int arraytop;
164 142
165 ASSERT(context->count >= 0); 143 if (!context->alist)
166 144 goto compute_size;
167 /*
168 * Only show root namespace entries if we are actually allowed to
169 * see them.
170 */
171 if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
172 return 0;
173 145
174 arraytop = context->count + prefix_len + namelen + 1; 146 arraytop = context->count + prefix_len + namelen + 1;
175 if (arraytop > context->firstu) { 147 if (arraytop > context->firstu) {
@@ -177,17 +149,19 @@ xfs_xattr_put_listent(
177 return 1; 149 return 1;
178 } 150 }
179 offset = (char *)context->alist + context->count; 151 offset = (char *)context->alist + context->count;
180 strncpy(offset, xfs_xattr_prefix(flags), prefix_len); 152 strncpy(offset, prefix, prefix_len);
181 offset += prefix_len; 153 offset += prefix_len;
182 strncpy(offset, (char *)name, namelen); /* real name */ 154 strncpy(offset, (char *)name, namelen); /* real name */
183 offset += namelen; 155 offset += namelen;
184 *offset = '\0'; 156 *offset = '\0';
157
158compute_size:
185 context->count += prefix_len + namelen + 1; 159 context->count += prefix_len + namelen + 1;
186 return 0; 160 return 0;
187} 161}
188 162
189static int 163static int
190xfs_xattr_put_listent_sizes( 164xfs_xattr_put_listent(
191 struct xfs_attr_list_context *context, 165 struct xfs_attr_list_context *context,
192 int flags, 166 int flags,
193 unsigned char *name, 167 unsigned char *name,
@@ -195,24 +169,55 @@ xfs_xattr_put_listent_sizes(
195 int valuelen, 169 int valuelen,
196 unsigned char *value) 170 unsigned char *value)
197{ 171{
198 context->count += xfs_xattr_prefix_len(flags) + namelen + 1; 172 char *prefix;
199 return 0; 173 int prefix_len;
200}
201 174
202static int 175 ASSERT(context->count >= 0);
203list_one_attr(const char *name, const size_t len, void *data,
204 size_t size, ssize_t *result)
205{
206 char *p = data + *result;
207 176
208 *result += len; 177 if (flags & XFS_ATTR_ROOT) {
209 if (!size) 178#ifdef CONFIG_XFS_POSIX_ACL
210 return 0; 179 if (namelen == SGI_ACL_FILE_SIZE &&
211 if (*result > size) 180 strncmp(name, SGI_ACL_FILE,
212 return -ERANGE; 181 SGI_ACL_FILE_SIZE) == 0) {
182 int ret = __xfs_xattr_put_listent(
183 context, XATTR_SYSTEM_PREFIX,
184 XATTR_SYSTEM_PREFIX_LEN,
185 XATTR_POSIX_ACL_ACCESS,
186 strlen(XATTR_POSIX_ACL_ACCESS));
187 if (ret)
188 return ret;
189 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
190 strncmp(name, SGI_ACL_DEFAULT,
191 SGI_ACL_DEFAULT_SIZE) == 0) {
192 int ret = __xfs_xattr_put_listent(
193 context, XATTR_SYSTEM_PREFIX,
194 XATTR_SYSTEM_PREFIX_LEN,
195 XATTR_POSIX_ACL_DEFAULT,
196 strlen(XATTR_POSIX_ACL_DEFAULT));
197 if (ret)
198 return ret;
199 }
200#endif
213 201
214 strcpy(p, name); 202 /*
215 return 0; 203 * Only show root namespace entries if we are actually allowed to
204 * see them.
205 */
206 if (!capable(CAP_SYS_ADMIN))
207 return 0;
208
209 prefix = XATTR_TRUSTED_PREFIX;
210 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
211 } else if (flags & XFS_ATTR_SECURE) {
212 prefix = XATTR_SECURITY_PREFIX;
213 prefix_len = XATTR_SECURITY_PREFIX_LEN;
214 } else {
215 prefix = XATTR_USER_PREFIX;
216 prefix_len = XATTR_USER_PREFIX_LEN;
217 }
218
219 return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
220 namelen);
216} 221}
217 222
218ssize_t 223ssize_t
@@ -221,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
221 struct xfs_attr_list_context context; 226 struct xfs_attr_list_context context;
222 struct attrlist_cursor_kern cursor = { 0 }; 227 struct attrlist_cursor_kern cursor = { 0 };
223 struct inode *inode = d_inode(dentry); 228 struct inode *inode = d_inode(dentry);
224 int error;
225 229
226 /* 230 /*
227 * First read the regular on-disk attributes. 231 * First read the regular on-disk attributes.
@@ -230,37 +234,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
230 context.dp = XFS_I(inode); 234 context.dp = XFS_I(inode);
231 context.cursor = &cursor; 235 context.cursor = &cursor;
232 context.resynch = 1; 236 context.resynch = 1;
233 context.alist = data; 237 context.alist = size ? data : NULL;
234 context.bufsize = size; 238 context.bufsize = size;
235 context.firstu = context.bufsize; 239 context.firstu = context.bufsize;
236 240 context.put_listent = xfs_xattr_put_listent;
237 if (size)
238 context.put_listent = xfs_xattr_put_listent;
239 else
240 context.put_listent = xfs_xattr_put_listent_sizes;
241 241
242 xfs_attr_list_int(&context); 242 xfs_attr_list_int(&context);
243 if (context.count < 0) 243 if (context.count < 0)
244 return -ERANGE; 244 return -ERANGE;
245 245
246 /*
247 * Then add the two synthetic ACL attributes.
248 */
249 if (posix_acl_access_exists(inode)) {
250 error = list_one_attr(XATTR_NAME_POSIX_ACL_ACCESS,
251 strlen(XATTR_NAME_POSIX_ACL_ACCESS) + 1,
252 data, size, &context.count);
253 if (error)
254 return error;
255 }
256
257 if (posix_acl_default_exists(inode)) {
258 error = list_one_attr(XATTR_NAME_POSIX_ACL_DEFAULT,
259 strlen(XATTR_NAME_POSIX_ACL_DEFAULT) + 1,
260 data, size, &context.count);
261 if (error)
262 return error;
263 }
264
265 return context.count; 246 return context.count;
266} 247}