Date: Wed, 01 Jul 2026 08:44:07 +0000 From: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: YAO, Xin <mr.yaoxin@outlook.com> Subject: git: 2c905456312b - main - linuxulator: Fix O_PATH file descriptors errno for f*xattr(2) Message-ID: <6a44d357.392d0.4b7213ca@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=2c905456312b2e5986afe3402a9c87d49eb9cf86 commit 2c905456312b2e5986afe3402a9c87d49eb9cf86 Author: YAO, Xin <mr.yaoxin@outlook.com> AuthorDate: 2026-05-07 06:39:16 +0000 Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> CommitDate: 2026-07-01 08:38:05 +0000 linuxulator: Fix O_PATH file descriptors errno for f*xattr(2) LTP open13 expects these operations to fail with EBADF, matching Linux behavior, but FreeBSD currently returns EOPNOTSUPP for fgetxattr() on an O_PATH fd Look up Linux fd-based xattr descriptors with getvnode() and route the operations through shared kern_extattr_*_fp() helpers so the O_PATH check and the extattr operation use the same referenced file. Apply the same EBADF handling to fsetxattr(), fremovexattr(), and flistxattr() so the xattr paths stay consistent. Signed-off-by: YAO, Xin <mr.yaoxin@outlook.com> PR: 295537 Reviewed by: kib Pull Request: https://github.com/freebsd/freebsd-src/pull/2263 --- sys/compat/linux/linux_xattr.c | 81 ++++++++++++++++++++++++++++++++++++------ sys/kern/vfs_extattr.c | 47 ++++++++++++++++++++---- sys/sys/syscallsubr.h | 10 ++++++ 3 files changed, 121 insertions(+), 17 deletions(-) diff --git a/sys/compat/linux/linux_xattr.c b/sys/compat/linux/linux_xattr.c index 2eec33f8ef93..70e4c3a1d3db 100644 --- a/sys/compat/linux/linux_xattr.c +++ b/sys/compat/linux/linux_xattr.c @@ -26,8 +26,10 @@ */ #include <sys/param.h> +#include <sys/capsicum.h> #include <sys/extattr.h> #include <sys/fcntl.h> +#include <sys/file.h> #include <sys/namei.h> #include <sys/proc.h> #include <sys/syscallsubr.h> @@ -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,17 +338,30 @@ 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); + +out_err: + if (fp != NULL) + fdrop(fp, td); return (error == EPERM ? ENOATTR : error); } @@ -373,14 +414,28 @@ 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) { + if ((args->flags & LINUX_XATTR_FLAGS) != 0) + cap_rights_init(&rights, CAP_EXTATTR_GET, CAP_EXTATTR_SET); + else + cap_rights_init_one(&rights, CAP_EXTATTR_SET); + error = getvnode(td, args->fd, &rights, &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 +443,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 +459,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 1fe7494f3998..01bfe343a1e4 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 0eb471cc9dde..c6bfe89dcf35 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -139,21 +139,31 @@ int kern_execve(struct thread *td, struct image_args *args, void kern_exit(struct thread *, int, int); 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);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a44d357.392d0.4b7213ca>
