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 error
= vn_start_write(vp
, &mp
, V_WAIT
| PCATCH
);
171 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
173 aiov
.iov_base
= data
;
174 aiov
.iov_len
= nbytes
;
175 auio
.uio_iov
= &aiov
;
178 if (nbytes
> IOSIZE_MAX
) {
182 auio
.uio_resid
= nbytes
;
183 auio
.uio_rw
= UIO_WRITE
;
184 auio
.uio_segflg
= UIO_USERSPACE
;
189 error
= mac_vnode_check_setextattr(td
->td_ucred
, vp
, attrnamespace
,
195 error
= VOP_SETEXTATTR(vp
, attrnamespace
, attrname
, &auio
,
197 cnt
-= auio
.uio_resid
;
198 td
->td_retval
[0] = cnt
;
202 vn_finished_write(mp
);
207 sys_extattr_set_fd(td
, uap
)
209 struct extattr_set_fd_args
/* {
212 const char *attrname;
218 char attrname
[EXTATTR_MAXNAMELEN
];
222 AUDIT_ARG_FD(uap
->fd
);
223 AUDIT_ARG_VALUE(uap
->attrnamespace
);
224 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
227 AUDIT_ARG_TEXT(attrname
);
229 error
= getvnode(td
, uap
->fd
,
230 cap_rights_init(&rights
, CAP_EXTATTR_SET
), &fp
);
234 error
= extattr_set_vp(fp
->f_vnode
, uap
->attrnamespace
,
235 attrname
, uap
->data
, uap
->nbytes
, td
);
242 sys_extattr_set_file(td
, uap
)
244 struct extattr_set_file_args
/* {
247 const char *attrname;
253 char attrname
[EXTATTR_MAXNAMELEN
];
256 AUDIT_ARG_VALUE(uap
->attrnamespace
);
257 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
260 AUDIT_ARG_TEXT(attrname
);
262 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
267 NDFREE(&nd
, NDF_ONLY_PNBUF
);
269 error
= extattr_set_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
270 uap
->data
, uap
->nbytes
, td
);
277 sys_extattr_set_link(td
, uap
)
279 struct extattr_set_link_args
/* {
282 const char *attrname;
288 char attrname
[EXTATTR_MAXNAMELEN
];
291 AUDIT_ARG_VALUE(uap
->attrnamespace
);
292 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
295 AUDIT_ARG_TEXT(attrname
);
297 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
302 NDFREE(&nd
, NDF_ONLY_PNBUF
);
304 error
= extattr_set_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
305 uap
->data
, uap
->nbytes
, td
);
312 * Get a named extended attribute on a file or directory
314 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
315 * kernelspace string pointer "attrname", userspace buffer
316 * pointer "data", buffer length "nbytes", thread "td".
317 * Returns: 0 on success, an error number otherwise
319 * References: vp must be a valid reference for the duration of the call
322 extattr_get_vp(struct vnode
*vp
, int attrnamespace
, const char *attrname
,
323 void *data
, size_t nbytes
, struct thread
*td
)
325 struct uio auio
, *auiop
;
331 vn_lock(vp
, LK_SHARED
| LK_RETRY
);
334 * Slightly unusual semantics: if the user provides a NULL data
335 * pointer, they don't want to receive the data, just the maximum
342 aiov
.iov_base
= data
;
343 aiov
.iov_len
= nbytes
;
344 auio
.uio_iov
= &aiov
;
347 if (nbytes
> IOSIZE_MAX
) {
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
;
382 sys_extattr_get_fd(td
, uap
)
384 struct extattr_get_fd_args
/* {
387 const char *attrname;
393 char attrname
[EXTATTR_MAXNAMELEN
];
397 AUDIT_ARG_FD(uap
->fd
);
398 AUDIT_ARG_VALUE(uap
->attrnamespace
);
399 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
402 AUDIT_ARG_TEXT(attrname
);
404 error
= getvnode(td
, uap
->fd
,
405 cap_rights_init(&rights
, CAP_EXTATTR_GET
), &fp
);
409 error
= extattr_get_vp(fp
->f_vnode
, uap
->attrnamespace
,
410 attrname
, uap
->data
, uap
->nbytes
, td
);
417 sys_extattr_get_file(td
, uap
)
419 struct extattr_get_file_args
/* {
422 const char *attrname;
428 char attrname
[EXTATTR_MAXNAMELEN
];
431 AUDIT_ARG_VALUE(uap
->attrnamespace
);
432 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
435 AUDIT_ARG_TEXT(attrname
);
437 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
, td
);
441 NDFREE(&nd
, NDF_ONLY_PNBUF
);
443 error
= extattr_get_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
444 uap
->data
, uap
->nbytes
, td
);
451 sys_extattr_get_link(td
, uap
)
453 struct extattr_get_link_args
/* {
456 const char *attrname;
462 char attrname
[EXTATTR_MAXNAMELEN
];
465 AUDIT_ARG_VALUE(uap
->attrnamespace
);
466 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
469 AUDIT_ARG_TEXT(attrname
);
471 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
,
476 NDFREE(&nd
, NDF_ONLY_PNBUF
);
478 error
= extattr_get_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
479 uap
->data
, uap
->nbytes
, td
);
486 * extattr_delete_vp(): Delete a named extended attribute on a file or
489 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
490 * kernelspace string pointer "attrname", proc "p"
491 * Returns: 0 on success, an error number otherwise
493 * References: vp must be a valid reference for the duration of the call
496 extattr_delete_vp(struct vnode
*vp
, int attrnamespace
, const char *attrname
,
502 error
= vn_start_write(vp
, &mp
, V_WAIT
| PCATCH
);
505 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
508 error
= mac_vnode_check_deleteextattr(td
->td_ucred
, vp
, attrnamespace
,
514 error
= VOP_DELETEEXTATTR(vp
, attrnamespace
, attrname
, td
->td_ucred
,
516 if (error
== EOPNOTSUPP
)
517 error
= VOP_SETEXTATTR(vp
, attrnamespace
, attrname
, NULL
,
523 vn_finished_write(mp
);
528 sys_extattr_delete_fd(td
, uap
)
530 struct extattr_delete_fd_args
/* {
533 const char *attrname;
537 char attrname
[EXTATTR_MAXNAMELEN
];
541 AUDIT_ARG_FD(uap
->fd
);
542 AUDIT_ARG_VALUE(uap
->attrnamespace
);
543 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
546 AUDIT_ARG_TEXT(attrname
);
548 error
= getvnode(td
, uap
->fd
,
549 cap_rights_init(&rights
, CAP_EXTATTR_DELETE
), &fp
);
553 error
= extattr_delete_vp(fp
->f_vnode
, uap
->attrnamespace
,
560 sys_extattr_delete_file(td
, uap
)
562 struct extattr_delete_file_args
/* {
565 const char *attrname;
569 char attrname
[EXTATTR_MAXNAMELEN
];
572 AUDIT_ARG_VALUE(uap
->attrnamespace
);
573 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
576 AUDIT_ARG_TEXT(attrname
);
578 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
, td
);
582 NDFREE(&nd
, NDF_ONLY_PNBUF
);
584 error
= extattr_delete_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
, td
);
590 sys_extattr_delete_link(td
, uap
)
592 struct extattr_delete_link_args
/* {
595 const char *attrname;
599 char attrname
[EXTATTR_MAXNAMELEN
];
602 AUDIT_ARG_VALUE(uap
->attrnamespace
);
603 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
606 AUDIT_ARG_TEXT(attrname
);
608 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
, td
);
612 NDFREE(&nd
, NDF_ONLY_PNBUF
);
614 error
= extattr_delete_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
, td
);
620 * Retrieve a list of extended attributes on a file or directory.
622 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
623 * userspace buffer pointer "data", buffer length "nbytes",
625 * Returns: 0 on success, an error number otherwise
627 * References: vp must be a valid reference for the duration of the call
630 extattr_list_vp(struct vnode
*vp
, int attrnamespace
, void *data
,
631 size_t nbytes
, struct thread
*td
)
633 struct uio auio
, *auiop
;
639 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
645 aiov
.iov_base
= data
;
646 aiov
.iov_len
= nbytes
;
647 auio
.uio_iov
= &aiov
;
650 if (nbytes
> IOSIZE_MAX
) {
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
;
685 sys_extattr_list_fd(td
, uap
)
687 struct extattr_list_fd_args
/* {
698 AUDIT_ARG_FD(uap
->fd
);
699 AUDIT_ARG_VALUE(uap
->attrnamespace
);
700 error
= getvnode(td
, uap
->fd
,
701 cap_rights_init(&rights
, CAP_EXTATTR_LIST
), &fp
);
705 error
= extattr_list_vp(fp
->f_vnode
, uap
->attrnamespace
, uap
->data
,
713 sys_extattr_list_file(td
, uap
)
715 struct extattr_list_file_args
/* {
725 AUDIT_ARG_VALUE(uap
->attrnamespace
);
726 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
, td
);
730 NDFREE(&nd
, NDF_ONLY_PNBUF
);
732 error
= extattr_list_vp(nd
.ni_vp
, uap
->attrnamespace
, uap
->data
,
740 sys_extattr_list_link(td
, uap
)
742 struct extattr_list_link_args
/* {
752 AUDIT_ARG_VALUE(uap
->attrnamespace
);
753 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
, uap
->path
,
758 NDFREE(&nd
, NDF_ONLY_PNBUF
);
760 error
= extattr_list_vp(nd
.ni_vp
, uap
->attrnamespace
, uap
->data
,