aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_xattr.c
diff options
context:
space:
mode:
authorYAO, Xin <mr.yaoxin@outlook.com>2026-05-07 06:39:16 +0000
committerPouria Mousavizadeh Tehrani <pouria@FreeBSD.org>2026-07-01 08:38:05 +0000
commit2c905456312b2e5986afe3402a9c87d49eb9cf86 (patch)
tree625908392850186f6019a3aaf6650ba8508f1927 /sys/compat/linux/linux_xattr.c
parentc9991e01149b5cd5a6710d70921b203ef7f16fc2 (diff)
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
Diffstat (limited to 'sys/compat/linux/linux_xattr.c')
-rw-r--r--sys/compat/linux/linux_xattr.c81
1 files changed, 71 insertions, 10 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