diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -49,15 +49,15 @@ #include #include -static int kern_extattr_set_path(struct thread *td, const char *path, +static int user_extattr_set_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes, int follow); -static int kern_extattr_get_path(struct thread *td, const char *path, +static int user_extattr_get_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes, int follow); -static int kern_extattr_delete_path(struct thread *td, const char *path, +static int user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, const char *attrname, int follow); -static int kern_extattr_list_path(struct thread *td, const char *path, +static int user_extattr_list_path(struct thread *td, const char *path, int attrnamespace, void *data, size_t nbytes, int follow); /* @@ -232,25 +232,35 @@ int sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap) { - struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; - cap_rights_t rights; int error; - AUDIT_ARG_FD(uap->fd); - AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); + return (kern_extattr_set_fd(td, uap->fd, uap->attrnamespace, + attrname, uap->data, uap->nbytes)); +} + +int +kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname, void *data, size_t nbytes) +{ + struct file *fp; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - error = getvnode_path(td, uap->fd, + error = getvnode_path(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); if (error) return (error); - error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, - attrname, uap->data, uap->nbytes, td); + error = extattr_set_vp(fp->f_vnode, attrnamespace, + attrname, data, nbytes, td); fdrop(fp, td); return (error); @@ -269,7 +279,7 @@ sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap) { - return (kern_extattr_set_path(td, uap->path, uap->attrnamespace, + return (user_extattr_set_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, FOLLOW)); } @@ -286,25 +296,36 @@ sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap) { - return (kern_extattr_set_path(td, uap->path, uap->attrnamespace, + return (user_extattr_set_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); } static int -kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, +user_extattr_set_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, void *data, size_t nbytes, int follow) { - struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; - AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return (error); + return (kern_extattr_set_path(td, path, attrnamespace, + attrname, data, nbytes, follow, UIO_USERSPACE)); +} + +int +kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, + const char *attrname, void *data, size_t nbytes, int follow, + enum uio_seg pathseg) +{ + struct nameidata nd; + int error; + + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); + NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); error = namei(&nd); if (error) return (error); @@ -399,25 +420,35 @@ int sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap) { - struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; - cap_rights_t rights; int error; - AUDIT_ARG_FD(uap->fd); - AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); + return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace, + attrname, uap->data, uap->nbytes)); +} + +int +kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname, void *data, size_t nbytes) +{ + struct file *fp; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - error = getvnode_path(td, uap->fd, + error = getvnode_path(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp); if (error) return (error); - error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, - attrname, uap->data, uap->nbytes, td); + error = extattr_get_vp(fp->f_vnode, attrnamespace, + attrname, data, nbytes, td); fdrop(fp, td); return (error); @@ -435,7 +466,7 @@ int sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap) { - return (kern_extattr_get_path(td, uap->path, uap->attrnamespace, + return (user_extattr_get_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, FOLLOW)); } @@ -451,25 +482,36 @@ int sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap) { - return (kern_extattr_get_path(td, uap->path, uap->attrnamespace, + return (user_extattr_get_path(td, uap->path, uap->attrnamespace, uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); } static int -kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, +user_extattr_get_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, void *data, size_t nbytes, int follow) { - struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; - AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return (error); + return (kern_extattr_get_path(td, path, attrnamespace, + attrname, data, nbytes, follow, UIO_USERSPACE)); +} + +int +kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, + const char *attrname, void *data, size_t nbytes, int follow, + enum uio_seg pathseg) +{ + struct nameidata nd; + int error; + + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); + NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); error = namei(&nd); if (error) return (error); @@ -534,24 +576,34 @@ int sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap) { - struct file *fp; char attrname[EXTATTR_MAXNAMELEN + 1]; - cap_rights_t rights; int error; - AUDIT_ARG_FD(uap->fd); - AUDIT_ARG_VALUE(uap->attrnamespace); error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); if (error) return (error); + return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace, + attrname)); +} + +int +kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname) +{ + struct file *fp; + cap_rights_t rights; + int error; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - error = getvnode_path(td, uap->fd, + error = getvnode_path(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp); if (error) return (error); - error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace, + error = extattr_delete_vp(fp->f_vnode, attrnamespace, attrname, td); fdrop(fp, td); return (error); @@ -568,7 +620,7 @@ sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap) { - return (kern_extattr_delete_path(td, uap->path, uap->attrnamespace, + return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, uap->attrname, FOLLOW)); } @@ -583,25 +635,35 @@ sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap) { - return (kern_extattr_delete_path(td, uap->path, uap->attrnamespace, + return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, uap->attrname, NOFOLLOW)); } -static int -kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, +int +user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, const char *uattrname, int follow) { - struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN + 1]; int error; - AUDIT_ARG_VALUE(attrnamespace); error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); if (error) return(error); + return (kern_extattr_delete_path(td, path, attrnamespace, + attrname, follow, UIO_USERSPACE)); +} + +int +kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, + const char *attrname, int follow, enum uio_seg pathseg) +{ + struct nameidata nd; + int error; + + AUDIT_ARG_VALUE(attrnamespace); AUDIT_ARG_TEXT(attrname); - NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); + NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); error = namei(&nd); if (error) return(error); @@ -623,33 +685,19 @@ * References: vp must be a valid reference for the duration of the call */ static int -extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, - size_t nbytes, struct thread *td) +extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop, + struct thread *td) { - struct uio auio, *auiop; size_t size, *sizep; - struct iovec aiov; ssize_t cnt; int error; - if (nbytes > IOSIZE_MAX) - return (EINVAL); - - auiop = NULL; sizep = NULL; cnt = 0; - if (data != NULL) { - aiov.iov_base = data; - aiov.iov_len = nbytes; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_resid = nbytes; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; - auiop = &auio; - cnt = nbytes; + if (auiop != NULL) { + if (auiop->uio_resid > IOSIZE_MAX) + return (EINVAL); + cnt = auiop->uio_resid; } else sizep = &size; @@ -668,7 +716,7 @@ VOP_UNLOCK(vp); if (auiop != NULL) { - cnt -= auio.uio_resid; + cnt -= auiop->uio_resid; td->td_retval[0] = cnt; } else td->td_retval[0] = size; @@ -685,20 +733,44 @@ #endif int sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap) +{ + struct uio auio, *auiop; + struct iovec aiov; + + if (uap->data != NULL) { + aiov.iov_base = uap->data; + aiov.iov_len = uap->nbytes; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_resid = uap->nbytes; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + auiop = &auio; + } else + auiop = NULL; + + return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace, + auiop)); +} + +int +kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, + struct uio *auiop) { struct file *fp; cap_rights_t rights; int error; - AUDIT_ARG_FD(uap->fd); - AUDIT_ARG_VALUE(uap->attrnamespace); - error = getvnode_path(td, uap->fd, + AUDIT_ARG_FD(fd); + AUDIT_ARG_VALUE(attrnamespace); + error = getvnode_path(td, fd, cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp); if (error) return (error); - error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, - uap->nbytes, td); + error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td); fdrop(fp, td); return (error); @@ -716,7 +788,7 @@ sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap) { - return (kern_extattr_list_path(td, uap->path, uap->attrnamespace, + return (user_extattr_list_path(td, uap->path, uap->attrnamespace, uap->data, uap->nbytes, FOLLOW)); } @@ -732,25 +804,50 @@ sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap) { - return (kern_extattr_list_path(td, uap->path, uap->attrnamespace, + return (user_extattr_list_path(td, uap->path, uap->attrnamespace, uap->data, uap->nbytes, NOFOLLOW)); } static int -kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, +user_extattr_list_path(struct thread *td, const char *path, int attrnamespace, void *data, size_t nbytes, int follow) +{ + struct uio auio, *auiop; + struct iovec aiov; + + if (data != NULL) { + aiov.iov_base = data; + aiov.iov_len = nbytes; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_resid = nbytes; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + auiop = &auio; + } else + auiop = NULL; + + return (kern_extattr_list_path(td, path, attrnamespace, + auiop, follow, UIO_USERSPACE)); +} + +int +kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, + struct uio *auiop, int follow, enum uio_seg pathseg) { struct nameidata nd; int error; AUDIT_ARG_VALUE(attrnamespace); - NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path); + NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); error = namei(&nd); if (error) return (error); NDFREE_PNBUF(&nd); - error = extattr_list_vp(nd.ni_vp, attrnamespace, data, nbytes, td); + error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td); vrele(nd.ni_vp); return (error); diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h --- a/sys/sys/extattr.h +++ b/sys/sys/extattr.h @@ -64,11 +64,33 @@ #ifdef _KERNEL #include +enum uio_seg; +struct uio; struct thread; struct ucred; struct vnode; int extattr_check_cred(struct vnode *vp, int attrnamespace, struct ucred *cred, struct thread *td, accmode_t accmode); +int kern_extattr_set_path(struct thread *td, const char *path, + int attrnamespace, const char *attrname, void *data, + size_t nbytes, int follow, enum uio_seg pathseg); +int kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname, void *data, size_t nbytes); +int kern_extattr_get_path(struct thread *td, const char *path, + int attrnamespace, const char *attrname, void *data, + size_t nbytes, int follow, enum uio_seg pathseg); +int kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname, void *data, size_t nbytes); +int kern_extattr_delete_path(struct thread *td, const char *path, + int attrnamespace, const char *attrname, int follow, + enum uio_seg pathseg); +int kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, + const char *attrname); +int kern_extattr_list_path(struct thread *td, const char *path, + int attrnamespace, struct uio *auiop, int follow, + enum uio_seg pathseg); +int kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, + struct uio *auiop); #else #include