29 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capability.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>
60 struct extattrctl_args
68 struct vnode *filename_vp;
70 struct mount *mp, *mp_writable;
71 char attrname[EXTATTR_MAXNAMELEN];
72 int vfslocked, fnvfslocked, error;
74 AUDIT_ARG_CMD(uap->cmd);
75 AUDIT_ARG_VALUE(uap->attrnamespace);
80 if (uap->attrname != NULL) {
81 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
86 AUDIT_ARG_TEXT(attrname);
88 vfslocked = fnvfslocked = 0;
91 if (uap->filename != NULL) {
92 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE2,
93 UIO_USERSPACE, uap->filename, td);
97 fnvfslocked = NDHASGIANT(&nd);
98 filename_vp = nd.ni_vp;
99 NDFREE(&nd, NDF_NO_VP_RELE);
103 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | AUDITVNODE1,
104 UIO_USERSPACE, uap->path, td);
108 vfslocked = NDHASGIANT(&nd);
109 mp = nd.ni_vp->v_mount;
116 VOP_UNLOCK(nd.ni_vp, 0);
118 NDFREE(&nd, NDF_NO_VP_UNLOCK);
121 if (filename_vp != NULL) {
127 error = vn_lock(filename_vp, LK_EXCLUSIVE);
134 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
135 uap->attrname != NULL ? attrname : NULL);
146 if (filename_vp != NULL)
148 VFS_UNLOCK_GIANT(fnvfslocked);
149 VFS_UNLOCK_GIANT(vfslocked);
165 void *data,
size_t nbytes,
struct thread *td)
173 VFS_ASSERT_GIANT(vp->v_mount);
177 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
179 aiov.iov_base = data;
180 aiov.iov_len = nbytes;
181 auio.uio_iov = &aiov;
184 if (nbytes > IOSIZE_MAX) {
188 auio.uio_resid = nbytes;
189 auio.uio_rw = UIO_WRITE;
190 auio.uio_segflg = UIO_USERSPACE;
195 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
201 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
203 cnt -= auio.uio_resid;
204 td->td_retval[0] = cnt;
215 struct extattr_set_fd_args
224 char attrname[EXTATTR_MAXNAMELEN];
225 int vfslocked, error;
227 AUDIT_ARG_FD(uap->fd);
228 AUDIT_ARG_VALUE(uap->attrnamespace);
229 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
232 AUDIT_ARG_TEXT(attrname);
234 error =
getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp);
238 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
240 attrname, uap->data, uap->nbytes, td);
242 VFS_UNLOCK_GIANT(vfslocked);
250 struct extattr_set_file_args
259 char attrname[EXTATTR_MAXNAMELEN];
260 int vfslocked, error;
262 AUDIT_ARG_VALUE(uap->attrnamespace);
263 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
266 AUDIT_ARG_TEXT(attrname);
268 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
273 NDFREE(&nd, NDF_ONLY_PNBUF);
275 vfslocked = NDHASGIANT(&nd);
277 uap->data, uap->nbytes, td);
280 VFS_UNLOCK_GIANT(vfslocked);
287 struct extattr_set_link_args
296 char attrname[EXTATTR_MAXNAMELEN];
297 int vfslocked, error;
299 AUDIT_ARG_VALUE(uap->attrnamespace);
300 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
303 AUDIT_ARG_TEXT(attrname);
305 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
310 NDFREE(&nd, NDF_ONLY_PNBUF);
312 vfslocked = NDHASGIANT(&nd);
314 uap->data, uap->nbytes, td);
317 VFS_UNLOCK_GIANT(vfslocked);
333 void *data,
size_t nbytes,
struct thread *td)
335 struct uio auio, *auiop;
341 VFS_ASSERT_GIANT(vp->v_mount);
342 vn_lock(vp, LK_SHARED | LK_RETRY);
353 aiov.iov_base = data;
354 aiov.iov_len = nbytes;
355 auio.uio_iov = &aiov;
358 if (nbytes > IOSIZE_MAX) {
362 auio.uio_resid = nbytes;
363 auio.uio_rw = UIO_READ;
364 auio.uio_segflg = UIO_USERSPACE;
372 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
378 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
382 cnt -= auio.uio_resid;
383 td->td_retval[0] = cnt;
385 td->td_retval[0] = size;
395 struct extattr_get_fd_args
404 char attrname[EXTATTR_MAXNAMELEN];
405 int vfslocked, error;
407 AUDIT_ARG_FD(uap->fd);
408 AUDIT_ARG_VALUE(uap->attrnamespace);
409 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
412 AUDIT_ARG_TEXT(attrname);
414 error =
getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp);
418 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
420 attrname, uap->data, uap->nbytes, td);
423 VFS_UNLOCK_GIANT(vfslocked);
430 struct extattr_get_file_args
439 char attrname[EXTATTR_MAXNAMELEN];
440 int vfslocked, error;
442 AUDIT_ARG_VALUE(uap->attrnamespace);
443 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
446 AUDIT_ARG_TEXT(attrname);
448 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
453 NDFREE(&nd, NDF_ONLY_PNBUF);
455 vfslocked = NDHASGIANT(&nd);
457 uap->data, uap->nbytes, td);
460 VFS_UNLOCK_GIANT(vfslocked);
467 struct extattr_get_link_args
476 char attrname[EXTATTR_MAXNAMELEN];
477 int vfslocked, error;
479 AUDIT_ARG_VALUE(uap->attrnamespace);
480 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
483 AUDIT_ARG_TEXT(attrname);
485 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
490 NDFREE(&nd, NDF_ONLY_PNBUF);
492 vfslocked = NDHASGIANT(&nd);
494 uap->data, uap->nbytes, td);
497 VFS_UNLOCK_GIANT(vfslocked);
518 VFS_ASSERT_GIANT(vp->v_mount);
522 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
525 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
531 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
533 if (error == EOPNOTSUPP)
534 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
547 struct extattr_delete_fd_args
554 char attrname[EXTATTR_MAXNAMELEN];
555 int vfslocked, error;
557 AUDIT_ARG_FD(uap->fd);
558 AUDIT_ARG_VALUE(uap->attrnamespace);
559 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
562 AUDIT_ARG_TEXT(attrname);
564 error =
getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE,
569 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
573 VFS_UNLOCK_GIANT(vfslocked);
580 struct extattr_delete_file_args
587 char attrname[EXTATTR_MAXNAMELEN];
588 int vfslocked, error;
590 AUDIT_ARG_VALUE(uap->attrnamespace);
591 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
594 AUDIT_ARG_TEXT(attrname);
596 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
601 NDFREE(&nd, NDF_ONLY_PNBUF);
603 vfslocked = NDHASGIANT(&nd);
606 VFS_UNLOCK_GIANT(vfslocked);
613 struct extattr_delete_link_args
620 char attrname[EXTATTR_MAXNAMELEN];
621 int vfslocked, error;
623 AUDIT_ARG_VALUE(uap->attrnamespace);
624 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
627 AUDIT_ARG_TEXT(attrname);
629 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
634 NDFREE(&nd, NDF_ONLY_PNBUF);
636 vfslocked = NDHASGIANT(&nd);
639 VFS_UNLOCK_GIANT(vfslocked);
655 size_t nbytes,
struct thread *td)
657 struct uio auio, *auiop;
663 VFS_ASSERT_GIANT(vp->v_mount);
664 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
670 aiov.iov_base = data;
671 aiov.iov_len = nbytes;
672 auio.uio_iov = &aiov;
675 if (nbytes > IOSIZE_MAX) {
679 auio.uio_resid = nbytes;
680 auio.uio_rw = UIO_READ;
681 auio.uio_segflg = UIO_USERSPACE;
689 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
694 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
698 cnt -= auio.uio_resid;
699 td->td_retval[0] = cnt;
701 td->td_retval[0] = size;
712 struct extattr_list_fd_args
720 int vfslocked, error;
722 AUDIT_ARG_FD(uap->fd);
723 AUDIT_ARG_VALUE(uap->attrnamespace);
724 error =
getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp);
728 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
733 VFS_UNLOCK_GIANT(vfslocked);
740 struct extattr_list_file_args
748 int vfslocked, error;
750 AUDIT_ARG_VALUE(uap->attrnamespace);
751 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
756 NDFREE(&nd, NDF_ONLY_PNBUF);
758 vfslocked = NDHASGIANT(&nd);
763 VFS_UNLOCK_GIANT(vfslocked);
770 struct extattr_list_link_args
778 int vfslocked, error;
780 AUDIT_ARG_VALUE(uap->attrnamespace);
781 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
786 NDFREE(&nd, NDF_ONLY_PNBUF);
788 vfslocked = NDHASGIANT(&nd);
793 VFS_UNLOCK_GIANT(vfslocked);
int getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, struct file **fpp)
void NDFREE(struct nameidata *ndp, const u_int flags)
int sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap)
int sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap)
void vn_finished_write(struct mount *mp)
int sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap)
int sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap)
int sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap)
int sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap)
int sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap)
int sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap)
static int extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, struct thread *td)
void vfs_unbusy(struct mount *mp)
int namei(struct nameidata *ndp)
static int extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, void *data, size_t nbytes, struct thread *td)
int sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap)
int sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap)
int sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap)
static int extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, void *data, size_t nbytes, struct thread *td)
int vfs_busy(struct mount *mp, int flags)
void vrele(struct vnode *vp)
int vn_start_write(struct vnode *vp, struct mount **mpp, int flags)
static int extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes, struct thread *td)
int sys_extattrctl(struct thread *td, struct extattrctl_args *uap)
int sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap)