diff --git a/sys/compat/linux/linux_xattr.c b/sys/compat/linux/linux_xattr.c index 2eec33f8ef93f..533c9b03374a9 100644 --- a/sys/compat/linux/linux_xattr.c +++ b/sys/compat/linux/linux_xattr.c @@ -26,8 +26,10 @@ */ #include +#include #include #include +#include #include #include #include @@ -132,12 +134,21 @@ listxattr(struct thread *td, struct listxattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; char *data, *prefix, *key; + cap_rights_t rights; + struct file *fp = NULL; struct uio auio; struct iovec aiov; unsigned char keylen; size_t sz, cnt, rs, prefixlen, pairlen; int attrnamespace, error; + if (args->path == NULL) { + error = getvnode(td, args->fd, + cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp); + if (error != 0) + return (error); + } + if (args->size != 0) sz = min(LINUX_XATTR_LIST_MAX, args->size); else @@ -162,7 +173,7 @@ listxattr(struct thread *td, struct listxattr_args *args) error = kern_extattr_list_path(td, args->path, attrnamespace, &auio, args->follow, UIO_USERSPACE); else - error = kern_extattr_list_fd(td, args->fd, + error = kern_extattr_list_fp(td, fp, attrnamespace, &auio); rs = sz - auio.uio_resid; if (error == EPERM) @@ -204,6 +215,8 @@ listxattr(struct thread *td, struct listxattr_args *args) if (error == 0) td->td_retval[0] = cnt; free(data, M_LINUX); + if (fp != NULL) + fdrop(fp, td); return (error_to_xattrerror(attrnamespace, error)); } @@ -253,18 +266,33 @@ static int removexattr(struct thread *td, struct removexattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; + struct file *fp = NULL; + cap_rights_t rights; int attrnamespace, error; + if (args->path == NULL) { + error = getvnode(td, args->fd, + cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp); + if (error != 0) + return (error); + } + error = xattr_to_extattr(args->name, &attrnamespace, attrname); if (error != 0) - return (error); + goto out_err; if (args->path != NULL) error = kern_extattr_delete_path(td, args->path, attrnamespace, attrname, args->follow, UIO_USERSPACE); else - error = kern_extattr_delete_fd(td, args->fd, attrnamespace, + error = kern_extattr_delete_fp(td, fp, attrnamespace, attrname); + if (fp != NULL) + fdrop(fp, td); return (error_to_xattrerror(attrnamespace, error)); +out_err: + if (fp != NULL) + fdrop(fp, td); + return (error); } int @@ -310,18 +338,33 @@ static int getxattr(struct thread *td, struct getxattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; + struct file *fp = NULL; + cap_rights_t rights; int attrnamespace, error; + if (args->path == NULL) { + error = getvnode(td, args->fd, + cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp); + if (error != 0) + return (error); + } + error = xattr_to_extattr(args->name, &attrnamespace, attrname); if (error != 0) - return (error); + goto out_err; if (args->path != NULL) error = kern_extattr_get_path(td, args->path, attrnamespace, attrname, args->value, args->size, args->follow, UIO_USERSPACE); else - error = kern_extattr_get_fd(td, args->fd, attrnamespace, + error = kern_extattr_get_fp(td, fp, attrnamespace, attrname, args->value, args->size); + if (fp != NULL) + fdrop(fp, td); return (error == EPERM ? ENOATTR : error); +out_err: + if (fp != NULL) + fdrop(fp, td); + return (error); } int @@ -373,14 +416,25 @@ static int setxattr(struct thread *td, struct setxattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; + struct file *fp = NULL; + cap_rights_t rights; int attrnamespace, error; + if (args->path == NULL) { + error = getvnode(td, args->fd, + cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); + if (error != 0) + return (error); + } + if ((args->flags & ~(LINUX_XATTR_FLAGS)) != 0 || - args->flags == (LINUX_XATTR_FLAGS)) - return (EINVAL); + args->flags == (LINUX_XATTR_FLAGS)) { + error = EINVAL; + goto out_err; + } error = xattr_to_extattr(args->name, &attrnamespace, attrname); if (error != 0) - return (error); + goto out_err; if ((args->flags & (LINUX_XATTR_FLAGS)) != 0 ) { if (args->path != NULL) @@ -388,7 +442,7 @@ setxattr(struct thread *td, struct setxattr_args *args) attrnamespace, attrname, NULL, args->size, args->follow, UIO_USERSPACE); else - error = kern_extattr_get_fd(td, args->fd, + error = kern_extattr_get_fp(td, fp, attrnamespace, attrname, NULL, args->size); if ((args->flags & LINUX_XATTR_CREATE) != 0) { if (error == 0) @@ -404,11 +458,17 @@ setxattr(struct thread *td, struct setxattr_args *args) attrname, args->value, args->size, args->follow, UIO_USERSPACE); else - error = kern_extattr_set_fd(td, args->fd, attrnamespace, + error = kern_extattr_set_fp(td, fp, attrnamespace, attrname, args->value, args->size); out: + if (fp != NULL) + fdrop(fp, td); td->td_retval[0] = 0; return (error_to_xattrerror(attrnamespace, error)); +out_err: + if (fp != NULL) + fdrop(fp, td); + return (error); } int diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 1fe7494f3998e..01bfe343a1e48 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -240,6 +240,15 @@ sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap) attrname, uap->data, uap->nbytes)); } +int +kern_extattr_set_fp(struct thread *td, struct file *fp, int attrnamespace, + const char *attrname, void *data, size_t nbytes) +{ + + return (extattr_set_vp(fp->f_vnode, attrnamespace, attrname, data, + nbytes, td)); +} + int kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes) @@ -257,8 +266,8 @@ kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, if (error) return (error); - error = extattr_set_vp(fp->f_vnode, attrnamespace, - attrname, data, nbytes, td); + error = kern_extattr_set_fp(td, fp, attrnamespace, attrname, data, + nbytes); fdrop(fp, td); return (error); @@ -428,6 +437,15 @@ sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap) attrname, uap->data, uap->nbytes)); } +int +kern_extattr_get_fp(struct thread *td, struct file *fp, int attrnamespace, + const char *attrname, void *data, size_t nbytes) +{ + + return (extattr_get_vp(fp->f_vnode, attrnamespace, attrname, data, + nbytes, td)); +} + int kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes) @@ -445,8 +463,8 @@ kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, if (error) return (error); - error = extattr_get_vp(fp->f_vnode, attrnamespace, - attrname, data, nbytes, td); + error = kern_extattr_get_fp(td, fp, attrnamespace, attrname, data, + nbytes); fdrop(fp, td); return (error); @@ -584,6 +602,14 @@ sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap) attrname)); } +int +kern_extattr_delete_fp(struct thread *td, struct file *fp, int attrnamespace, + const char *attrname) +{ + + return (extattr_delete_vp(fp->f_vnode, attrnamespace, attrname, td)); +} + int kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, const char *attrname) @@ -601,8 +627,7 @@ kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, if (error) return (error); - error = extattr_delete_vp(fp->f_vnode, attrnamespace, - attrname, td); + error = kern_extattr_delete_fp(td, fp, attrnamespace, attrname); fdrop(fp, td); return (error); } @@ -753,6 +778,14 @@ sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap) auiop)); } +int +kern_extattr_list_fp(struct thread *td, struct file *fp, int attrnamespace, + struct uio *auiop) +{ + + return (extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td)); +} + int kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, struct uio *auiop) @@ -768,7 +801,7 @@ kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, if (error) return (error); - error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td); + error = kern_extattr_list_fp(td, fp, attrnamespace, auiop); fdrop(fp, td); return (error); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 8d546428820ee..14d9e1bf21fec 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -138,21 +138,31 @@ int kern_execve(struct thread *td, struct image_args *args, struct mac *mac_p, struct vmspace *oldvmspace); int kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, const char *attrname); +int kern_extattr_delete_fp(struct thread *td, struct file *fp, + int attrnamespace, const char *attrname); 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_get_fd(struct thread *td, int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); +int kern_extattr_get_fp(struct thread *td, struct file *fp, + 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_list_fd(struct thread *td, int fd, int attrnamespace, struct uio *auiop); +int kern_extattr_list_fp(struct thread *td, struct file *fp, + int attrnamespace, struct uio *auiop); 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_set_fd(struct thread *td, int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); +int kern_extattr_set_fp(struct thread *td, struct file *fp, + int attrnamespace, const char *attrname, void *data, + size_t nbytes); 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);