diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2015-12-02 08:44:40 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-06 21:34:16 -0500 |
commit | 5d92b75c753ae27578ee764df3be650c67fa5877 (patch) | |
tree | 360e7bbd6446de9e9b59ab33515274cb5561ec4b /fs/xfs/xfs_xattr.c | |
parent | 786534b92f3ce68f4afc8a761c80b76887797b0a (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>
Diffstat (limited to 'fs/xfs/xfs_xattr.c')
-rw-r--r-- | fs/xfs/xfs_xattr.c | 137 |
1 files changed, 59 insertions, 78 deletions
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 | ||
132 | static 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 | |||
142 | static 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 | |||
152 | static int | 132 | static int |
153 | xfs_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 | |||
158 | compute_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 | ||
189 | static int | 163 | static int |
190 | xfs_xattr_put_listent_sizes( | 164 | xfs_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 | ||
202 | static int | 175 | ASSERT(context->count >= 0); |
203 | list_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 | ||
218 | ssize_t | 223 | ssize_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 | } |