mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 01:43:39 +00:00
virtio-9p: Use layered xattr approach
We would need this to make sure we handle the mapped security model correctly for different xattr names. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
This commit is contained in:
parent
0f8151cb75
commit
fc22118d9b
|
@ -249,7 +249,8 @@ sound-obj-$(CONFIG_CS4231A) += cs4231a.o
|
|||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
|
||||
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
|
||||
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o
|
||||
|
||||
######################################################################
|
||||
# libdis
|
||||
|
|
|
@ -47,11 +47,14 @@ typedef struct FsCred
|
|||
dev_t fc_rdev;
|
||||
} FsCred;
|
||||
|
||||
struct xattr_operations;
|
||||
|
||||
typedef struct FsContext
|
||||
{
|
||||
char *fs_root;
|
||||
SecModel fs_sm;
|
||||
uid_t uid;
|
||||
struct xattr_operations **xops;
|
||||
} FsContext;
|
||||
|
||||
extern void cred_init(FsCred *);
|
||||
|
@ -94,4 +97,12 @@ typedef struct FileOperations
|
|||
int (*lremovexattr)(FsContext *, const char *, const char *);
|
||||
void *opaque;
|
||||
} FileOperations;
|
||||
|
||||
static inline const char *rpath(FsContext *ctx, const char *path)
|
||||
{
|
||||
/* FIXME: so wrong... */
|
||||
static char buffer[4096];
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
#include "virtio.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "virtio-9p-xattr.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
@ -19,14 +20,6 @@
|
|||
#include <sys/un.h>
|
||||
#include <attr/xattr.h>
|
||||
|
||||
static const char *rpath(FsContext *ctx, const char *path)
|
||||
{
|
||||
/* FIXME: so wrong... */
|
||||
static char buffer[4096];
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
|
||||
{
|
||||
|
@ -497,103 +490,25 @@ static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
|
|||
static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
if ((ctx->fs_sm == SM_MAPPED) &&
|
||||
(strncmp(name, "user.virtfs.", 12) == 0)) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return lgetxattr(rpath(ctx, path), name, value, size);
|
||||
return v9fs_get_xattr(ctx, path, name, value, size);
|
||||
}
|
||||
|
||||
static ssize_t local_llistxattr(FsContext *ctx, const char *path,
|
||||
void *value, size_t size)
|
||||
{
|
||||
ssize_t retval;
|
||||
ssize_t actual_len = 0;
|
||||
char *orig_value, *orig_value_start;
|
||||
char *temp_value, *temp_value_start;
|
||||
ssize_t xattr_len, parsed_len = 0, attr_len;
|
||||
|
||||
if (ctx->fs_sm != SM_MAPPED) {
|
||||
return llistxattr(rpath(ctx, path), value, size);
|
||||
}
|
||||
|
||||
/* Get the actual len */
|
||||
xattr_len = llistxattr(rpath(ctx, path), value, 0);
|
||||
|
||||
/* Now fetch the xattr and find the actual size */
|
||||
orig_value = qemu_malloc(xattr_len);
|
||||
xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
|
||||
|
||||
/*
|
||||
* For mapped security model drop user.virtfs namespace
|
||||
* from the list
|
||||
*/
|
||||
temp_value = qemu_mallocz(xattr_len);
|
||||
temp_value_start = temp_value;
|
||||
orig_value_start = orig_value;
|
||||
while (xattr_len > parsed_len) {
|
||||
attr_len = strlen(orig_value) + 1;
|
||||
if (strncmp(orig_value, "user.virtfs.", 12) != 0) {
|
||||
/* Copy this entry */
|
||||
strcat(temp_value, orig_value);
|
||||
temp_value += attr_len;
|
||||
actual_len += attr_len;
|
||||
}
|
||||
parsed_len += attr_len;
|
||||
orig_value += attr_len;
|
||||
}
|
||||
if (!size) {
|
||||
retval = actual_len;
|
||||
goto out;
|
||||
} else if (size >= actual_len) {
|
||||
/* now copy the parsed attribute list back */
|
||||
memset(value, 0, size);
|
||||
memcpy(value, temp_value_start, actual_len);
|
||||
retval = actual_len;
|
||||
goto out;
|
||||
}
|
||||
errno = ERANGE;
|
||||
retval = -1;
|
||||
out:
|
||||
qemu_free(orig_value_start);
|
||||
qemu_free(temp_value_start);
|
||||
return retval;
|
||||
return v9fs_list_xattr(ctx, path, value, size);
|
||||
}
|
||||
|
||||
static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
if ((ctx->fs_sm == SM_MAPPED) &&
|
||||
(strncmp(name, "user.virtfs.", 12) == 0)) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return lsetxattr(rpath(ctx, path), name, value, size, flags);
|
||||
return v9fs_set_xattr(ctx, path, name, value, size, flags);
|
||||
}
|
||||
|
||||
static int local_lremovexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
if ((ctx->fs_sm == SM_MAPPED) &&
|
||||
(strncmp(name, "user.virtfs.", 12) == 0)) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return lremovexattr(rpath(ctx, path), name);
|
||||
return v9fs_remove_xattr(ctx, path, name);
|
||||
}
|
||||
|
||||
|
||||
|
|
101
hw/virtio-9p-xattr-user.c
Normal file
101
hw/virtio-9p-xattr-user.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Virtio 9p user. xattr callback
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "virtio.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "file-op-9p.h"
|
||||
#include "virtio-9p-xattr.h"
|
||||
|
||||
|
||||
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
return lgetxattr(rpath(ctx, path), name, value, size);
|
||||
}
|
||||
|
||||
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||
char *name, void *value, size_t size)
|
||||
{
|
||||
int name_size = strlen(name) + 1;
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (!value) {
|
||||
return name_size;
|
||||
}
|
||||
|
||||
if (size < name_size) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(value, name, name_size);
|
||||
return name_size;
|
||||
}
|
||||
|
||||
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return lsetxattr(rpath(ctx, path), name, value, size, flags);
|
||||
}
|
||||
|
||||
static int mp_user_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||
/*
|
||||
* Don't allow fetch of user.virtfs namesapce
|
||||
* in case of mapped security
|
||||
*/
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return lremovexattr(rpath(ctx, path), name);
|
||||
}
|
||||
|
||||
XattrOperations mapped_user_xattr = {
|
||||
.name = "user.",
|
||||
.getxattr = mp_user_getxattr,
|
||||
.setxattr = mp_user_setxattr,
|
||||
.listxattr = mp_user_listxattr,
|
||||
.removexattr = mp_user_removexattr,
|
||||
};
|
||||
|
||||
XattrOperations passthrough_user_xattr = {
|
||||
.name = "user.",
|
||||
.getxattr = pt_getxattr,
|
||||
.setxattr = pt_setxattr,
|
||||
.listxattr = pt_listxattr,
|
||||
.removexattr = pt_removexattr,
|
||||
};
|
152
hw/virtio-9p-xattr.c
Normal file
152
hw/virtio-9p-xattr.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Virtio 9p xattr callback
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "virtio.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "file-op-9p.h"
|
||||
#include "virtio-9p-xattr.h"
|
||||
|
||||
|
||||
static XattrOperations *get_xattr_operations(XattrOperations **h,
|
||||
const char *name)
|
||||
{
|
||||
XattrOperations *xops;
|
||||
for (xops = *(h)++; xops != NULL; xops = *(h)++) {
|
||||
if (!strncmp(name, xops->name, strlen(xops->name))) {
|
||||
return xops;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
XattrOperations *xops = get_xattr_operations(ctx->xops, name);
|
||||
if (xops) {
|
||||
return xops->getxattr(ctx, path, name, value, size);
|
||||
}
|
||||
errno = -EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t pt_listxattr(FsContext *ctx, const char *path,
|
||||
char *name, void *value, size_t size)
|
||||
{
|
||||
int name_size = strlen(name) + 1;
|
||||
if (!value) {
|
||||
return name_size;
|
||||
}
|
||||
|
||||
if (size < name_size) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(value, name, name_size);
|
||||
return name_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the list and pass to each layer to find out whether
|
||||
* to send the data or not
|
||||
*/
|
||||
ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
||||
void *value, size_t vsize)
|
||||
{
|
||||
ssize_t size = 0;
|
||||
void *ovalue = value;
|
||||
XattrOperations *xops;
|
||||
char *orig_value, *orig_value_start;
|
||||
ssize_t xattr_len, parsed_len = 0, attr_len;
|
||||
|
||||
/* Get the actual len */
|
||||
xattr_len = llistxattr(rpath(ctx, path), value, 0);
|
||||
|
||||
/* Now fetch the xattr and find the actual size */
|
||||
orig_value = qemu_malloc(xattr_len);
|
||||
xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
|
||||
|
||||
/* store the orig pointer */
|
||||
orig_value_start = orig_value;
|
||||
while (xattr_len > parsed_len) {
|
||||
xops = get_xattr_operations(ctx->xops, orig_value);
|
||||
if (!xops) {
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
size += xops->listxattr(ctx, path, orig_value, value, vsize);
|
||||
} else {
|
||||
size = xops->listxattr(ctx, path, orig_value, value, vsize);
|
||||
if (size < 0) {
|
||||
goto err_out;
|
||||
}
|
||||
value += size;
|
||||
vsize -= size;
|
||||
}
|
||||
next_entry:
|
||||
/* Got the next entry */
|
||||
attr_len = strlen(orig_value) + 1;
|
||||
parsed_len += attr_len;
|
||||
orig_value += attr_len;
|
||||
}
|
||||
if (value) {
|
||||
size = value - ovalue;
|
||||
}
|
||||
|
||||
err_out:
|
||||
qemu_free(orig_value_start);
|
||||
return size;
|
||||
}
|
||||
|
||||
int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags)
|
||||
{
|
||||
XattrOperations *xops = get_xattr_operations(ctx->xops, name);
|
||||
if (xops) {
|
||||
return xops->setxattr(ctx, path, name, value, size, flags);
|
||||
}
|
||||
errno = -EOPNOTSUPP;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int v9fs_remove_xattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
XattrOperations *xops = get_xattr_operations(ctx->xops, name);
|
||||
if (xops) {
|
||||
return xops->removexattr(ctx, path, name);
|
||||
}
|
||||
errno = -EOPNOTSUPP;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
XattrOperations *mapped_xattr_ops[] = {
|
||||
&mapped_user_xattr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
XattrOperations *passthrough_xattr_ops[] = {
|
||||
&passthrough_user_xattr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* for .user none model should be same as passthrough */
|
||||
XattrOperations *none_xattr_ops[] = {
|
||||
&passthrough_user_xattr,
|
||||
NULL,
|
||||
};
|
69
hw/virtio-9p-xattr.h
Normal file
69
hw/virtio-9p-xattr.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Virtio 9p
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#ifndef _QEMU_VIRTIO_9P_XATTR_H
|
||||
#define _QEMU_VIRTIO_9P_XATTR_H
|
||||
|
||||
#include <attr/xattr.h>
|
||||
|
||||
typedef struct xattr_operations
|
||||
{
|
||||
const char *name;
|
||||
ssize_t (*getxattr)(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size);
|
||||
ssize_t (*listxattr)(FsContext *ctx, const char *path,
|
||||
char *name, void *value, size_t size);
|
||||
int (*setxattr)(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags);
|
||||
int (*removexattr)(FsContext *ctx,
|
||||
const char *path, const char *name);
|
||||
} XattrOperations;
|
||||
|
||||
|
||||
extern XattrOperations mapped_user_xattr;
|
||||
extern XattrOperations passthrough_user_xattr;
|
||||
|
||||
extern XattrOperations *mapped_xattr_ops[];
|
||||
extern XattrOperations *passthrough_xattr_ops[];
|
||||
extern XattrOperations *none_xattr_ops[];
|
||||
|
||||
extern ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size);
|
||||
extern ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
||||
void *value, size_t vsize);
|
||||
extern int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
|
||||
void *value, size_t size, int flags);
|
||||
extern int v9fs_remove_xattr(FsContext *ctx,
|
||||
const char *path, const char *name);
|
||||
extern ssize_t pt_listxattr(FsContext *ctx, const char *path,
|
||||
char *name, void *value, size_t size);
|
||||
|
||||
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value, size_t size)
|
||||
{
|
||||
return lgetxattr(rpath(ctx, path), name, value, size);
|
||||
}
|
||||
|
||||
static inline int pt_setxattr(FsContext *ctx, const char *path,
|
||||
const char *name, void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return lsetxattr(rpath(ctx, path), name, value, size, flags);
|
||||
}
|
||||
|
||||
static inline int pt_removexattr(FsContext *ctx,
|
||||
const char *path, const char *name)
|
||||
{
|
||||
return lremovexattr(rpath(ctx, path), name);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#include "virtio-9p.h"
|
||||
#include "fsdev/qemu-fsdev.h"
|
||||
#include "virtio-9p-debug.h"
|
||||
#include "virtio-9p-xattr.h"
|
||||
|
||||
int debug_9p_pdu;
|
||||
|
||||
|
@ -3712,23 +3713,26 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
|
|||
if (!strcmp(fse->security_model, "passthrough")) {
|
||||
/* Files on the Fileserver set to client user credentials */
|
||||
s->ctx.fs_sm = SM_PASSTHROUGH;
|
||||
s->ctx.xops = passthrough_xattr_ops;
|
||||
} else if (!strcmp(fse->security_model, "mapped")) {
|
||||
/* Files on the fileserver are set to QEMU credentials.
|
||||
* Client user credentials are saved in extended attributes.
|
||||
*/
|
||||
s->ctx.fs_sm = SM_MAPPED;
|
||||
s->ctx.xops = mapped_xattr_ops;
|
||||
} else if (!strcmp(fse->security_model, "none")) {
|
||||
/*
|
||||
* Files on the fileserver are set to QEMU credentials.
|
||||
*/
|
||||
s->ctx.fs_sm = SM_NONE;
|
||||
|
||||
s->ctx.xops = none_xattr_ops;
|
||||
} else {
|
||||
fprintf(stderr, "Default to security_model=none. You may want"
|
||||
" enable advanced security model using "
|
||||
"security option:\n\t security_model=passthrough \n\t "
|
||||
"security_model=mapped\n");
|
||||
s->ctx.fs_sm = SM_NONE;
|
||||
s->ctx.xops = none_xattr_ops;
|
||||
}
|
||||
|
||||
if (lstat(fse->path, &stat)) {
|
||||
|
|
Loading…
Reference in a new issue