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>
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>
47 #include <security/audit/audit.h>
48 #include <security/mac/mac_framework.h>
51 * Syscall to push extended attribute configuration information into the VFS.
52 * Accepts a path, which it converts to a mountpoint, as well as a command
53 * (int cmd), and attribute name and misc data.
55 * Currently this is used only by UFS1 extended attributes.
58 sys_extattrctl(td, uap)
60 struct extattrctl_args /* {
68 struct vnode *filename_vp;
70 struct mount *mp, *mp_writable;
71 char attrname[EXTATTR_MAXNAMELEN];
74 AUDIT_ARG_CMD(uap->cmd);
75 AUDIT_ARG_VALUE(uap->attrnamespace);
77 * uap->attrname is not always defined. We check again later when we
78 * invoke the VFS call so as to pass in NULL there if needed.
80 if (uap->attrname != NULL) {
81 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
86 AUDIT_ARG_TEXT(attrname);
90 if (uap->filename != NULL) {
91 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2,
92 UIO_USERSPACE, uap->filename, td);
96 filename_vp = nd.ni_vp;
97 NDFREE(&nd, NDF_NO_VP_RELE);
100 /* uap->path is always defined. */
101 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
102 UIO_USERSPACE, uap->path, td);
106 mp = nd.ni_vp->v_mount;
107 error = vfs_busy(mp, 0);
113 VOP_UNLOCK(nd.ni_vp, 0);
114 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
115 NDFREE(&nd, NDF_NO_VP_UNLOCK);
118 if (filename_vp != NULL) {
120 * uap->filename is not always defined. If it is,
121 * grab a vnode lock, which VFS_EXTATTRCTL() will
124 error = vn_lock(filename_vp, LK_EXCLUSIVE);
126 vn_finished_write(mp_writable);
131 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
132 uap->attrname != NULL ? attrname : NULL);
134 vn_finished_write(mp_writable);
140 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
141 * so vrele it if it is defined.
143 if (filename_vp != NULL)
149 * Set a named extended attribute on a file or directory
151 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
152 * kernelspace string pointer "attrname", userspace buffer
153 * pointer "data", buffer length "nbytes", thread "td".
154 * Returns: 0 on success, an error number otherwise
156 * References: vp must be a valid reference for the duration of the call
159 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
160 void *data, size_t nbytes, struct thread *td)
168 if (nbytes > IOSIZE_MAX)
171 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
174 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
176 aiov.iov_base = data;
177 aiov.iov_len = nbytes;
178 auio.uio_iov = &aiov;
181 auio.uio_resid = nbytes;
182 auio.uio_rw = UIO_WRITE;
183 auio.uio_segflg = UIO_USERSPACE;
188 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
194 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
196 cnt -= auio.uio_resid;
197 td->td_retval[0] = cnt;
203 vn_finished_write(mp);
208 sys_extattr_set_fd(td, uap)
210 struct extattr_set_fd_args /* {
213 const char *attrname;
219 char attrname[EXTATTR_MAXNAMELEN];
223 AUDIT_ARG_FD(uap->fd);
224 AUDIT_ARG_VALUE(uap->attrnamespace);
225 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
228 AUDIT_ARG_TEXT(attrname);
230 error = getvnode(td, uap->fd,
231 cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
235 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
236 attrname, uap->data, uap->nbytes, td);
243 sys_extattr_set_file(td, uap)
245 struct extattr_set_file_args /* {
248 const char *attrname;
254 char attrname[EXTATTR_MAXNAMELEN];
257 AUDIT_ARG_VALUE(uap->attrnamespace);
258 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
261 AUDIT_ARG_TEXT(attrname);
263 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE,
268 NDFREE(&nd, NDF_ONLY_PNBUF);
270 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
271 uap->data, uap->nbytes, td);
278 sys_extattr_set_link(td, uap)
280 struct extattr_set_link_args /* {
283 const char *attrname;
289 char attrname[EXTATTR_MAXNAMELEN];
292 AUDIT_ARG_VALUE(uap->attrnamespace);
293 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
296 AUDIT_ARG_TEXT(attrname);
298 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
303 NDFREE(&nd, NDF_ONLY_PNBUF);
305 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
306 uap->data, uap->nbytes, td);
313 * Get a named extended attribute on a file or directory
315 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
316 * kernelspace string pointer "attrname", userspace buffer
317 * pointer "data", buffer length "nbytes", thread "td".
318 * Returns: 0 on success, an error number otherwise
320 * References: vp must be a valid reference for the duration of the call
323 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
324 void *data, size_t nbytes, struct thread *td)
326 struct uio auio, *auiop;
332 if (nbytes > IOSIZE_MAX)
335 vn_lock(vp, LK_SHARED | LK_RETRY);
338 * Slightly unusual semantics: if the user provides a NULL data
339 * pointer, they don't want to receive the data, just the maximum
346 aiov.iov_base = data;
347 aiov.iov_len = nbytes;
348 auio.uio_iov = &aiov;
351 auio.uio_resid = nbytes;
352 auio.uio_rw = UIO_READ;
353 auio.uio_segflg = UIO_USERSPACE;
361 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
367 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
371 cnt -= auio.uio_resid;
372 td->td_retval[0] = cnt;
374 td->td_retval[0] = size;
383 sys_extattr_get_fd(td, uap)
385 struct extattr_get_fd_args /* {
388 const char *attrname;
394 char attrname[EXTATTR_MAXNAMELEN];
398 AUDIT_ARG_FD(uap->fd);
399 AUDIT_ARG_VALUE(uap->attrnamespace);
400 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
403 AUDIT_ARG_TEXT(attrname);
405 error = getvnode(td, uap->fd,
406 cap_rights_init(&rights, CAP_EXTATTR_GET), &fp);
410 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
411 attrname, uap->data, uap->nbytes, td);
418 sys_extattr_get_file(td, uap)
420 struct extattr_get_file_args /* {
423 const char *attrname;
429 char attrname[EXTATTR_MAXNAMELEN];
432 AUDIT_ARG_VALUE(uap->attrnamespace);
433 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
436 AUDIT_ARG_TEXT(attrname);
438 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
442 NDFREE(&nd, NDF_ONLY_PNBUF);
444 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
445 uap->data, uap->nbytes, td);
452 sys_extattr_get_link(td, uap)
454 struct extattr_get_link_args /* {
457 const char *attrname;
463 char attrname[EXTATTR_MAXNAMELEN];
466 AUDIT_ARG_VALUE(uap->attrnamespace);
467 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
470 AUDIT_ARG_TEXT(attrname);
472 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
477 NDFREE(&nd, NDF_ONLY_PNBUF);
479 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
480 uap->data, uap->nbytes, td);
487 * extattr_delete_vp(): Delete a named extended attribute on a file or
490 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
491 * kernelspace string pointer "attrname", proc "p"
492 * Returns: 0 on success, an error number otherwise
494 * References: vp must be a valid reference for the duration of the call
497 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
503 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
506 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
509 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
515 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
517 if (error == EOPNOTSUPP)
518 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
524 vn_finished_write(mp);
529 sys_extattr_delete_fd(td, uap)
531 struct extattr_delete_fd_args /* {
534 const char *attrname;
538 char attrname[EXTATTR_MAXNAMELEN];
542 AUDIT_ARG_FD(uap->fd);
543 AUDIT_ARG_VALUE(uap->attrnamespace);
544 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
547 AUDIT_ARG_TEXT(attrname);
549 error = getvnode(td, uap->fd,
550 cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp);
554 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
561 sys_extattr_delete_file(td, uap)
563 struct extattr_delete_file_args /* {
566 const char *attrname;
570 char attrname[EXTATTR_MAXNAMELEN];
573 AUDIT_ARG_VALUE(uap->attrnamespace);
574 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
577 AUDIT_ARG_TEXT(attrname);
579 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
583 NDFREE(&nd, NDF_ONLY_PNBUF);
585 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
591 sys_extattr_delete_link(td, uap)
593 struct extattr_delete_link_args /* {
596 const char *attrname;
600 char attrname[EXTATTR_MAXNAMELEN];
603 AUDIT_ARG_VALUE(uap->attrnamespace);
604 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
607 AUDIT_ARG_TEXT(attrname);
609 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
613 NDFREE(&nd, NDF_ONLY_PNBUF);
615 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
621 * Retrieve a list of extended attributes on a file or directory.
623 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
624 * userspace buffer pointer "data", buffer length "nbytes",
626 * Returns: 0 on success, an error number otherwise
628 * References: vp must be a valid reference for the duration of the call
631 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
632 size_t nbytes, struct thread *td)
634 struct uio auio, *auiop;
640 if (nbytes > IOSIZE_MAX)
643 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
649 aiov.iov_base = data;
650 aiov.iov_len = nbytes;
651 auio.uio_iov = &aiov;
654 auio.uio_resid = nbytes;
655 auio.uio_rw = UIO_READ;
656 auio.uio_segflg = UIO_USERSPACE;
664 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
669 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
673 cnt -= auio.uio_resid;
674 td->td_retval[0] = cnt;
676 td->td_retval[0] = size;
686 sys_extattr_list_fd(td, uap)
688 struct extattr_list_fd_args /* {
699 AUDIT_ARG_FD(uap->fd);
700 AUDIT_ARG_VALUE(uap->attrnamespace);
701 error = getvnode(td, uap->fd,
702 cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp);
706 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
714 sys_extattr_list_file(td, uap)
716 struct extattr_list_file_args /* {
726 AUDIT_ARG_VALUE(uap->attrnamespace);
727 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
731 NDFREE(&nd, NDF_ONLY_PNBUF);
733 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
741 sys_extattr_list_link(td, uap)
743 struct extattr_list_link_args /* {
753 AUDIT_ARG_VALUE(uap->attrnamespace);
754 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
759 NDFREE(&nd, NDF_ONLY_PNBUF);
761 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,