2 * Copyright (c) 1999-2001 Robert N. M. Watson
5 * This software was developed by Robert Watson for the TrustedBSD Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <sys/mount.h>
36 #include <sys/mutex.h>
37 #include <sys/sysproto.h>
38 #include <sys/fcntl.h>
39 #include <sys/namei.h>
40 #include <sys/filedesc.h>
41 #include <sys/limits.h>
42 #include <sys/vnode.h>
44 #include <sys/extattr.h>
46 #include <security/audit/audit.h>
47 #include <security/mac/mac_framework.h>
50 * Syscall to push extended attribute configuration information into the VFS.
51 * Accepts a path, which it converts to a mountpoint, as well as a command
52 * (int cmd), and attribute name and misc data.
54 * Currently this is used only by UFS1 extended attributes.
59 struct extattrctl_args /* {
67 struct vnode *filename_vp;
69 struct mount *mp, *mp_writable;
70 char attrname[EXTATTR_MAXNAMELEN];
71 int vfslocked, fnvfslocked, error;
73 AUDIT_ARG_CMD(uap->cmd);
74 AUDIT_ARG_VALUE(uap->attrnamespace);
76 * uap->attrname is not always defined. We check again later when we
77 * invoke the VFS call so as to pass in NULL there if needed.
79 if (uap->attrname != NULL) {
80 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
85 AUDIT_ARG_TEXT(attrname);
87 vfslocked = fnvfslocked = 0;
90 if (uap->filename != NULL) {
91 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE2,
92 UIO_USERSPACE, uap->filename, td);
96 fnvfslocked = NDHASGIANT(&nd);
97 filename_vp = nd.ni_vp;
98 NDFREE(&nd, NDF_NO_VP_RELE);
101 /* uap->path is always defined. */
102 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | AUDITVNODE1,
103 UIO_USERSPACE, uap->path, td);
107 vfslocked = NDHASGIANT(&nd);
108 mp = nd.ni_vp->v_mount;
109 error = vfs_busy(mp, 0);
115 VOP_UNLOCK(nd.ni_vp, 0);
116 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
117 NDFREE(&nd, NDF_NO_VP_UNLOCK);
120 if (filename_vp != NULL) {
122 * uap->filename is not always defined. If it is,
123 * grab a vnode lock, which VFS_EXTATTRCTL() will
126 error = vn_lock(filename_vp, LK_EXCLUSIVE);
128 vn_finished_write(mp_writable);
133 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
134 uap->attrname != NULL ? attrname : NULL);
136 vn_finished_write(mp_writable);
142 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
143 * so vrele it if it is defined.
145 if (filename_vp != NULL)
147 VFS_UNLOCK_GIANT(fnvfslocked);
148 VFS_UNLOCK_GIANT(vfslocked);
153 * Set a named extended attribute on a file or directory
155 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
156 * kernelspace string pointer "attrname", userspace buffer
157 * pointer "data", buffer length "nbytes", thread "td".
158 * Returns: 0 on success, an error number otherwise
160 * References: vp must be a valid reference for the duration of the call
163 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
164 void *data, size_t nbytes, struct thread *td)
172 VFS_ASSERT_GIANT(vp->v_mount);
173 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
176 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
178 aiov.iov_base = data;
179 aiov.iov_len = nbytes;
180 auio.uio_iov = &aiov;
183 if (nbytes > INT_MAX) {
187 auio.uio_resid = nbytes;
188 auio.uio_rw = UIO_WRITE;
189 auio.uio_segflg = UIO_USERSPACE;
194 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
200 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
202 cnt -= auio.uio_resid;
203 td->td_retval[0] = cnt;
207 vn_finished_write(mp);
212 extattr_set_fd(td, uap)
214 struct extattr_set_fd_args /* {
217 const char *attrname;
223 char attrname[EXTATTR_MAXNAMELEN];
224 int vfslocked, error;
226 AUDIT_ARG_FD(uap->fd);
227 AUDIT_ARG_VALUE(uap->attrnamespace);
228 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
231 AUDIT_ARG_TEXT(attrname);
233 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
237 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
238 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
239 attrname, uap->data, uap->nbytes, td);
241 VFS_UNLOCK_GIANT(vfslocked);
247 extattr_set_file(td, uap)
249 struct extattr_set_file_args /* {
252 const char *attrname;
258 char attrname[EXTATTR_MAXNAMELEN];
259 int vfslocked, error;
261 AUDIT_ARG_VALUE(uap->attrnamespace);
262 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
265 AUDIT_ARG_TEXT(attrname);
267 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
272 NDFREE(&nd, NDF_ONLY_PNBUF);
274 vfslocked = NDHASGIANT(&nd);
275 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
276 uap->data, uap->nbytes, td);
279 VFS_UNLOCK_GIANT(vfslocked);
284 extattr_set_link(td, uap)
286 struct extattr_set_link_args /* {
289 const char *attrname;
295 char attrname[EXTATTR_MAXNAMELEN];
296 int vfslocked, error;
298 AUDIT_ARG_VALUE(uap->attrnamespace);
299 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
302 AUDIT_ARG_TEXT(attrname);
304 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
309 NDFREE(&nd, NDF_ONLY_PNBUF);
311 vfslocked = NDHASGIANT(&nd);
312 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
313 uap->data, uap->nbytes, td);
316 VFS_UNLOCK_GIANT(vfslocked);
321 * Get a named extended attribute on a file or directory
323 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
324 * kernelspace string pointer "attrname", userspace buffer
325 * pointer "data", buffer length "nbytes", thread "td".
326 * Returns: 0 on success, an error number otherwise
328 * References: vp must be a valid reference for the duration of the call
331 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
332 void *data, size_t nbytes, struct thread *td)
334 struct uio auio, *auiop;
340 VFS_ASSERT_GIANT(vp->v_mount);
341 vn_lock(vp, LK_SHARED | LK_RETRY);
344 * Slightly unusual semantics: if the user provides a NULL data
345 * pointer, they don't want to receive the data, just the maximum
352 aiov.iov_base = data;
353 aiov.iov_len = nbytes;
354 auio.uio_iov = &aiov;
357 if (nbytes > INT_MAX) {
361 auio.uio_resid = nbytes;
362 auio.uio_rw = UIO_READ;
363 auio.uio_segflg = UIO_USERSPACE;
371 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
377 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
381 cnt -= auio.uio_resid;
382 td->td_retval[0] = cnt;
384 td->td_retval[0] = size;
392 extattr_get_fd(td, uap)
394 struct extattr_get_fd_args /* {
397 const char *attrname;
403 char attrname[EXTATTR_MAXNAMELEN];
404 int vfslocked, error;
406 AUDIT_ARG_FD(uap->fd);
407 AUDIT_ARG_VALUE(uap->attrnamespace);
408 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
411 AUDIT_ARG_TEXT(attrname);
413 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
417 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
418 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
419 attrname, uap->data, uap->nbytes, td);
422 VFS_UNLOCK_GIANT(vfslocked);
427 extattr_get_file(td, uap)
429 struct extattr_get_file_args /* {
432 const char *attrname;
438 char attrname[EXTATTR_MAXNAMELEN];
439 int vfslocked, error;
441 AUDIT_ARG_VALUE(uap->attrnamespace);
442 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
445 AUDIT_ARG_TEXT(attrname);
447 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
452 NDFREE(&nd, NDF_ONLY_PNBUF);
454 vfslocked = NDHASGIANT(&nd);
455 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
456 uap->data, uap->nbytes, td);
459 VFS_UNLOCK_GIANT(vfslocked);
464 extattr_get_link(td, uap)
466 struct extattr_get_link_args /* {
469 const char *attrname;
475 char attrname[EXTATTR_MAXNAMELEN];
476 int vfslocked, error;
478 AUDIT_ARG_VALUE(uap->attrnamespace);
479 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
482 AUDIT_ARG_TEXT(attrname);
484 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
489 NDFREE(&nd, NDF_ONLY_PNBUF);
491 vfslocked = NDHASGIANT(&nd);
492 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
493 uap->data, uap->nbytes, td);
496 VFS_UNLOCK_GIANT(vfslocked);
501 * extattr_delete_vp(): Delete a named extended attribute on a file or
504 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
505 * kernelspace string pointer "attrname", proc "p"
506 * Returns: 0 on success, an error number otherwise
508 * References: vp must be a valid reference for the duration of the call
511 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
517 VFS_ASSERT_GIANT(vp->v_mount);
518 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
521 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
524 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
530 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
532 if (error == EOPNOTSUPP)
533 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
539 vn_finished_write(mp);
544 extattr_delete_fd(td, uap)
546 struct extattr_delete_fd_args /* {
549 const char *attrname;
553 char attrname[EXTATTR_MAXNAMELEN];
554 int vfslocked, error;
556 AUDIT_ARG_FD(uap->fd);
557 AUDIT_ARG_VALUE(uap->attrnamespace);
558 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
561 AUDIT_ARG_TEXT(attrname);
563 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
567 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
568 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
571 VFS_UNLOCK_GIANT(vfslocked);
576 extattr_delete_file(td, uap)
578 struct extattr_delete_file_args /* {
581 const char *attrname;
585 char attrname[EXTATTR_MAXNAMELEN];
586 int vfslocked, error;
588 AUDIT_ARG_VALUE(uap->attrnamespace);
589 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
592 AUDIT_ARG_TEXT(attrname);
594 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
599 NDFREE(&nd, NDF_ONLY_PNBUF);
601 vfslocked = NDHASGIANT(&nd);
602 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
604 VFS_UNLOCK_GIANT(vfslocked);
609 extattr_delete_link(td, uap)
611 struct extattr_delete_link_args /* {
614 const char *attrname;
618 char attrname[EXTATTR_MAXNAMELEN];
619 int vfslocked, error;
621 AUDIT_ARG_VALUE(uap->attrnamespace);
622 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
625 AUDIT_ARG_TEXT(attrname);
627 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
632 NDFREE(&nd, NDF_ONLY_PNBUF);
634 vfslocked = NDHASGIANT(&nd);
635 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
637 VFS_UNLOCK_GIANT(vfslocked);
642 * Retrieve a list of extended attributes on a file or directory.
644 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
645 * userspace buffer pointer "data", buffer length "nbytes",
647 * Returns: 0 on success, an error number otherwise
649 * References: vp must be a valid reference for the duration of the call
652 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
653 size_t nbytes, struct thread *td)
655 struct uio auio, *auiop;
661 VFS_ASSERT_GIANT(vp->v_mount);
662 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
668 aiov.iov_base = data;
669 aiov.iov_len = nbytes;
670 auio.uio_iov = &aiov;
673 if (nbytes > INT_MAX) {
677 auio.uio_resid = nbytes;
678 auio.uio_rw = UIO_READ;
679 auio.uio_segflg = UIO_USERSPACE;
687 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
692 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
696 cnt -= auio.uio_resid;
697 td->td_retval[0] = cnt;
699 td->td_retval[0] = size;
708 extattr_list_fd(td, uap)
710 struct extattr_list_fd_args /* {
718 int vfslocked, error;
720 AUDIT_ARG_FD(uap->fd);
721 AUDIT_ARG_VALUE(uap->attrnamespace);
722 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
726 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
727 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
731 VFS_UNLOCK_GIANT(vfslocked);
736 extattr_list_file(td, uap)
738 struct extattr_list_file_args /* {
746 int vfslocked, error;
748 AUDIT_ARG_VALUE(uap->attrnamespace);
749 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
754 NDFREE(&nd, NDF_ONLY_PNBUF);
756 vfslocked = NDHASGIANT(&nd);
757 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
761 VFS_UNLOCK_GIANT(vfslocked);
766 extattr_list_link(td, uap)
768 struct extattr_list_link_args /* {
776 int vfslocked, error;
778 AUDIT_ARG_VALUE(uap->attrnamespace);
779 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
784 NDFREE(&nd, NDF_ONLY_PNBUF);
786 vfslocked = NDHASGIANT(&nd);
787 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
791 VFS_UNLOCK_GIANT(vfslocked);