diff --git a/lib/libc/sys/extattr_get_file.2 b/lib/libc/sys/extattr_get_file.2 index 5134c8d8ac0f..c38b27e17423 100644 --- a/lib/libc/sys/extattr_get_file.2 +++ b/lib/libc/sys/extattr_get_file.2 @@ -1,287 +1,292 @@ .\" .\" Copyright (c) 2001 Dima Dorfman .\" Copyright (c) 2003 Robert Watson .\" 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. .\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ .\" -.Dd December 7, 2020 +.Dd October 11, 2021 .Dt EXTATTR 2 .Os .Sh NAME .Nm extattr_delete_fd , .Nm extattr_delete_file , .Nm extattr_delete_link , .Nm extattr_get_fd , .Nm extattr_get_file , .Nm extattr_get_link , .Nm extattr_list_fd , .Nm extattr_list_file , .Nm extattr_list_link , .Nm extattr_set_fd , .Nm extattr_set_file , .Nm extattr_set_link .Nd system calls to manipulate VFS extended attributes .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/types.h .In sys/extattr.h .Ft int .Fn extattr_delete_fd "int fd" "int attrnamespace" "const char *attrname" .Ft int .Fn extattr_delete_file "const char *path" "int attrnamespace" "const char *attrname" .Ft int .Fn extattr_delete_link "const char *path" "int attrnamespace" "const char *attrname" .Ft ssize_t .Fn extattr_get_fd "int fd" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_get_file "const char *path" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_get_link "const char *path" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_list_fd "int fd" "int attrnamespace" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_list_file "const char *path" "int attrnamespace" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_list_link "const char *path" "int attrnamespace" "void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_set_fd "int fd" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_set_file "const char *path" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes" .Ft ssize_t .Fn extattr_set_link "const char *path" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes" .Sh DESCRIPTION Named extended attributes are meta-data associated with vnodes representing files and directories. They exist as .Qq Li name=value pairs within a set of namespaces. .Pp The .Fn extattr_get_file system call retrieves the value of the specified extended attribute into a buffer pointed to by .Fa data of size .Fa nbytes . The .Fn extattr_set_file system call sets the value of the specified extended attribute to the data described by .Fa data . The .Fn extattr_delete_file system call deletes the extended attribute specified. The .Fn extattr_list_file returns a list of attributes present in the requested namespace. Each list entry consists of a single byte containing the length of the attribute name, followed by the attribute name. The attribute name is not terminated by ASCII 0 (nul). The .Fn extattr_get_file and .Fn extattr_list_file calls consume the .Fa data and .Fa nbytes arguments in the style of .Xr read 2 ; .Fn extattr_set_file consumes these arguments in the style of .Xr write 2 . .Pp If .Fa data is .Dv NULL in a call to .Fn extattr_get_file and .Fn extattr_list_file then the size of defined extended attribute data will be returned, rather than the quantity read, permitting applications to test the size of the data without performing a read. The .Fn extattr_delete_link , .Fn extattr_get_link , and .Fn extattr_set_link system calls behave in the same way as their _file counterparts, except that they do not follow symlinks. .Pp The .Fn extattr_get_fd , .Fn extattr_delete_fd , .Fn extattr_list_fd , and .Fn extattr_set_fd calls are identical to their .Qq Li _file counterparts except for the first argument. The .Qq Li _fd functions take a file descriptor, while the .Qq Li _file functions take a path. Both arguments describe a file associated with the extended attribute that should be manipulated. +The +.Qq Li _fd +functions can be used with file descriptors opened with the +.Dv O_PATH +flag. .Pp The following arguments are common to all the system calls described here: .Bl -tag -width attrnamespace .It Fa attrnamespace the namespace in which the extended attribute resides; see .Xr extattr 9 .It Fa attrname the name of the extended attribute .El .Pp Named extended attribute semantics vary by file system implementing the call. Not all operations may be supported for a particular attribute. Additionally, the format of the data in .Fa data is attribute-specific. .Pp For more information on named extended attributes, please see .Xr extattr 9 . .Sh RETURN VALUES If successful, the .Fn extattr_get_fd , .Fn extattr_get_file , .Fn extattr_get_link , .Fn extattr_list_fd , .Fn extattr_list_file , .Fn extattr_list_link , .Fn extattr_set_fd , .Fn extattr_set_file , and .Fn extattr_set_link calls return the number of bytes that were read or written from the .Fa data , respectively. If .Fa data was .Dv NULL , then .Fn extattr_get_fd , .Fn extattr_get_file , .Fn extattr_get_link , .Fn extattr_list_fd , .Fn extattr_list_file , and .Fn extattr_list_link return the number of bytes available to read. If any of the calls are unsuccessful, the value \-1 is returned and the global variable .Va errno is set to indicate the error. .Pp .Rv -std extattr_delete_file .Sh ERRORS The following errors may be returned by the system calls themselves. Additionally, the file system implementing the call may return any other errors it desires. .Bl -tag -width Er .It Bq Er EFAULT The .Fa attrnamespace and .Fa attrname arguments, or the memory range defined by .Fa data and .Fa nbytes point outside the process's allocated address space. .It Bq Er ENAMETOOLONG The attribute name was longer than .Dv EXTATTR_MAXNAMELEN . .El .Pp The .Fn extattr_get_fd , .Fn extattr_set_fd , .Fn extattr_delete_fd , and .Fn extattr_list_fd system calls may also fail if: .Bl -tag -width Er .It Bq Er EBADF The file descriptor referenced by .Fa fd was invalid. .El .Pp Additionally, the .Fn extattr_get_file , .Fn extattr_set_file , and .Fn extattr_delete_file calls may also fail due to the following errors: .Bl -tag -width Er .It Bq Er ENOATTR The requested attribute was not defined for this file. .It Bq Er ENOTDIR A component of the path prefix is not a directory. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters. .It Bq Er ENOENT A component of the path name that must exist does not exist. .It Bq Er EACCES Search permission is denied for a component of the path prefix. .\" XXX are any missing? .El .Sh SEE ALSO .Xr extattr 3 , .Xr getextattr 8 , .Xr setextattr 8 , .Xr extattr 9 , .Xr VOP_GETEXTATTR 9 , .Xr VOP_SETEXTATTR 9 .Sh HISTORY Extended attribute support was developed as part of the .Tn TrustedBSD Project, and introduced in .Fx 5.0 . It was developed to support security extensions requiring additional labels to be associated with each file or directory. .Sh CAVEATS This interface is under active development, and as such is subject to change as applications are adapted to use it. Developers are discouraged from relying on its stability. .Sh BUGS In earlier versions of this API, passing an empty string for the attribute name to .Fn extattr_get_fd , .Fn extattr_get_file , or .Fn extattr_get_link would return the list of attributes defined for the target object. This interface has been deprecated in preference to using the explicit list API, and should not be used. diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index adb882288f6c..43b000c78110 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -1,755 +1,755 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1999-2001 Robert N. M. Watson * All rights reserved. * * This software was developed by Robert Watson for the TrustedBSD Project. * * 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. * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes, int follow); static int kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes, int follow); static int kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, int follow); static int kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, void *data, size_t nbytes, int follow); /* * Syscall to push extended attribute configuration information into the VFS. * Accepts a path, which it converts to a mountpoint, as well as a command * (int cmd), and attribute name and misc data. * * Currently this is used only by UFS1 extended attributes. */ #ifndef _SYS_SYSPROTO_H_ struct extattrctl_args { const char *path; int cmd; const char *filename; int attrnamespace; const char *attrname; }; #endif int sys_extattrctl(struct thread *td, struct extattrctl_args *uap) { struct vnode *filename_vp; struct nameidata nd; struct mount *mp, *mp_writable; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; AUDIT_ARG_CMD(uap->cmd); AUDIT_ARG_VALUE(uap->attrnamespace); /* * uap->attrname is not always defined. We check again later when we * invoke the VFS call so as to pass in NULL there if needed. */ if (uap->attrname != NULL) { error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); } AUDIT_ARG_TEXT(attrname); mp = NULL; filename_vp = NULL; if (uap->filename != NULL) { NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2, UIO_USERSPACE, uap->filename, td); error = namei(&nd); if (error) return (error); filename_vp = nd.ni_vp; NDFREE(&nd, NDF_NO_VP_RELE); } /* uap->path is always defined. */ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, uap->path, td); error = namei(&nd); if (error) goto out; mp = nd.ni_vp->v_mount; error = vfs_busy(mp, 0); if (error) { NDFREE(&nd, 0); mp = NULL; goto out; } VOP_UNLOCK(nd.ni_vp); error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH); NDFREE(&nd, NDF_NO_VP_UNLOCK); if (error) goto out; if (filename_vp != NULL) { /* * uap->filename is not always defined. If it is, * grab a vnode lock, which VFS_EXTATTRCTL() will * later release. */ error = vn_lock(filename_vp, LK_EXCLUSIVE); if (error) { vn_finished_write(mp_writable); goto out; } } error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace, uap->attrname != NULL ? attrname : NULL); vn_finished_write(mp_writable); out: if (mp != NULL) vfs_unbusy(mp); /* * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp, * so vrele it if it is defined. */ if (filename_vp != NULL) vrele(filename_vp); return (error); } /*- * Set a named extended attribute on a file or directory * * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", * kernelspace string pointer "attrname", userspace buffer * pointer "data", buffer length "nbytes", thread "td". * Returns: 0 on success, an error number otherwise * Locks: none * References: vp must be a valid reference for the duration of the call */ static int extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, void *data, size_t nbytes, struct thread *td) { struct mount *mp; struct uio auio; struct iovec aiov; ssize_t cnt; int error; if (nbytes > IOSIZE_MAX) return (EINVAL); error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); aiov.iov_base = data; aiov.iov_len = nbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_resid = nbytes; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_USERSPACE; auio.uio_td = td; cnt = nbytes; #ifdef MAC error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, attrname); if (error) goto done; #endif error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, td->td_ucred, td); cnt -= auio.uio_resid; td->td_retval[0] = cnt; #ifdef MAC done: #endif VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_set_fd_args { int fd; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td, uap->fd, + error = getvnode_path(td, uap->fd, cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); if (error) return (error); error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, attrname, uap->data, uap->nbytes, td); fdrop(fp, td); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_set_file_args { const char *path; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap) { return (kern_extattr_set_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, FOLLOW)); } #ifndef _SYS_SYSPROTO_H_ struct extattr_set_link_args { const char *path; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap) { return (kern_extattr_set_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); } static int kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, void *data, size_t nbytes, int follow) { struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return (error); AUDIT_ARG_TEXT(attrname); NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); error = namei(&nd); if (error) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data, nbytes, td); vrele(nd.ni_vp); return (error); } /*- * Get a named extended attribute on a file or directory * * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", * kernelspace string pointer "attrname", userspace buffer * pointer "data", buffer length "nbytes", thread "td". * Returns: 0 on success, an error number otherwise * Locks: none * References: vp must be a valid reference for the duration of the call */ static int extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, void *data, size_t nbytes, struct thread *td) { struct uio auio, *auiop; struct iovec aiov; ssize_t cnt; size_t size, *sizep; int error; if (nbytes > IOSIZE_MAX) return (EINVAL); vn_lock(vp, LK_SHARED | LK_RETRY); /* * Slightly unusual semantics: if the user provides a NULL data * pointer, they don't want to receive the data, just the maximum * read length. */ auiop = NULL; sizep = NULL; cnt = 0; if (data != NULL) { aiov.iov_base = data; aiov.iov_len = nbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_resid = nbytes; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_td = td; auiop = &auio; cnt = nbytes; } else sizep = &size; #ifdef MAC error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, attrname); if (error) goto done; #endif error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, td->td_ucred, td); if (auiop != NULL) { cnt -= auio.uio_resid; td->td_retval[0] = cnt; } else td->td_retval[0] = size; #ifdef MAC done: #endif VOP_UNLOCK(vp); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_get_fd_args { int fd; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td, uap->fd, + error = getvnode_path(td, uap->fd, cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp); if (error) return (error); error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, attrname, uap->data, uap->nbytes, td); fdrop(fp, td); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_get_file_args { const char *path; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap) { return (kern_extattr_get_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, FOLLOW)); } #ifndef _SYS_SYSPROTO_H_ struct extattr_get_link_args { const char *path; int attrnamespace; const char *attrname; void *data; size_t nbytes; }; #endif int sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap) { return (kern_extattr_get_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); } static int kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, void *data, size_t nbytes, int follow) { struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return (error); AUDIT_ARG_TEXT(attrname); NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); error = namei(&nd); if (error) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data, nbytes, td); vrele(nd.ni_vp); return (error); } /* * extattr_delete_vp(): Delete a named extended attribute on a file or * directory * * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", * kernelspace string pointer "attrname", proc "p" * Returns: 0 on success, an error number otherwise * Locks: none * References: vp must be a valid reference for the duration of the call */ static int extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, struct thread *td) { struct mount *mp; int error; error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error) return (error); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef MAC error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, attrname); if (error) goto done; #endif error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, td); if (error == EOPNOTSUPP) error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred, td); #ifdef MAC done: #endif VOP_UNLOCK(vp); vn_finished_write(mp); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_delete_fd_args { int fd; int attrnamespace; const char *attrname; }; #endif int sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap) { struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td, uap->fd, + error = getvnode_path(td, uap->fd, cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp); if (error) return (error); error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace, attrname, td); fdrop(fp, td); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_delete_file_args { const char *path; int attrnamespace; const char *attrname; }; #endif int sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap) { return (kern_extattr_delete_path(td, uap->path, uap->attrnamespace, uap->attrname, FOLLOW)); } #ifndef _SYS_SYSPROTO_H_ struct extattr_delete_link_args { const char *path; int attrnamespace; const char *attrname; }; #endif int sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap) { return (kern_extattr_delete_path(td, uap->path, uap->attrnamespace, uap->attrname, NOFOLLOW)); } static int kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, int follow) { struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return(error); AUDIT_ARG_TEXT(attrname); NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); error = namei(&nd); if (error) return(error); NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td); vrele(nd.ni_vp); return(error); } /*- * Retrieve a list of extended attributes on a file or directory. * * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", * userspace buffer pointer "data", buffer length "nbytes", * thread "td". * Returns: 0 on success, an error number otherwise * Locks: none * References: vp must be a valid reference for the duration of the call */ static int extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes, struct thread *td) { struct uio auio, *auiop; size_t size, *sizep; struct iovec aiov; ssize_t cnt; int error; if (nbytes > IOSIZE_MAX) return (EINVAL); auiop = NULL; sizep = NULL; cnt = 0; if (data != NULL) { aiov.iov_base = data; aiov.iov_len = nbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_resid = nbytes; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_td = td; auiop = &auio; cnt = nbytes; } else sizep = &size; vn_lock(vp, LK_SHARED | LK_RETRY); #ifdef MAC error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); if (error) { VOP_UNLOCK(vp); return (error); } #endif error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, td->td_ucred, td); VOP_UNLOCK(vp); if (auiop != NULL) { cnt -= auio.uio_resid; td->td_retval[0] = cnt; } else td->td_retval[0] = size; return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_list_fd_args { int fd; int attrnamespace; void *data; size_t nbytes; }; #endif int sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap) { struct file *fp; cap_rights_t rights; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); - error = getvnode(td, uap->fd, + error = getvnode_path(td, uap->fd, cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp); if (error) return (error); error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, uap->nbytes, td); fdrop(fp, td); return (error); } #ifndef _SYS_SYSPROTO_H_ struct extattr_list_file_args { const char *path; int attrnamespace; void *data; size_t nbytes; } #endif int sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap) { return (kern_extattr_list_path(td, uap->path, uap->attrnamespace, uap->data, uap->nbytes, FOLLOW)); } #ifndef _SYS_SYSPROTO_H_ struct extattr_list_link_args { const char *path; int attrnamespace; void *data; size_t nbytes; }; #endif int sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap) { return (kern_extattr_list_path(td, uap->path, uap->attrnamespace, uap->data, uap->nbytes, NOFOLLOW)); } static int kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, void *data, size_t nbytes, int follow) { struct nameidata nd; int error; AUDIT_ARG_VALUE(attrnamespace); NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); error = namei(&nd); if (error) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_list_vp(nd.ni_vp, attrnamespace, data, nbytes, td); vrele(nd.ni_vp); return (error); }