2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 1999-2001 Robert N. M. Watson
7 * This software was developed by Robert Watson for the TrustedBSD Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capsicum.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sysproto.h>
39 #include <sys/fcntl.h>
40 #include <sys/namei.h>
41 #include <sys/filedesc.h>
42 #include <sys/limits.h>
43 #include <sys/vnode.h>
45 #include <sys/extattr.h>
46 #include <sys/syscallsubr.h>
48 #include <security/audit/audit.h>
49 #include <security/mac/mac_framework.h>
51 static int user_extattr_set_path(struct thread *td, const char *path,
52 int attrnamespace, const char *attrname, void *data,
53 size_t nbytes, int follow);
54 static int user_extattr_get_path(struct thread *td, const char *path,
55 int attrnamespace, const char *attrname, void *data,
56 size_t nbytes, int follow);
57 static int user_extattr_delete_path(struct thread *td, const char *path,
58 int attrnamespace, const char *attrname, int follow);
59 static int user_extattr_list_path(struct thread *td, const char *path,
60 int attrnamespace, void *data, size_t nbytes, int follow);
63 * Syscall to push extended attribute configuration information into the VFS.
64 * Accepts a path, which it converts to a mountpoint, as well as a command
65 * (int cmd), and attribute name and misc data.
67 * Currently this is used only by UFS1 extended attributes.
69 #ifndef _SYS_SYSPROTO_H_
70 struct extattrctl_args {
79 sys_extattrctl(struct thread *td, struct extattrctl_args *uap)
81 struct vnode *filename_vp;
83 struct mount *mp, *mp_writable;
84 char attrname[EXTATTR_MAXNAMELEN + 1];
87 AUDIT_ARG_CMD(uap->cmd);
88 AUDIT_ARG_VALUE(uap->attrnamespace);
90 * uap->attrname is not always defined. We check again later when we
91 * invoke the VFS call so as to pass in NULL there if needed.
93 if (uap->attrname != NULL) {
94 error = copyinstr(uap->attrname, attrname, sizeof(attrname),
99 AUDIT_ARG_TEXT(attrname);
103 if (uap->filename != NULL) {
104 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2, UIO_USERSPACE,
109 filename_vp = nd.ni_vp;
113 /* uap->path is always defined. */
114 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
119 mp = nd.ni_vp->v_mount;
120 error = vfs_busy(mp, 0);
127 VOP_UNLOCK(nd.ni_vp);
128 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | V_PCATCH);
133 if (filename_vp != NULL) {
135 * uap->filename is not always defined. If it is,
136 * grab a vnode lock, which VFS_EXTATTRCTL() will
139 error = vn_lock(filename_vp, LK_EXCLUSIVE);
141 vn_finished_write(mp_writable);
146 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
147 uap->attrname != NULL ? attrname : NULL);
149 vn_finished_write(mp_writable);
155 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
156 * so vrele it if it is defined.
158 if (filename_vp != NULL)
164 * Set a named extended attribute on a file or directory
166 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
167 * kernelspace string pointer "attrname", userspace buffer
168 * pointer "data", buffer length "nbytes", thread "td".
169 * Returns: 0 on success, an error number otherwise
171 * References: vp must be a valid reference for the duration of the call
174 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
175 void *data, size_t nbytes, struct thread *td)
183 if (nbytes > IOSIZE_MAX)
186 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
189 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
191 aiov.iov_base = data;
192 aiov.iov_len = nbytes;
193 auio.uio_iov = &aiov;
196 auio.uio_resid = nbytes;
197 auio.uio_rw = UIO_WRITE;
198 auio.uio_segflg = UIO_USERSPACE;
203 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
209 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
211 cnt -= auio.uio_resid;
212 td->td_retval[0] = cnt;
218 vn_finished_write(mp);
222 #ifndef _SYS_SYSPROTO_H_
223 struct extattr_set_fd_args {
226 const char *attrname;
232 sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap)
234 char attrname[EXTATTR_MAXNAMELEN + 1];
237 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
240 return (kern_extattr_set_fd(td, uap->fd, uap->attrnamespace,
241 attrname, uap->data, uap->nbytes));
245 kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace,
246 const char *attrname, void *data, size_t nbytes)
253 AUDIT_ARG_VALUE(attrnamespace);
254 AUDIT_ARG_TEXT(attrname);
256 error = getvnode_path(td, fd,
257 cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp);
261 error = extattr_set_vp(fp->f_vnode, attrnamespace,
262 attrname, data, nbytes, td);
268 #ifndef _SYS_SYSPROTO_H_
269 struct extattr_set_file_args {
272 const char *attrname;
278 sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap)
281 return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
282 uap->attrname, uap->data, uap->nbytes, FOLLOW));
285 #ifndef _SYS_SYSPROTO_H_
286 struct extattr_set_link_args {
289 const char *attrname;
295 sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap)
298 return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
299 uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
303 user_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
304 const char *uattrname, void *data, size_t nbytes, int follow)
306 char attrname[EXTATTR_MAXNAMELEN + 1];
309 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
312 return (kern_extattr_set_path(td, path, attrnamespace,
313 attrname, data, nbytes, follow, UIO_USERSPACE));
317 kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
318 const char *attrname, void *data, size_t nbytes, int follow,
319 enum uio_seg pathseg)
324 AUDIT_ARG_VALUE(attrnamespace);
325 AUDIT_ARG_TEXT(attrname);
327 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
333 error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data,
341 * Get a named extended attribute on a file or directory
343 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
344 * kernelspace string pointer "attrname", userspace buffer
345 * pointer "data", buffer length "nbytes", thread "td".
346 * Returns: 0 on success, an error number otherwise
348 * References: vp must be a valid reference for the duration of the call
351 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
352 void *data, size_t nbytes, struct thread *td)
354 struct uio auio, *auiop;
360 if (nbytes > IOSIZE_MAX)
363 vn_lock(vp, LK_SHARED | LK_RETRY);
366 * Slightly unusual semantics: if the user provides a NULL data
367 * pointer, they don't want to receive the data, just the maximum
374 aiov.iov_base = data;
375 aiov.iov_len = nbytes;
376 auio.uio_iov = &aiov;
379 auio.uio_resid = nbytes;
380 auio.uio_rw = UIO_READ;
381 auio.uio_segflg = UIO_USERSPACE;
389 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
395 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
399 cnt -= auio.uio_resid;
400 td->td_retval[0] = cnt;
402 td->td_retval[0] = size;
410 #ifndef _SYS_SYSPROTO_H_
411 struct extattr_get_fd_args {
414 const char *attrname;
420 sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap)
422 char attrname[EXTATTR_MAXNAMELEN + 1];
425 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
428 return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace,
429 attrname, uap->data, uap->nbytes));
433 kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace,
434 const char *attrname, void *data, size_t nbytes)
441 AUDIT_ARG_VALUE(attrnamespace);
442 AUDIT_ARG_TEXT(attrname);
444 error = getvnode_path(td, fd,
445 cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp);
449 error = extattr_get_vp(fp->f_vnode, attrnamespace,
450 attrname, data, nbytes, td);
456 #ifndef _SYS_SYSPROTO_H_
457 struct extattr_get_file_args {
460 const char *attrname;
466 sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap)
468 return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
469 uap->attrname, uap->data, uap->nbytes, FOLLOW));
472 #ifndef _SYS_SYSPROTO_H_
473 struct extattr_get_link_args {
476 const char *attrname;
482 sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap)
484 return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
485 uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
489 user_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
490 const char *uattrname, void *data, size_t nbytes, int follow)
492 char attrname[EXTATTR_MAXNAMELEN + 1];
495 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
498 return (kern_extattr_get_path(td, path, attrnamespace,
499 attrname, data, nbytes, follow, UIO_USERSPACE));
503 kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
504 const char *attrname, void *data, size_t nbytes, int follow,
505 enum uio_seg pathseg)
510 AUDIT_ARG_VALUE(attrnamespace);
511 AUDIT_ARG_TEXT(attrname);
513 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
519 error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data,
527 * extattr_delete_vp(): Delete a named extended attribute on a file or
530 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
531 * kernelspace string pointer "attrname", proc "p"
532 * Returns: 0 on success, an error number otherwise
534 * References: vp must be a valid reference for the duration of the call
537 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
543 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
546 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
549 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
555 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
557 if (error == EOPNOTSUPP)
558 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
564 vn_finished_write(mp);
568 #ifndef _SYS_SYSPROTO_H_
569 struct extattr_delete_fd_args {
572 const char *attrname;
576 sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap)
578 char attrname[EXTATTR_MAXNAMELEN + 1];
581 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
584 return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace,
589 kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace,
590 const char *attrname)
597 AUDIT_ARG_VALUE(attrnamespace);
598 AUDIT_ARG_TEXT(attrname);
600 error = getvnode_path(td, fd,
601 cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp);
605 error = extattr_delete_vp(fp->f_vnode, attrnamespace,
611 #ifndef _SYS_SYSPROTO_H_
612 struct extattr_delete_file_args {
615 const char *attrname;
619 sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap)
622 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
623 uap->attrname, FOLLOW));
626 #ifndef _SYS_SYSPROTO_H_
627 struct extattr_delete_link_args {
630 const char *attrname;
634 sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap)
637 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
638 uap->attrname, NOFOLLOW));
642 user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
643 const char *uattrname, int follow)
645 char attrname[EXTATTR_MAXNAMELEN + 1];
648 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
651 return (kern_extattr_delete_path(td, path, attrnamespace,
652 attrname, follow, UIO_USERSPACE));
656 kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
657 const char *attrname, int follow, enum uio_seg pathseg)
662 AUDIT_ARG_VALUE(attrnamespace);
663 AUDIT_ARG_TEXT(attrname);
665 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
671 error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td);
677 * Retrieve a list of extended attributes on a file or directory.
679 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
680 * userspace buffer pointer "data", buffer length "nbytes",
682 * Returns: 0 on success, an error number otherwise
684 * References: vp must be a valid reference for the duration of the call
687 extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop,
697 if (auiop->uio_resid > IOSIZE_MAX)
699 cnt = auiop->uio_resid;
703 vn_lock(vp, LK_SHARED | LK_RETRY);
706 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
713 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
718 cnt -= auiop->uio_resid;
719 td->td_retval[0] = cnt;
721 td->td_retval[0] = size;
725 #ifndef _SYS_SYSPROTO_H_
726 struct extattr_list_fd_args {
734 sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap)
736 struct uio auio, *auiop;
739 if (uap->data != NULL) {
740 aiov.iov_base = uap->data;
741 aiov.iov_len = uap->nbytes;
742 auio.uio_iov = &aiov;
745 auio.uio_resid = uap->nbytes;
746 auio.uio_rw = UIO_READ;
747 auio.uio_segflg = UIO_USERSPACE;
753 return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace,
758 kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace,
766 AUDIT_ARG_VALUE(attrnamespace);
767 error = getvnode_path(td, fd,
768 cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp);
772 error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td);
778 #ifndef _SYS_SYSPROTO_H_
779 struct extattr_list_file_args {
787 sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap)
790 return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
791 uap->data, uap->nbytes, FOLLOW));
794 #ifndef _SYS_SYSPROTO_H_
795 struct extattr_list_link_args {
803 sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap)
806 return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
807 uap->data, uap->nbytes, NOFOLLOW));
811 user_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
812 void *data, size_t nbytes, int follow)
814 struct uio auio, *auiop;
818 aiov.iov_base = data;
819 aiov.iov_len = nbytes;
820 auio.uio_iov = &aiov;
823 auio.uio_resid = nbytes;
824 auio.uio_rw = UIO_READ;
825 auio.uio_segflg = UIO_USERSPACE;
831 return (kern_extattr_list_path(td, path, attrnamespace,
832 auiop, follow, UIO_USERSPACE));
836 kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
837 struct uio *auiop, int follow, enum uio_seg pathseg)
842 AUDIT_ARG_VALUE(attrnamespace);
843 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
849 error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td);