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$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/mount.h>
38 #include <sys/mutex.h>
39 #include <sys/sysproto.h>
40 #include <sys/fcntl.h>
41 #include <sys/namei.h>
42 #include <sys/filedesc.h>
43 #include <sys/limits.h>
44 #include <sys/vnode.h>
46 #include <sys/extattr.h>
48 #include <security/audit/audit.h>
49 #include <security/mac/mac_framework.h>
52 * Syscall to push extended attribute configuration information into the VFS.
53 * Accepts a path, which it converts to a mountpoint, as well as a command
54 * (int cmd), and attribute name and misc data.
56 * Currently this is used only by UFS1 extended attributes.
61 struct extattrctl_args
/* {
69 struct vnode
*filename_vp
;
71 struct mount
*mp
, *mp_writable
;
72 char attrname
[EXTATTR_MAXNAMELEN
];
73 int vfslocked
, fnvfslocked
, error
;
75 AUDIT_ARG(cmd
, uap
->cmd
);
76 AUDIT_ARG(value
, uap
->attrnamespace
);
78 * uap->attrname is not always defined. We check again later when we
79 * invoke the VFS call so as to pass in NULL there if needed.
81 if (uap
->attrname
!= NULL
) {
82 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
,
87 AUDIT_ARG(text
, attrname
);
89 vfslocked
= fnvfslocked
= 0;
91 * uap->filename is not always defined. If it is, grab a vnode lock,
92 * which VFS_EXTATTRCTL() will later release.
95 if (uap
->filename
!= NULL
) {
96 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| LOCKLEAF
|
97 AUDITVNODE2
, UIO_USERSPACE
, uap
->filename
, td
);
101 fnvfslocked
= NDHASGIANT(&nd
);
102 filename_vp
= nd
.ni_vp
;
103 NDFREE(&nd
, NDF_NO_VP_RELE
| NDF_NO_VP_UNLOCK
);
106 /* uap->path is always defined. */
107 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
111 if (filename_vp
!= NULL
)
115 vfslocked
= NDHASGIANT(&nd
);
116 mp
= nd
.ni_vp
->v_mount
;
117 error
= vn_start_write(nd
.ni_vp
, &mp_writable
, V_WAIT
| PCATCH
);
120 if (filename_vp
!= NULL
)
125 error
= VFS_EXTATTRCTL(mp
, uap
->cmd
, filename_vp
, uap
->attrnamespace
,
126 uap
->attrname
!= NULL
? attrname
: NULL
, td
);
128 vn_finished_write(mp_writable
);
130 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
131 * so vrele it if it is defined.
133 if (filename_vp
!= NULL
)
136 VFS_UNLOCK_GIANT(fnvfslocked
);
137 VFS_UNLOCK_GIANT(vfslocked
);
142 * Set a named extended attribute on a file or directory
144 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
145 * kernelspace string pointer "attrname", userspace buffer
146 * pointer "data", buffer length "nbytes", thread "td".
147 * Returns: 0 on success, an error number otherwise
149 * References: vp must be a valid reference for the duration of the call
152 extattr_set_vp(struct vnode
*vp
, int attrnamespace
, const char *attrname
,
153 void *data
, size_t nbytes
, struct thread
*td
)
161 VFS_ASSERT_GIANT(vp
->v_mount
);
162 error
= vn_start_write(vp
, &mp
, V_WAIT
| PCATCH
);
165 VOP_LEASE(vp
, td
, td
->td_ucred
, LEASE_WRITE
);
166 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
168 aiov
.iov_base
= data
;
169 aiov
.iov_len
= nbytes
;
170 auio
.uio_iov
= &aiov
;
173 if (nbytes
> INT_MAX
) {
177 auio
.uio_resid
= nbytes
;
178 auio
.uio_rw
= UIO_WRITE
;
179 auio
.uio_segflg
= UIO_USERSPACE
;
184 error
= mac_vnode_check_setextattr(td
->td_ucred
, vp
, attrnamespace
,
190 error
= VOP_SETEXTATTR(vp
, attrnamespace
, attrname
, &auio
,
192 cnt
-= auio
.uio_resid
;
193 td
->td_retval
[0] = cnt
;
197 vn_finished_write(mp
);
202 extattr_set_fd(td
, uap
)
204 struct extattr_set_fd_args
/* {
207 const char *attrname;
213 char attrname
[EXTATTR_MAXNAMELEN
];
214 int vfslocked
, error
;
216 AUDIT_ARG(fd
, uap
->fd
);
217 AUDIT_ARG(value
, uap
->attrnamespace
);
218 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
221 AUDIT_ARG(text
, attrname
);
223 error
= getvnode(td
->td_proc
->p_fd
, uap
->fd
, &fp
);
227 vfslocked
= VFS_LOCK_GIANT(fp
->f_vnode
->v_mount
);
228 error
= extattr_set_vp(fp
->f_vnode
, uap
->attrnamespace
,
229 attrname
, uap
->data
, uap
->nbytes
, td
);
231 VFS_UNLOCK_GIANT(vfslocked
);
237 extattr_set_file(td
, uap
)
239 struct extattr_set_file_args
/* {
242 const char *attrname;
248 char attrname
[EXTATTR_MAXNAMELEN
];
249 int vfslocked
, error
;
251 AUDIT_ARG(value
, uap
->attrnamespace
);
252 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
255 AUDIT_ARG(text
, attrname
);
257 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
262 NDFREE(&nd
, NDF_ONLY_PNBUF
);
264 vfslocked
= NDHASGIANT(&nd
);
265 error
= extattr_set_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
266 uap
->data
, uap
->nbytes
, td
);
269 VFS_UNLOCK_GIANT(vfslocked
);
274 extattr_set_link(td
, uap
)
276 struct extattr_set_link_args
/* {
279 const char *attrname;
285 char attrname
[EXTATTR_MAXNAMELEN
];
286 int vfslocked
, error
;
288 AUDIT_ARG(value
, uap
->attrnamespace
);
289 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
292 AUDIT_ARG(text
, attrname
);
294 NDINIT(&nd
, LOOKUP
, MPSAFE
| NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
299 NDFREE(&nd
, NDF_ONLY_PNBUF
);
301 vfslocked
= NDHASGIANT(&nd
);
302 error
= extattr_set_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
303 uap
->data
, uap
->nbytes
, td
);
306 VFS_UNLOCK_GIANT(vfslocked
);
311 * Get a named extended attribute on a file or directory
313 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
314 * kernelspace string pointer "attrname", userspace buffer
315 * pointer "data", buffer length "nbytes", thread "td".
316 * Returns: 0 on success, an error number otherwise
318 * References: vp must be a valid reference for the duration of the call
321 extattr_get_vp(struct vnode
*vp
, int attrnamespace
, const char *attrname
,
322 void *data
, size_t nbytes
, struct thread
*td
)
324 struct uio auio
, *auiop
;
330 VFS_ASSERT_GIANT(vp
->v_mount
);
331 VOP_LEASE(vp
, td
, td
->td_ucred
, LEASE_READ
);
332 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
335 * Slightly unusual semantics: if the user provides a NULL data
336 * pointer, they don't want to receive the data, just the maximum
343 aiov
.iov_base
= data
;
344 aiov
.iov_len
= nbytes
;
345 auio
.uio_iov
= &aiov
;
348 if (nbytes
> INT_MAX
) {
352 auio
.uio_resid
= nbytes
;
353 auio
.uio_rw
= UIO_READ
;
354 auio
.uio_segflg
= UIO_USERSPACE
;
362 error
= mac_vnode_check_getextattr(td
->td_ucred
, vp
, attrnamespace
,
368 error
= VOP_GETEXTATTR(vp
, attrnamespace
, attrname
, auiop
, sizep
,
372 cnt
-= auio
.uio_resid
;
373 td
->td_retval
[0] = cnt
;
375 td
->td_retval
[0] = size
;
383 extattr_get_fd(td
, uap
)
385 struct extattr_get_fd_args
/* {
388 const char *attrname;
394 char attrname
[EXTATTR_MAXNAMELEN
];
395 int vfslocked
, error
;
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
->td_proc
->p_fd
, uap
->fd
, &fp
);
408 vfslocked
= VFS_LOCK_GIANT(fp
->f_vnode
->v_mount
);
409 error
= extattr_get_vp(fp
->f_vnode
, uap
->attrnamespace
,
410 attrname
, uap
->data
, uap
->nbytes
, td
);
413 VFS_UNLOCK_GIANT(vfslocked
);
418 extattr_get_file(td
, uap
)
420 struct extattr_get_file_args
/* {
423 const char *attrname;
429 char attrname
[EXTATTR_MAXNAMELEN
];
430 int vfslocked
, error
;
432 AUDIT_ARG(value
, uap
->attrnamespace
);
433 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
436 AUDIT_ARG(text
, attrname
);
438 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
443 NDFREE(&nd
, NDF_ONLY_PNBUF
);
445 vfslocked
= NDHASGIANT(&nd
);
446 error
= extattr_get_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
447 uap
->data
, uap
->nbytes
, td
);
450 VFS_UNLOCK_GIANT(vfslocked
);
455 extattr_get_link(td
, uap
)
457 struct extattr_get_link_args
/* {
460 const char *attrname;
466 char attrname
[EXTATTR_MAXNAMELEN
];
467 int vfslocked
, error
;
469 AUDIT_ARG(value
, uap
->attrnamespace
);
470 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
473 AUDIT_ARG(text
, attrname
);
475 NDINIT(&nd
, LOOKUP
, MPSAFE
| NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
480 NDFREE(&nd
, NDF_ONLY_PNBUF
);
482 vfslocked
= NDHASGIANT(&nd
);
483 error
= extattr_get_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
,
484 uap
->data
, uap
->nbytes
, td
);
487 VFS_UNLOCK_GIANT(vfslocked
);
492 * extattr_delete_vp(): Delete a named extended attribute on a file or
495 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
496 * kernelspace string pointer "attrname", proc "p"
497 * Returns: 0 on success, an error number otherwise
499 * References: vp must be a valid reference for the duration of the call
502 extattr_delete_vp(struct vnode
*vp
, int attrnamespace
, const char *attrname
,
508 VFS_ASSERT_GIANT(vp
->v_mount
);
509 error
= vn_start_write(vp
, &mp
, V_WAIT
| PCATCH
);
512 VOP_LEASE(vp
, td
, td
->td_ucred
, LEASE_WRITE
);
513 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
516 error
= mac_vnode_check_deleteextattr(td
->td_ucred
, vp
, attrnamespace
,
522 error
= VOP_DELETEEXTATTR(vp
, attrnamespace
, attrname
, td
->td_ucred
,
524 if (error
== EOPNOTSUPP
)
525 error
= VOP_SETEXTATTR(vp
, attrnamespace
, attrname
, NULL
,
531 vn_finished_write(mp
);
536 extattr_delete_fd(td
, uap
)
538 struct extattr_delete_fd_args
/* {
541 const char *attrname;
545 char attrname
[EXTATTR_MAXNAMELEN
];
546 int vfslocked
, error
;
548 AUDIT_ARG(fd
, uap
->fd
);
549 AUDIT_ARG(value
, uap
->attrnamespace
);
550 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
553 AUDIT_ARG(text
, attrname
);
555 error
= getvnode(td
->td_proc
->p_fd
, uap
->fd
, &fp
);
559 vfslocked
= VFS_LOCK_GIANT(fp
->f_vnode
->v_mount
);
560 error
= extattr_delete_vp(fp
->f_vnode
, uap
->attrnamespace
,
563 VFS_UNLOCK_GIANT(vfslocked
);
568 extattr_delete_file(td
, uap
)
570 struct extattr_delete_file_args
/* {
573 const char *attrname;
577 char attrname
[EXTATTR_MAXNAMELEN
];
578 int vfslocked
, error
;
580 AUDIT_ARG(value
, uap
->attrnamespace
);
581 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
584 AUDIT_ARG(text
, attrname
);
586 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
591 NDFREE(&nd
, NDF_ONLY_PNBUF
);
593 vfslocked
= NDHASGIANT(&nd
);
594 error
= extattr_delete_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
, td
);
596 VFS_UNLOCK_GIANT(vfslocked
);
601 extattr_delete_link(td
, uap
)
603 struct extattr_delete_link_args
/* {
606 const char *attrname;
610 char attrname
[EXTATTR_MAXNAMELEN
];
611 int vfslocked
, error
;
613 AUDIT_ARG(value
, uap
->attrnamespace
);
614 error
= copyinstr(uap
->attrname
, attrname
, EXTATTR_MAXNAMELEN
, NULL
);
617 AUDIT_ARG(text
, attrname
);
619 NDINIT(&nd
, LOOKUP
, MPSAFE
| NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
624 NDFREE(&nd
, NDF_ONLY_PNBUF
);
626 vfslocked
= NDHASGIANT(&nd
);
627 error
= extattr_delete_vp(nd
.ni_vp
, uap
->attrnamespace
, attrname
, td
);
629 VFS_UNLOCK_GIANT(vfslocked
);
634 * Retrieve a list of extended attributes on a file or directory.
636 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
637 * userspace buffer pointer "data", buffer length "nbytes",
639 * Returns: 0 on success, an error number otherwise
641 * References: vp must be a valid reference for the duration of the call
644 extattr_list_vp(struct vnode
*vp
, int attrnamespace
, void *data
,
645 size_t nbytes
, struct thread
*td
)
647 struct uio auio
, *auiop
;
653 VFS_ASSERT_GIANT(vp
->v_mount
);
654 VOP_LEASE(vp
, td
, td
->td_ucred
, LEASE_READ
);
655 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
661 aiov
.iov_base
= data
;
662 aiov
.iov_len
= nbytes
;
663 auio
.uio_iov
= &aiov
;
666 if (nbytes
> INT_MAX
) {
670 auio
.uio_resid
= nbytes
;
671 auio
.uio_rw
= UIO_READ
;
672 auio
.uio_segflg
= UIO_USERSPACE
;
680 error
= mac_vnode_check_listextattr(td
->td_ucred
, vp
, attrnamespace
);
685 error
= VOP_LISTEXTATTR(vp
, attrnamespace
, auiop
, sizep
,
689 cnt
-= auio
.uio_resid
;
690 td
->td_retval
[0] = cnt
;
692 td
->td_retval
[0] = size
;
701 extattr_list_fd(td
, uap
)
703 struct extattr_list_fd_args
/* {
711 int vfslocked
, error
;
713 AUDIT_ARG(fd
, uap
->fd
);
714 AUDIT_ARG(value
, uap
->attrnamespace
);
715 error
= getvnode(td
->td_proc
->p_fd
, uap
->fd
, &fp
);
719 vfslocked
= VFS_LOCK_GIANT(fp
->f_vnode
->v_mount
);
720 error
= extattr_list_vp(fp
->f_vnode
, uap
->attrnamespace
, uap
->data
,
724 VFS_UNLOCK_GIANT(vfslocked
);
729 extattr_list_file(td
, uap
)
731 struct extattr_list_file_args
/* {
739 int vfslocked
, error
;
741 AUDIT_ARG(value
, uap
->attrnamespace
);
742 NDINIT(&nd
, LOOKUP
, MPSAFE
| FOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
747 NDFREE(&nd
, NDF_ONLY_PNBUF
);
749 vfslocked
= NDHASGIANT(&nd
);
750 error
= extattr_list_vp(nd
.ni_vp
, uap
->attrnamespace
, uap
->data
,
754 VFS_UNLOCK_GIANT(vfslocked
);
759 extattr_list_link(td
, uap
)
761 struct extattr_list_link_args
/* {
769 int vfslocked
, error
;
771 AUDIT_ARG(value
, uap
->attrnamespace
);
772 NDINIT(&nd
, LOOKUP
, MPSAFE
| NOFOLLOW
| AUDITVNODE1
, UIO_USERSPACE
,
777 NDFREE(&nd
, NDF_ONLY_PNBUF
);
779 vfslocked
= NDHASGIANT(&nd
);
780 error
= extattr_list_vp(nd
.ni_vp
, uap
->attrnamespace
, uap
->data
,
784 VFS_UNLOCK_GIANT(vfslocked
);