mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
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 <[email protected]> PR: 295537 Reviewed by: kib Pull Request: https://github.com/freebsd/freebsd-src/pull/2263
This commit is contained in:
1 parent
c9991e0114
commit
2c90545631
3 files changed
+121
-17
No files matched your search
@@ -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
|
||||
|
||||
+40
-7
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user