Index: sys/amd64/linux/linux_dummy.c =================================================================== --- sys/amd64/linux/linux_dummy.c +++ sys/amd64/linux/linux_dummy.c @@ -155,24 +155,3 @@ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); - -#define DUMMY_XATTR(s) \ -int \ -linux_ ## s ## xattr( \ - struct thread *td, struct linux_ ## s ## xattr_args *arg) \ -{ \ - \ - return (ENOATTR); \ -} -DUMMY_XATTR(set); -DUMMY_XATTR(lset); -DUMMY_XATTR(fset); -DUMMY_XATTR(get); -DUMMY_XATTR(lget); -DUMMY_XATTR(fget); -DUMMY_XATTR(list); -DUMMY_XATTR(llist); -DUMMY_XATTR(flist); -DUMMY_XATTR(remove); -DUMMY_XATTR(lremove); -DUMMY_XATTR(fremove); Index: sys/amd64/linux32/linux32_dummy.c =================================================================== --- sys/amd64/linux32/linux32_dummy.c +++ sys/amd64/linux32/linux32_dummy.c @@ -163,24 +163,3 @@ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); - -#define DUMMY_XATTR(s) \ -int \ -linux_ ## s ## xattr( \ - struct thread *td, struct linux_ ## s ## xattr_args *arg) \ -{ \ - \ - return (ENOATTR); \ -} -DUMMY_XATTR(set); -DUMMY_XATTR(lset); -DUMMY_XATTR(fset); -DUMMY_XATTR(get); -DUMMY_XATTR(lget); -DUMMY_XATTR(fget); -DUMMY_XATTR(list); -DUMMY_XATTR(llist); -DUMMY_XATTR(flist); -DUMMY_XATTR(remove); -DUMMY_XATTR(lremove); -DUMMY_XATTR(fremove); Index: sys/bsm/audit_kevents.h =================================================================== --- sys/bsm/audit_kevents.h +++ sys/bsm/audit_kevents.h @@ -770,8 +770,12 @@ #define AUE_INITGROUPS AUE_NULL #define AUE_IOPOLICYSYS AUE_NULL #define AUE_ISSETUGID AUE_NULL +#define AUE_LGETXATTR AUE_NULL #define AUE_LIOLISTIO AUE_NULL #define AUE_LISTXATTR AUE_NULL +#define AUE_LLISTXATTR AUE_NULL +#define AUE_LREMOVEXATTR AUE_NULL +#define AUE_LSETXATTR AUE_NULL #define AUE_LSTATV AUE_NULL #define AUE_LSTAT64 AUE_NULL #define AUE_LSTAT64_EXTENDED AUE_NULL Index: sys/compat/linux/linux_xattr.h =================================================================== --- /dev/null +++ sys/compat/linux/linux_xattr.h @@ -0,0 +1,40 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017 Fedor Uporov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define XATTR_NAME_MAX 255 /* Chars in an xattr name */ +#define XATTR_SIZE_MAX 65536 /* Size of an extended attribute value (64k). */ + +#define XATTR_NAMESPACE_SECURITY_STRING "security" +#define LINUX_BSD_USER_NAMESPACE EXTATTR_NAMESPACE_USER + +static const char linux_xattr_name_separator = '.'; + +#define XATTR_CREATE 0x1 /* Set value, fail if attr already exists. */ +#define XATTR_REPLACE 0x2 /* Set value, fail if attr does not exist. */ Index: sys/compat/linux/linux_xattr.c =================================================================== --- /dev/null +++ sys/compat/linux/linux_xattr.c @@ -0,0 +1,695 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017 Fedor Uporov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_compat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef COMPAT_LINUX32 +#include +#include +#else +#include +#include +#endif + +#include +#include + +static int +linux_xattr_namespace_from_linux(const char *linux_name, int *attrnamespace, + const char **bsd_name) +{ + int prefix_len; + + /* + * The only 'user.' linux namespace is supported for now. + */ + if (bcmp(linux_name, EXTATTR_NAMESPACE_USER_STRING, + strlen(EXTATTR_NAMESPACE_USER_STRING)) == 0 && + linux_name[strlen(EXTATTR_NAMESPACE_USER_STRING)] == + linux_xattr_name_separator) { + *attrnamespace = EXTATTR_NAMESPACE_USER; + prefix_len = strlen(EXTATTR_NAMESPACE_USER_STRING) + 1; + *bsd_name = &linux_name[prefix_len]; + return (0); + } + + return (EOPNOTSUPP); +} + +static int +linux_setxattr_common(struct vnode *vp, const char *attrname, + char *value, size_t size, int flags, struct thread *td) +{ + struct mount *mp; + struct uio auio; + struct iovec aiov; + const char *bsd_attrname; + struct vattr vattr; + int attrnamespace, error; + + /* + * Validate fs objects types according LTP requirements + * for 'user.' namespace xattrs. + */ + if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) + return (EPERM); + + /* Validate xattr value size. */ + if (size > XATTR_SIZE_MAX) + return (E2BIG); + + /* Validate create/replace flags. */ + if (flags && (flags != XATTR_CREATE && flags != XATTR_REPLACE)) + return (EINVAL); + + error = vn_start_write(vp, &mp, V_WAIT | PCATCH); + if (error) + return (error); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + + /* + * Check stat immutable/append flags. + */ + vattr.va_birthtime.tv_sec = -1; + vattr.va_birthtime.tv_nsec = 0; + vattr.va_fsid = VNOVAL; + vattr.va_rdev = NODEV; + error = VOP_GETATTR(vp, &vattr, NOCRED); + if (error) + goto done; + + if (vattr.va_flags & (IMMUTABLE | APPEND)) { + error = EPERM; + goto done; + } + + error = linux_xattr_namespace_from_linux(attrname, &attrnamespace, + &bsd_attrname); + if (error) + goto done; + + /* + * Check create/replace file flags. + */ + if (flags) { + error = VOP_GETEXTATTR(vp, attrnamespace, bsd_attrname, NULL, NULL, + td->td_ucred, td); + if (error && error != ENOATTR) + goto done; + else if (error == ENOATTR && (flags & XATTR_REPLACE)) + goto done; + else if (error == 0 && !(flags & XATTR_REPLACE)) { + error = EEXIST; + goto done; + } + } + + aiov.iov_base = value; + aiov.iov_len = size; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + if (size > IOSIZE_MAX) { + error = ERANGE; + goto done; + } + auio.uio_resid = size; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + + error = VOP_SETEXTATTR(vp, attrnamespace, bsd_attrname, &auio, + td->td_ucred, td); + +done: + VOP_UNLOCK(vp, 0); + vn_finished_write(mp); + return (error); +} + +int +linux_setxattr(struct thread *td, struct linux_setxattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error && error == ENAMETOOLONG) + return (ERANGE); + else if (error) + return (error); + + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, + args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_setxattr_common(nd.ni_vp, attrname, args->value, + args->size, args->flags, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_lsetxattr(struct thread *td, struct linux_lsetxattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error && error == ENAMETOOLONG) + return (ERANGE); + else if (error) + return (error); + + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, + args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_setxattr_common(nd.ni_vp, attrname, args->value, + args->size, args->flags, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_fsetxattr(struct thread *td, struct linux_fsetxattr_args *args) +{ + struct file *fp; + char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(args->fd); + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error && error == ENAMETOOLONG) + return (ERANGE); + else if (error) + return (error); + + AUDIT_ARG_TEXT(attrname); + + error = getvnode(td, args->fd, + cap_rights_init(&rights, CAP_EXTATTR_SET), &fp); + if (error) + return (error); + + error = linux_setxattr_common(fp->f_vnode, attrname, args->value, + args->size, args->flags, td); + + fdrop(fp, td); + return (error); +} + +static int +linux_getxattr_common(struct vnode *vp, const char *attrname, + char *value, size_t size, struct thread *td) +{ + struct uio auio; + struct iovec aiov; + const char *bsd_attrname; + size_t bsd_size = 0; + int attrnamespace, error; + + error = linux_xattr_namespace_from_linux(attrname, &attrnamespace, + &bsd_attrname); + if (error) + return (error); + + /* + * The only files and directories can have 'user.' xattrs. + */ + if (attrnamespace == EXTATTR_NAMESPACE_USER && + vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) + return (EPERM); + + vn_lock(vp, LK_SHARED | LK_RETRY); + + /* + * Request xattr value size and check that the input buffer size is + * not less then xattr value size. + */ + error = VOP_GETEXTATTR(vp, attrnamespace, bsd_attrname, NULL, &bsd_size, + td->td_ucred, td); + if (error) + goto done; + + if (size && bsd_size > size) { + error = ERANGE; + goto done; + } + else if(value == NULL) + goto done; + + aiov.iov_base = value; + aiov.iov_len = bsd_size; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + if (bsd_size > IOSIZE_MAX) { + error = ERANGE; + goto done; + } + auio.uio_resid = bsd_size; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + + error = VOP_GETEXTATTR(vp, attrnamespace, bsd_attrname, &auio, NULL, + td->td_ucred, td); + +done: + if (bsd_size) + td->td_retval[0] = bsd_size; + else + td->td_retval[0] = 0; + + VOP_UNLOCK(vp, 0); + return (error); +} + +int +linux_getxattr(struct thread *td, struct linux_getxattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_getxattr_common(nd.ni_vp, attrname, args->value, + args->size, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_lgetxattr(struct thread *td, struct linux_lgetxattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_getxattr_common(nd.ni_vp, attrname, args->value, + args->size, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_fgetxattr(struct thread *td, struct linux_fgetxattr_args *args) +{ + struct file *fp; + char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(args->fd); + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + error = getvnode(td, args->fd, + cap_rights_init(&rights, CAP_EXTATTR_GET), &fp); + if (error) + return (error); + + error = linux_getxattr_common(fp->f_vnode, attrname, args->value, + args->size, td); + + fdrop(fp, td); + return (error); +} + +/* + * This function is used to convert bsd attr names list to linux compatible. + * The conversion consist of the next steps: + * 1) Adding the terminating zero in the end of the string. + * 2) Removing byte with characters number. + * 3) Adding namespace prefix. + * + * name0name1 ... + * to + * user.name0\0user.name1\0 ... + * + * Also, this function could be used to retrieve the size + * of linux attr names buffer form bsd-compatible one. + * Let's pass the linux_buf == NULL in this case. + */ +static int +linux_xattrs_names_convert_to_linux(int attrnamespace, + const char *bsd_buf, size_t bsd_buf_size, + char *linux_buf, size_t* linux_buf_size) +{ + const char *attrnamespace_prefix, *bsd_p; + char *linux_p; + unsigned int size; + + bsd_p = bsd_buf; + linux_p = linux_buf; + size = 0; + + if (linux_buf_size == NULL) + return (EINVAL); + + *linux_buf_size = 0; + + if (attrnamespace == EXTATTR_NAMESPACE_USER) + attrnamespace_prefix = EXTATTR_NAMESPACE_USER_STRING; + else if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) + attrnamespace_prefix = EXTATTR_NAMESPACE_SYSTEM_STRING; + else + return (EINVAL); + + while (bsd_p < bsd_buf + bsd_buf_size) { + /* Add namespace prefix. */ + size = strlen(attrnamespace_prefix); + + /* Add separator. */ + size += sizeof(linux_xattr_name_separator); + + /* Fill the name. */ + size += *bsd_p; + + /* Add terminating zero. */ + size += 1; + + /* Fill name if linux_buf was passed. */ + if (linux_p != NULL) { + snprintf(linux_p, size, "%s%c%s", + attrnamespace_prefix, linux_xattr_name_separator, + bsd_p + 1); + linux_p[size] = '\0'; + linux_p += size; + } + + bsd_p += *bsd_p; + bsd_p += 1; + *linux_buf_size += size; + } + + return (0); +} + +static int +linux_listxattr_common(struct vnode *vp, char *buf, size_t size, struct thread *td) +{ + struct uio auio; + struct iovec aiov; + char *bsd_buf = NULL; + size_t bsd_size, linux_size; + int error; + + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + + /* + * Unfortunately we should do two listxattr() calls per one system call, + * because it is impossible to get linux compatible xattrs list size + * without bsd list reading. + */ + error = VOP_LISTEXTATTR(vp, LINUX_BSD_USER_NAMESPACE, NULL, &bsd_size, + td->td_ucred, td); + if (error) + goto done; + + bsd_buf = malloc(bsd_size, M_TEMP, M_WAITOK); + if (bsd_buf == NULL) { + error = ENOMEM; + goto done; + } + + aiov.iov_base = bsd_buf; + aiov.iov_len = bsd_size; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + if (bsd_size > IOSIZE_MAX) { + error = ERANGE; + goto done; + } + auio.uio_resid = bsd_size; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + + error = VOP_LISTEXTATTR(vp, LINUX_BSD_USER_NAMESPACE, &auio, NULL, + td->td_ucred, td); + if (error) + goto done; + + error = linux_xattrs_names_convert_to_linux(LINUX_BSD_USER_NAMESPACE, + bsd_buf, bsd_size, buf, &linux_size); + if (error) { + td->td_retval[0] = 0; + } else { + /* Check, that we have space in the input buffer. */ + if (size && size < linux_size) { + td->td_retval[0] = 0; + error = ERANGE; + } else + td->td_retval[0] = linux_size; + } + +done: + free(bsd_buf, M_TEMP); + VOP_UNLOCK(vp, 0); + return (error); +} + +int +linux_listxattr(struct thread *td, struct linux_listxattr_args *args) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_listxattr_common(nd.ni_vp, args->list, args->size, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_llistxattr(struct thread *td, struct linux_llistxattr_args *args) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, + td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_listxattr_common(nd.ni_vp, args->list, args->size, td); + + vrele(nd.ni_vp); + return (error); +} + +int +linux_flistxattr(struct thread *td, struct linux_flistxattr_args *args) +{ + struct file *fp; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(args->fd); + error = getvnode(td, args->fd, + cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp); + if (error) + return (error); + + error = linux_listxattr_common(fp->f_vnode, args->list, args->size, td); + + fdrop(fp, td); + return (error); +} + +int +linux_removexattr(struct thread *td, struct linux_removexattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + const char *bsd_attrname; + int attrnamespace, error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_xattr_namespace_from_linux(attrname, &attrnamespace, + &bsd_attrname); + if (error) + goto done; + + error = extattr_delete_vp(nd.ni_vp, attrnamespace, bsd_attrname, td); + +done: + vrele(nd.ni_vp); + return (error); +} + +int +linux_lremovexattr(struct thread *td, struct linux_lremovexattr_args *args) +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + const char *bsd_attrname; + int attrnamespace, error; + + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, args->path, td); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = linux_xattr_namespace_from_linux(attrname, &attrnamespace, + &bsd_attrname); + if (error) + goto done; + + error = extattr_delete_vp(nd.ni_vp, attrnamespace, bsd_attrname, td); + +done: + vrele(nd.ni_vp); + return (error); +} + +int +linux_fremovexattr(struct thread *td, struct linux_fremovexattr_args *args) +{ + struct file *fp; + char attrname[EXTATTR_MAXNAMELEN]; + cap_rights_t rights; + const char *bsd_attrname; + int attrnamespace, error; + + AUDIT_ARG_FD(args->fd); + error = copyinstr(args->name, attrname, EXTATTR_MAXNAMELEN, NULL); + if (error) + return (error); + AUDIT_ARG_TEXT(attrname); + + error = getvnode(td, args->fd, + cap_rights_init(&rights, CAP_EXTATTR_GET), &fp); + if (error) + return (error); + + error = linux_xattr_namespace_from_linux(attrname, &attrnamespace, + &bsd_attrname); + if (error) + goto done; + + error = extattr_delete_vp(fp->f_vnode, attrnamespace, bsd_attrname, td); + +done: + fdrop(fp, td); + return (error); +} Index: sys/conf/files.amd64 =================================================================== --- sys/conf/files.amd64 +++ sys/conf/files.amd64 @@ -632,6 +632,7 @@ compat/linux/linux_uid16.c optional compat_linux32 compat/linux/linux_util.c optional compat_linux32 compat/linux/linux_vdso.c optional compat_linux32 +compat/linux/linux_xattr.c optional compat_linux32 compat/linux/linux_common.c optional compat_linux32 compat/linux/linux_event.c optional compat_linux32 compat/linux/linux.c optional compat_linux32 Index: sys/conf/files.i386 =================================================================== --- sys/conf/files.i386 +++ sys/conf/files.i386 @@ -106,6 +106,7 @@ compat/linux/linux_uid16.c optional compat_linux compat/linux/linux_util.c optional compat_linux compat/linux/linux_vdso.c optional compat_linux +compat/linux/linux_xattr.c optional compat_linux compat/linux/linux.c optional compat_linux compat/ndis/kern_ndis.c optional ndisapi pci compat/ndis/kern_windrv.c optional ndisapi pci Index: sys/i386/linux/linux_dummy.c =================================================================== --- sys/i386/linux/linux_dummy.c +++ sys/i386/linux/linux_dummy.c @@ -159,24 +159,3 @@ DUMMY(pkey_mprotect); DUMMY(pkey_alloc); DUMMY(pkey_free); - -#define DUMMY_XATTR(s) \ -int \ -linux_ ## s ## xattr( \ - struct thread *td, struct linux_ ## s ## xattr_args *arg) \ -{ \ - \ - return (ENOATTR); \ -} -DUMMY_XATTR(set); -DUMMY_XATTR(lset); -DUMMY_XATTR(fset); -DUMMY_XATTR(get); -DUMMY_XATTR(lget); -DUMMY_XATTR(fget); -DUMMY_XATTR(list); -DUMMY_XATTR(llist); -DUMMY_XATTR(flist); -DUMMY_XATTR(remove); -DUMMY_XATTR(lremove); -DUMMY_XATTR(fremove); Index: sys/modules/linux/Makefile =================================================================== --- sys/modules/linux/Makefile +++ sys/modules/linux/Makefile @@ -15,7 +15,7 @@ linux${SFX}_machdep.c linux_misc.c linux_signal.c \ linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \ linux${SFX}_sysvec.c linux_uid16.c linux_time.c \ - linux_timer.c linux_vdso.c \ + linux_timer.c linux_vdso.c linux_xattr.c \ opt_inet6.h opt_compat.h opt_posix.h opt_usb.h vnode_if.h \ device_if.h bus_if.h assym.s \ linux${SFX}_support.s Index: sys/modules/linux64/Makefile =================================================================== --- sys/modules/linux64/Makefile +++ sys/modules/linux64/Makefile @@ -9,7 +9,8 @@ linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \ linux_machdep.c linux_misc.c linux_ptrace.c linux_signal.c \ linux_socket.c linux_stats.c linux_sysctl.c linux_sysent.c \ - linux_sysvec.c linux_time.c linux_vdso.c linux_timer.c \ + linux_sysvec.c linux_time.c linux_timer.c linux_vdso.c \ + linux_xattr.c \ opt_inet6.h opt_compat.h opt_posix.h opt_usb.h \ vnode_if.h device_if.h bus_if.h assym.s \ linux_support.s