.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | File: fs/xattr.c |
---|
3 | 4 | |
---|
.. | .. |
---|
130 | 131 | return -EPERM; |
---|
131 | 132 | } |
---|
132 | 133 | |
---|
133 | | - return inode_permission2(ERR_PTR(-EOPNOTSUPP), inode, mask); |
---|
| 134 | + return inode_permission(inode, mask); |
---|
134 | 135 | } |
---|
| 136 | + |
---|
| 137 | +/* |
---|
| 138 | + * Look for any handler that deals with the specified namespace. |
---|
| 139 | + */ |
---|
| 140 | +int |
---|
| 141 | +xattr_supported_namespace(struct inode *inode, const char *prefix) |
---|
| 142 | +{ |
---|
| 143 | + const struct xattr_handler **handlers = inode->i_sb->s_xattr; |
---|
| 144 | + const struct xattr_handler *handler; |
---|
| 145 | + size_t preflen; |
---|
| 146 | + |
---|
| 147 | + if (!(inode->i_opflags & IOP_XATTR)) { |
---|
| 148 | + if (unlikely(is_bad_inode(inode))) |
---|
| 149 | + return -EIO; |
---|
| 150 | + return -EOPNOTSUPP; |
---|
| 151 | + } |
---|
| 152 | + |
---|
| 153 | + preflen = strlen(prefix); |
---|
| 154 | + |
---|
| 155 | + for_each_xattr_handler(handlers, handler) { |
---|
| 156 | + if (!strncmp(xattr_prefix(handler), prefix, preflen)) |
---|
| 157 | + return 0; |
---|
| 158 | + } |
---|
| 159 | + |
---|
| 160 | + return -EOPNOTSUPP; |
---|
| 161 | +} |
---|
| 162 | +EXPORT_SYMBOL(xattr_supported_namespace); |
---|
135 | 163 | |
---|
136 | 164 | int |
---|
137 | 165 | __vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, |
---|
.. | .. |
---|
204 | 232 | } |
---|
205 | 233 | |
---|
206 | 234 | /** |
---|
207 | | - * __vfs_setxattr_locked: set an extended attribute while holding the inode |
---|
| 235 | + * __vfs_setxattr_locked - set an extended attribute while holding the inode |
---|
208 | 236 | * lock |
---|
209 | 237 | * |
---|
210 | | - * @dentry - object to perform setxattr on |
---|
211 | | - * @name - xattr name to set |
---|
212 | | - * @value - value to set @name to |
---|
213 | | - * @size - size of @value |
---|
214 | | - * @flags - flags to pass into filesystem operations |
---|
215 | | - * @delegated_inode - on return, will contain an inode pointer that |
---|
| 238 | + * @dentry: object to perform setxattr on |
---|
| 239 | + * @name: xattr name to set |
---|
| 240 | + * @value: value to set @name to |
---|
| 241 | + * @size: size of @value |
---|
| 242 | + * @flags: flags to pass into filesystem operations |
---|
| 243 | + * @delegated_inode: on return, will contain an inode pointer that |
---|
216 | 244 | * a delegation was broken on, NULL if none. |
---|
217 | 245 | */ |
---|
218 | 246 | int |
---|
.. | .. |
---|
263 | 291 | } |
---|
264 | 292 | return error; |
---|
265 | 293 | } |
---|
266 | | -EXPORT_SYMBOL_GPL(vfs_setxattr); |
---|
| 294 | +EXPORT_SYMBOL_NS_GPL(vfs_setxattr, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
267 | 295 | |
---|
268 | 296 | static ssize_t |
---|
269 | 297 | xattr_getsecurity(struct inode *inode, const char *name, void *value, |
---|
.. | .. |
---|
317 | 345 | return PTR_ERR(handler); |
---|
318 | 346 | if (!handler->get) |
---|
319 | 347 | return -EOPNOTSUPP; |
---|
320 | | - error = handler->get(handler, dentry, inode, name, NULL, 0); |
---|
| 348 | + error = handler->get(handler, dentry, inode, name, NULL, 0, 0); |
---|
321 | 349 | if (error < 0) |
---|
322 | 350 | return error; |
---|
323 | 351 | |
---|
.. | .. |
---|
328 | 356 | memset(value, 0, error + 1); |
---|
329 | 357 | } |
---|
330 | 358 | |
---|
331 | | - error = handler->get(handler, dentry, inode, name, value, error); |
---|
| 359 | + error = handler->get(handler, dentry, inode, name, value, error, 0); |
---|
332 | 360 | *xattr_value = value; |
---|
333 | 361 | return error; |
---|
334 | 362 | } |
---|
335 | 363 | |
---|
336 | 364 | ssize_t |
---|
337 | 365 | __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, |
---|
338 | | - void *value, size_t size) |
---|
| 366 | + void *value, size_t size, int flags) |
---|
339 | 367 | { |
---|
340 | 368 | const struct xattr_handler *handler; |
---|
341 | | - |
---|
342 | | - handler = xattr_resolve_name(inode, &name); |
---|
343 | | - if (IS_ERR(handler)) |
---|
344 | | - return PTR_ERR(handler); |
---|
345 | | - if (unlikely(handler->__get)) |
---|
346 | | - return handler->__get(handler, dentry, inode, name, value, |
---|
347 | | - size); |
---|
348 | | - if (!handler->get) |
---|
349 | | - return -EOPNOTSUPP; |
---|
350 | | - return handler->get(handler, dentry, inode, name, value, size); |
---|
351 | | -} |
---|
352 | | -EXPORT_SYMBOL(__vfs_getxattr); |
---|
353 | | - |
---|
354 | | -ssize_t |
---|
355 | | -vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) |
---|
356 | | -{ |
---|
357 | | - struct inode *inode = dentry->d_inode; |
---|
358 | 369 | int error; |
---|
359 | | - const struct xattr_handler *handler; |
---|
360 | 370 | |
---|
| 371 | + if (flags & XATTR_NOSECURITY) |
---|
| 372 | + goto nolsm; |
---|
361 | 373 | error = xattr_permission(inode, name, MAY_READ); |
---|
362 | 374 | if (error) |
---|
363 | 375 | return error; |
---|
.. | .. |
---|
384 | 396 | return PTR_ERR(handler); |
---|
385 | 397 | if (!handler->get) |
---|
386 | 398 | return -EOPNOTSUPP; |
---|
387 | | - return handler->get(handler, dentry, inode, name, value, size); |
---|
| 399 | + return handler->get(handler, dentry, inode, name, value, size, flags); |
---|
388 | 400 | } |
---|
389 | | -EXPORT_SYMBOL_GPL(vfs_getxattr); |
---|
| 401 | +EXPORT_SYMBOL(__vfs_getxattr); |
---|
| 402 | + |
---|
| 403 | +ssize_t |
---|
| 404 | +vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) |
---|
| 405 | +{ |
---|
| 406 | + return __vfs_getxattr(dentry, dentry->d_inode, name, value, size, 0); |
---|
| 407 | +} |
---|
| 408 | +EXPORT_SYMBOL_NS_GPL(vfs_getxattr, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
390 | 409 | |
---|
391 | 410 | ssize_t |
---|
392 | 411 | vfs_listxattr(struct dentry *dentry, char *list, size_t size) |
---|
.. | .. |
---|
406 | 425 | } |
---|
407 | 426 | return error; |
---|
408 | 427 | } |
---|
409 | | -EXPORT_SYMBOL_GPL(vfs_listxattr); |
---|
| 428 | +EXPORT_SYMBOL_NS_GPL(vfs_listxattr, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
410 | 429 | |
---|
411 | 430 | int |
---|
412 | 431 | __vfs_removexattr(struct dentry *dentry, const char *name) |
---|
.. | .. |
---|
424 | 443 | EXPORT_SYMBOL(__vfs_removexattr); |
---|
425 | 444 | |
---|
426 | 445 | /** |
---|
427 | | - * __vfs_removexattr_locked: set an extended attribute while holding the inode |
---|
| 446 | + * __vfs_removexattr_locked - set an extended attribute while holding the inode |
---|
428 | 447 | * lock |
---|
429 | 448 | * |
---|
430 | | - * @dentry - object to perform setxattr on |
---|
431 | | - * @name - name of xattr to remove |
---|
432 | | - * @delegated_inode - on return, will contain an inode pointer that |
---|
| 449 | + * @dentry: object to perform setxattr on |
---|
| 450 | + * @name: name of xattr to remove |
---|
| 451 | + * @delegated_inode: on return, will contain an inode pointer that |
---|
433 | 452 | * a delegation was broken on, NULL if none. |
---|
434 | 453 | */ |
---|
435 | 454 | int |
---|
.. | .. |
---|
895 | 914 | if (len < sizeof(*new_xattr)) |
---|
896 | 915 | return NULL; |
---|
897 | 916 | |
---|
898 | | - new_xattr = kmalloc(len, GFP_KERNEL); |
---|
| 917 | + new_xattr = kvmalloc(len, GFP_KERNEL); |
---|
899 | 918 | if (!new_xattr) |
---|
900 | 919 | return NULL; |
---|
901 | 920 | |
---|
.. | .. |
---|
938 | 957 | * @value: value of the xattr. If %NULL, will remove the attribute. |
---|
939 | 958 | * @size: size of the new xattr |
---|
940 | 959 | * @flags: %XATTR_{CREATE|REPLACE} |
---|
| 960 | + * @removed_size: returns size of the removed xattr, -1 if none removed |
---|
941 | 961 | * |
---|
942 | 962 | * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails |
---|
943 | 963 | * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist; |
---|
.. | .. |
---|
946 | 966 | * Returns 0 on success, -errno on failure. |
---|
947 | 967 | */ |
---|
948 | 968 | int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, |
---|
949 | | - const void *value, size_t size, int flags) |
---|
| 969 | + const void *value, size_t size, int flags, |
---|
| 970 | + ssize_t *removed_size) |
---|
950 | 971 | { |
---|
951 | 972 | struct simple_xattr *xattr; |
---|
952 | 973 | struct simple_xattr *new_xattr = NULL; |
---|
953 | 974 | int err = 0; |
---|
| 975 | + |
---|
| 976 | + if (removed_size) |
---|
| 977 | + *removed_size = -1; |
---|
954 | 978 | |
---|
955 | 979 | /* value == NULL means remove */ |
---|
956 | 980 | if (value) { |
---|
.. | .. |
---|
960 | 984 | |
---|
961 | 985 | new_xattr->name = kstrdup(name, GFP_KERNEL); |
---|
962 | 986 | if (!new_xattr->name) { |
---|
963 | | - kfree(new_xattr); |
---|
| 987 | + kvfree(new_xattr); |
---|
964 | 988 | return -ENOMEM; |
---|
965 | 989 | } |
---|
966 | 990 | } |
---|
.. | .. |
---|
973 | 997 | err = -EEXIST; |
---|
974 | 998 | } else if (new_xattr) { |
---|
975 | 999 | list_replace(&xattr->list, &new_xattr->list); |
---|
| 1000 | + if (removed_size) |
---|
| 1001 | + *removed_size = xattr->size; |
---|
976 | 1002 | } else { |
---|
977 | 1003 | list_del(&xattr->list); |
---|
| 1004 | + if (removed_size) |
---|
| 1005 | + *removed_size = xattr->size; |
---|
978 | 1006 | } |
---|
979 | 1007 | goto out; |
---|
980 | 1008 | } |
---|
.. | .. |
---|
990 | 1018 | spin_unlock(&xattrs->lock); |
---|
991 | 1019 | if (xattr) { |
---|
992 | 1020 | kfree(xattr->name); |
---|
993 | | - kfree(xattr); |
---|
| 1021 | + kvfree(xattr); |
---|
994 | 1022 | } |
---|
995 | 1023 | return err; |
---|
996 | 1024 | |
---|
.. | .. |
---|
1021 | 1049 | ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, |
---|
1022 | 1050 | char *buffer, size_t size) |
---|
1023 | 1051 | { |
---|
1024 | | - bool trusted = capable(CAP_SYS_ADMIN); |
---|
| 1052 | + bool trusted = ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); |
---|
1025 | 1053 | struct simple_xattr *xattr; |
---|
1026 | 1054 | ssize_t remaining_size = size; |
---|
1027 | 1055 | int err = 0; |
---|