vfs: Export exattr methods to reuse by Linuxulator

Reviewed by:
Differential revision:	https://reviews.freebsd.org/D35543
MFC after:		1 month
This commit is contained in:
Dmitry Chagin 2023-07-22 14:03:33 +03:00
parent d9c2dc6bf1
commit 6453d4240f
2 changed files with 193 additions and 74 deletions

View file

@ -49,15 +49,15 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
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 @@ struct extattr_set_fd_args {
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 @@ int
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 @@ int
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 @@ struct extattr_get_fd_args {
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 @@ struct extattr_get_file_args {
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 @@ struct extattr_get_link_args {
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 @@ struct extattr_delete_fd_args {
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 @@ int
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 @@ int
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 @@ kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
* 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 @@ extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
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 @@ struct extattr_list_fd_args {
#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 @@ int
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 @@ int
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);

View file

@ -64,11 +64,33 @@
#ifdef _KERNEL
#include <sys/types.h>
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 <sys/cdefs.h>