* [Qemu-devel] [PATCH V2 01/12] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 02/12] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
` (12 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Move p9 marshaling/unmarshaling code to a separate file so that
proxy filesytem driver can use these calls. Also made marshaling
code generic to accept "struct iovec" instead of V9fsPDU.
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
Makefile.objs | 2 +-
fsdev/virtio-9p-marshal.c | 338 +++++++++++++++++++++++++++++++++++++++++++++
fsdev/virtio-9p-marshal.h | 87 ++++++++++++
hw/9pfs/virtio-9p.c | 297 +---------------------------------------
hw/9pfs/virtio-9p.h | 85 ++----------
5 files changed, 440 insertions(+), 369 deletions(-)
create mode 100644 fsdev/virtio-9p-marshal.c
create mode 100644 fsdev/virtio-9p-marshal.h
diff --git a/Makefile.objs b/Makefile.objs
index d7a6539..c256fdc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -61,7 +61,7 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
# only pull in the actual virtio-9p device if we also enabled virtio.
CONFIG_REALLY_VIRTFS=y
-fsdev-nested-y = qemu-fsdev.o
+fsdev-nested-y = qemu-fsdev.o virtio-9p-marshal.o
else
fsdev-nested-y = qemu-fsdev-dummy.o
endif
diff --git a/fsdev/virtio-9p-marshal.c b/fsdev/virtio-9p-marshal.c
new file mode 100644
index 0000000..2da0a34
--- /dev/null
+++ b/fsdev/virtio-9p-marshal.c
@@ -0,0 +1,338 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.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 <glib.h>
+#include <glib/gprintf.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "compiler.h"
+#include "virtio-9p-marshal.h"
+#include "bswap.h"
+
+void v9fs_string_init(V9fsString *str)
+{
+ str->data = NULL;
+ str->size = 0;
+}
+
+void v9fs_string_free(V9fsString *str)
+{
+ g_free(str->data);
+ str->data = NULL;
+ str->size = 0;
+}
+
+void v9fs_string_null(V9fsString *str)
+{
+ v9fs_string_free(str);
+}
+
+void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+{
+ va_list ap;
+
+ v9fs_string_free(str);
+
+ va_start(ap, fmt);
+ str->size = g_vasprintf(&str->data, fmt, ap);
+ va_end(ap);
+}
+
+void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+{
+ v9fs_string_free(lhs);
+ v9fs_string_sprintf(lhs, "%s", rhs->data);
+}
+
+
+static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
+ size_t offset, size_t size, int pack)
+{
+ int i = 0;
+ size_t copied = 0;
+
+ for (i = 0; size && i < sg_count; i++) {
+ size_t len;
+ if (offset >= sg[i].iov_len) {
+ /* skip this sg */
+ offset -= sg[i].iov_len;
+ continue;
+ } else {
+ len = MIN(sg[i].iov_len - offset, size);
+ if (pack) {
+ memcpy(sg[i].iov_base + offset, addr, len);
+ } else {
+ memcpy(addr, sg[i].iov_base + offset, len);
+ }
+ size -= len;
+ copied += len;
+ addr += len;
+ if (size) {
+ offset = 0;
+ continue;
+ }
+ }
+ }
+
+ return copied;
+}
+
+static size_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
+ size_t offset, size_t size)
+{
+ return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
+}
+
+size_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
+ const void *src, size_t size)
+{
+ return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
+}
+
+static int v9fs_copy_sg(struct iovec *src_sg, unsigned int num,
+ size_t offset, struct iovec *sg)
+{
+ size_t pos = 0;
+ int i, j;
+
+ j = 0;
+ for (i = 0; i < num; i++) {
+ if (offset <= pos) {
+ sg[j].iov_base = src_sg[i].iov_base;
+ sg[j].iov_len = src_sg[i].iov_len;
+ j++;
+ } else if (offset < (src_sg[i].iov_len + pos)) {
+ sg[j].iov_base = src_sg[i].iov_base;
+ sg[j].iov_len = src_sg[i].iov_len;
+ sg[j].iov_base += (offset - pos);
+ sg[j].iov_len -= (offset - pos);
+ j++;
+ }
+ pos += src_sg[i].iov_len;
+ }
+
+ return j;
+}
+
+size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
+ int convert, const char *fmt, ...)
+{
+ size_t old_offset = offset;
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ for (i = 0; fmt[i]; i++) {
+ switch (fmt[i]) {
+ case 'b': {
+ uint8_t *valp = va_arg(ap, uint8_t *);
+ offset += v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
+ break;
+ }
+ case 'w': {
+ uint16_t val, *valp;
+ valp = va_arg(ap, uint16_t *);
+ offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (convert) {
+ *valp = le16_to_cpu(val);
+ } else {
+ *valp = val;
+ }
+ break;
+ }
+ case 'd': {
+ uint32_t val, *valp;
+ valp = va_arg(ap, uint32_t *);
+ offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (convert) {
+ *valp = le32_to_cpu(val);
+ } else {
+ *valp = val;
+ }
+ break;
+ }
+ case 'q': {
+ uint64_t val, *valp;
+ valp = va_arg(ap, uint64_t *);
+ offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (convert) {
+ *valp = le64_to_cpu(val);
+ } else {
+ *valp = val;
+ }
+ break;
+ }
+ case 'v': {
+ struct iovec *iov = va_arg(ap, struct iovec *);
+ int *iovcnt = va_arg(ap, int *);
+ *iovcnt = v9fs_copy_sg(out_sg, out_num, offset, iov);
+ break;
+ }
+ case 's': {
+ V9fsString *str = va_arg(ap, V9fsString *);
+ offset += v9fs_unmarshal(out_sg, out_num, offset, convert,
+ "w", &str->size);
+ /* FIXME: sanity check str->size */
+ str->data = g_malloc(str->size + 1);
+ offset += v9fs_unpack(str->data, out_sg, out_num, offset,
+ str->size);
+ str->data[str->size] = 0;
+ break;
+ }
+ case 'Q': {
+ V9fsQID *qidp = va_arg(ap, V9fsQID *);
+ offset += v9fs_unmarshal(out_sg, out_num, offset, convert, "bdq",
+ &qidp->type, &qidp->version, &qidp->path);
+ break;
+ }
+ case 'S': {
+ V9fsStat *statp = va_arg(ap, V9fsStat *);
+ offset += v9fs_unmarshal(out_sg, out_num, offset, convert,
+ "wwdQdddqsssssddd",
+ &statp->size, &statp->type, &statp->dev,
+ &statp->qid, &statp->mode, &statp->atime,
+ &statp->mtime, &statp->length,
+ &statp->name, &statp->uid, &statp->gid,
+ &statp->muid, &statp->extension,
+ &statp->n_uid, &statp->n_gid,
+ &statp->n_muid);
+ break;
+ }
+ case 'I': {
+ V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
+ offset += v9fs_unmarshal(out_sg, out_num, offset, convert,
+ "ddddqqqqq",
+ &iattr->valid, &iattr->mode,
+ &iattr->uid, &iattr->gid, &iattr->size,
+ &iattr->atime_sec, &iattr->atime_nsec,
+ &iattr->mtime_sec, &iattr->mtime_nsec);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ va_end(ap);
+
+ return offset - old_offset;
+}
+
+size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
+ int convert, const char *fmt, ...)
+{
+ size_t old_offset = offset;
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ for (i = 0; fmt[i]; i++) {
+ switch (fmt[i]) {
+ case 'b': {
+ uint8_t val = va_arg(ap, int);
+ offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+ break;
+ }
+ case 'w': {
+ uint16_t val;
+ if (convert) {
+ cpu_to_le16w(&val, va_arg(ap, int));
+ } else {
+ val = va_arg(ap, int);
+ }
+ offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+ break;
+ }
+ case 'd': {
+ uint32_t val;
+ if (convert) {
+ cpu_to_le32w(&val, va_arg(ap, uint32_t));
+ } else {
+ val = va_arg(ap, uint32_t);
+ }
+ offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+ break;
+ }
+ case 'q': {
+ uint64_t val;
+ if (convert) {
+ cpu_to_le64w(&val, va_arg(ap, uint64_t));
+ } else {
+ val = va_arg(ap, uint64_t);
+ }
+ offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+ break;
+ }
+ case 'v': {
+ struct iovec *iov = va_arg(ap, struct iovec *);
+ int *iovcnt = va_arg(ap, int *);
+ *iovcnt = v9fs_copy_sg(in_sg, in_num, offset, iov);
+ break;
+ }
+ case 's': {
+ V9fsString *str = va_arg(ap, V9fsString *);
+ offset += v9fs_marshal(in_sg, in_num, offset, convert,
+ "w", str->size);
+ offset += v9fs_pack(in_sg, in_num, offset, str->data, str->size);
+ break;
+ }
+ case 'Q': {
+ V9fsQID *qidp = va_arg(ap, V9fsQID *);
+ offset += v9fs_marshal(in_sg, in_num, offset, convert, "bdq",
+ qidp->type, qidp->version, qidp->path);
+ break;
+ }
+ case 'S': {
+ V9fsStat *statp = va_arg(ap, V9fsStat *);
+ offset += v9fs_marshal(in_sg, in_num, offset, convert,
+ "wwdQdddqsssssddd",
+ statp->size, statp->type, statp->dev,
+ &statp->qid, statp->mode, statp->atime,
+ statp->mtime, statp->length, &statp->name,
+ &statp->uid, &statp->gid, &statp->muid,
+ &statp->extension, statp->n_uid,
+ statp->n_gid, statp->n_muid);
+ break;
+ }
+ case 'A': {
+ V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
+ offset += v9fs_marshal(in_sg, in_num, offset, convert,
+ "qQdddqqqqqqqqqqqqqqq",
+ statp->st_result_mask,
+ &statp->qid, statp->st_mode,
+ statp->st_uid, statp->st_gid,
+ statp->st_nlink, statp->st_rdev,
+ statp->st_size, statp->st_blksize,
+ statp->st_blocks, statp->st_atime_sec,
+ statp->st_atime_nsec, statp->st_mtime_sec,
+ statp->st_mtime_nsec, statp->st_ctime_sec,
+ statp->st_ctime_nsec, statp->st_btime_sec,
+ statp->st_btime_nsec, statp->st_gen,
+ statp->st_data_version);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ va_end(ap);
+
+ return offset - old_offset;
+}
diff --git a/fsdev/virtio-9p-marshal.h b/fsdev/virtio-9p-marshal.h
new file mode 100644
index 0000000..fe2d34b
--- /dev/null
+++ b/fsdev/virtio-9p-marshal.h
@@ -0,0 +1,87 @@
+#ifndef _QEMU_VIRTIO_9P_MARSHAL_H
+#define _QEMU_VIRTIO_9P_MARSHAL_H
+
+typedef struct V9fsString
+{
+ int16_t size;
+ char *data;
+} V9fsString;
+
+typedef struct V9fsQID
+{
+ int8_t type;
+ int32_t version;
+ int64_t path;
+} V9fsQID;
+
+typedef struct V9fsStat
+{
+ int16_t size;
+ int16_t type;
+ int32_t dev;
+ V9fsQID qid;
+ int32_t mode;
+ int32_t atime;
+ int32_t mtime;
+ int64_t length;
+ V9fsString name;
+ V9fsString uid;
+ V9fsString gid;
+ V9fsString muid;
+ /* 9p2000.u */
+ V9fsString extension;
+ int32_t n_uid;
+ int32_t n_gid;
+ int32_t n_muid;
+} V9fsStat;
+
+typedef struct V9fsIattr
+{
+ int32_t valid;
+ int32_t mode;
+ int32_t uid;
+ int32_t gid;
+ int64_t size;
+ int64_t atime_sec;
+ int64_t atime_nsec;
+ int64_t mtime_sec;
+ int64_t mtime_nsec;
+} V9fsIattr;
+
+typedef struct V9fsStatDotl {
+ uint64_t st_result_mask;
+ V9fsQID qid;
+ uint32_t st_mode;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint64_t st_nlink;
+ uint64_t st_rdev;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_atime_sec;
+ uint64_t st_atime_nsec;
+ uint64_t st_mtime_sec;
+ uint64_t st_mtime_nsec;
+ uint64_t st_ctime_sec;
+ uint64_t st_ctime_nsec;
+ uint64_t st_btime_sec;
+ uint64_t st_btime_nsec;
+ uint64_t st_gen;
+ uint64_t st_data_version;
+} V9fsStatDotl;
+
+extern void v9fs_string_init(V9fsString *str);
+extern void v9fs_string_free(V9fsString *str);
+extern void v9fs_string_null(V9fsString *str);
+extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
+extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
+
+size_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
+ const void *src, size_t size);
+size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
+ int convert, const char *fmt, ...);
+size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
+ int convert, const char *fmt, ...);
+
+#endif
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 01cf337..2a8ac56 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -11,9 +11,6 @@
*
*/
-#include <glib.h>
-#include <glib/gprintf.h>
-
#include "hw/virtio.h"
#include "hw/pc.h"
#include "qemu_socket.h"
@@ -146,42 +143,6 @@ static int get_dotl_openflags(V9fsState *s, int oflags)
return flags;
}
-void v9fs_string_init(V9fsString *str)
-{
- str->data = NULL;
- str->size = 0;
-}
-
-void v9fs_string_free(V9fsString *str)
-{
- g_free(str->data);
- str->data = NULL;
- str->size = 0;
-}
-
-void v9fs_string_null(V9fsString *str)
-{
- v9fs_string_free(str);
-}
-
-void GCC_FMT_ATTR(2, 3)
-v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
-{
- va_list ap;
-
- v9fs_string_free(str);
-
- va_start(ap, fmt);
- str->size = g_vasprintf(&str->data, fmt, ap);
- va_end(ap);
-}
-
-void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
-{
- v9fs_string_free(lhs);
- v9fs_string_sprintf(lhs, "%s", rhs->data);
-}
-
void v9fs_path_init(V9fsPath *path)
{
path->data = NULL;
@@ -600,257 +561,6 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu)
}
}
-size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
- size_t offset, size_t size, int pack)
-{
- int i = 0;
- size_t copied = 0;
-
- for (i = 0; size && i < sg_count; i++) {
- size_t len;
- if (offset >= sg[i].iov_len) {
- /* skip this sg */
- offset -= sg[i].iov_len;
- continue;
- } else {
- len = MIN(sg[i].iov_len - offset, size);
- if (pack) {
- memcpy(sg[i].iov_base + offset, addr, len);
- } else {
- memcpy(addr, sg[i].iov_base + offset, len);
- }
- size -= len;
- copied += len;
- addr += len;
- if (size) {
- offset = 0;
- continue;
- }
- }
- }
-
- return copied;
-}
-
-static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
-{
- return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
- offset, size, 0);
-}
-
-static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
- size_t size)
-{
- return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
- offset, size, 1);
-}
-
-static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
-{
- size_t pos = 0;
- int i, j;
- struct iovec *src_sg;
- unsigned int num;
-
- if (rx) {
- src_sg = pdu->elem.in_sg;
- num = pdu->elem.in_num;
- } else {
- src_sg = pdu->elem.out_sg;
- num = pdu->elem.out_num;
- }
-
- j = 0;
- for (i = 0; i < num; i++) {
- if (offset <= pos) {
- sg[j].iov_base = src_sg[i].iov_base;
- sg[j].iov_len = src_sg[i].iov_len;
- j++;
- } else if (offset < (src_sg[i].iov_len + pos)) {
- sg[j].iov_base = src_sg[i].iov_base;
- sg[j].iov_len = src_sg[i].iov_len;
- sg[j].iov_base += (offset - pos);
- sg[j].iov_len -= (offset - pos);
- j++;
- }
- pos += src_sg[i].iov_len;
- }
-
- return j;
-}
-
-static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
- size_t old_offset = offset;
- va_list ap;
- int i;
-
- va_start(ap, fmt);
- for (i = 0; fmt[i]; i++) {
- switch (fmt[i]) {
- case 'b': {
- uint8_t *valp = va_arg(ap, uint8_t *);
- offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
- break;
- }
- case 'w': {
- uint16_t val, *valp;
- valp = va_arg(ap, uint16_t *);
- offset += pdu_unpack(&val, pdu, offset, sizeof(val));
- *valp = le16_to_cpu(val);
- break;
- }
- case 'd': {
- uint32_t val, *valp;
- valp = va_arg(ap, uint32_t *);
- offset += pdu_unpack(&val, pdu, offset, sizeof(val));
- *valp = le32_to_cpu(val);
- break;
- }
- case 'q': {
- uint64_t val, *valp;
- valp = va_arg(ap, uint64_t *);
- offset += pdu_unpack(&val, pdu, offset, sizeof(val));
- *valp = le64_to_cpu(val);
- break;
- }
- case 'v': {
- struct iovec *iov = va_arg(ap, struct iovec *);
- int *iovcnt = va_arg(ap, int *);
- *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
- break;
- }
- case 's': {
- V9fsString *str = va_arg(ap, V9fsString *);
- offset += pdu_unmarshal(pdu, offset, "w", &str->size);
- /* FIXME: sanity check str->size */
- str->data = g_malloc(str->size + 1);
- offset += pdu_unpack(str->data, pdu, offset, str->size);
- str->data[str->size] = 0;
- break;
- }
- case 'Q': {
- V9fsQID *qidp = va_arg(ap, V9fsQID *);
- offset += pdu_unmarshal(pdu, offset, "bdq",
- &qidp->type, &qidp->version, &qidp->path);
- break;
- }
- case 'S': {
- V9fsStat *statp = va_arg(ap, V9fsStat *);
- offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
- &statp->size, &statp->type, &statp->dev,
- &statp->qid, &statp->mode, &statp->atime,
- &statp->mtime, &statp->length,
- &statp->name, &statp->uid, &statp->gid,
- &statp->muid, &statp->extension,
- &statp->n_uid, &statp->n_gid,
- &statp->n_muid);
- break;
- }
- case 'I': {
- V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
- offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
- &iattr->valid, &iattr->mode,
- &iattr->uid, &iattr->gid, &iattr->size,
- &iattr->atime_sec, &iattr->atime_nsec,
- &iattr->mtime_sec, &iattr->mtime_nsec);
- break;
- }
- default:
- break;
- }
- }
-
- va_end(ap);
-
- return offset - old_offset;
-}
-
-static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
-{
- size_t old_offset = offset;
- va_list ap;
- int i;
-
- va_start(ap, fmt);
- for (i = 0; fmt[i]; i++) {
- switch (fmt[i]) {
- case 'b': {
- uint8_t val = va_arg(ap, int);
- offset += pdu_pack(pdu, offset, &val, sizeof(val));
- break;
- }
- case 'w': {
- uint16_t val;
- cpu_to_le16w(&val, va_arg(ap, int));
- offset += pdu_pack(pdu, offset, &val, sizeof(val));
- break;
- }
- case 'd': {
- uint32_t val;
- cpu_to_le32w(&val, va_arg(ap, uint32_t));
- offset += pdu_pack(pdu, offset, &val, sizeof(val));
- break;
- }
- case 'q': {
- uint64_t val;
- cpu_to_le64w(&val, va_arg(ap, uint64_t));
- offset += pdu_pack(pdu, offset, &val, sizeof(val));
- break;
- }
- case 'v': {
- struct iovec *iov = va_arg(ap, struct iovec *);
- int *iovcnt = va_arg(ap, int *);
- *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
- break;
- }
- case 's': {
- V9fsString *str = va_arg(ap, V9fsString *);
- offset += pdu_marshal(pdu, offset, "w", str->size);
- offset += pdu_pack(pdu, offset, str->data, str->size);
- break;
- }
- case 'Q': {
- V9fsQID *qidp = va_arg(ap, V9fsQID *);
- offset += pdu_marshal(pdu, offset, "bdq",
- qidp->type, qidp->version, qidp->path);
- break;
- }
- case 'S': {
- V9fsStat *statp = va_arg(ap, V9fsStat *);
- offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
- statp->size, statp->type, statp->dev,
- &statp->qid, statp->mode, statp->atime,
- statp->mtime, statp->length, &statp->name,
- &statp->uid, &statp->gid, &statp->muid,
- &statp->extension, statp->n_uid,
- statp->n_gid, statp->n_muid);
- break;
- }
- case 'A': {
- V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
- offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
- statp->st_result_mask,
- &statp->qid, statp->st_mode,
- statp->st_uid, statp->st_gid,
- statp->st_nlink, statp->st_rdev,
- statp->st_size, statp->st_blksize, statp->st_blocks,
- statp->st_atime_sec, statp->st_atime_nsec,
- statp->st_mtime_sec, statp->st_mtime_nsec,
- statp->st_ctime_sec, statp->st_ctime_nsec,
- statp->st_btime_sec, statp->st_btime_nsec,
- statp->st_gen, statp->st_data_version);
- break;
- }
- default:
- break;
- }
- }
- va_end(ap);
-
- return offset - old_offset;
-}
-
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
{
int8_t id = pdu->id + 1; /* Response */
@@ -1758,9 +1468,10 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
read_count = 0;
}
offset += pdu_marshal(pdu, offset, "d", read_count);
- offset += pdu_pack(pdu, offset,
- ((char *)fidp->fs.xattr.value) + off,
- read_count);
+ offset += v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
+ ((char *)fidp->fs.xattr.value) + off,
+ read_count);
+
return offset;
}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 7f88356..93ebb4f 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -8,9 +8,11 @@
#include <sys/resource.h>
#include "hw/virtio.h"
#include "fsdev/file-op-9p.h"
+#include "fsdev/virtio-9p-marshal.h"
#include "qemu-thread.h"
#include "qemu-coroutine.h"
+
/* The feature bitmap for virtio 9P */
/* The mount point is specified in a config variable */
#define VIRTIO_9P_MOUNT_TAG 0
@@ -154,40 +156,6 @@ struct V9fsPDU
typedef struct V9fsFidState V9fsFidState;
-typedef struct V9fsString
-{
- int16_t size;
- char *data;
-} V9fsString;
-
-typedef struct V9fsQID
-{
- int8_t type;
- int32_t version;
- int64_t path;
-} V9fsQID;
-
-typedef struct V9fsStat
-{
- int16_t size;
- int16_t type;
- int32_t dev;
- V9fsQID qid;
- int32_t mode;
- int32_t atime;
- int32_t mtime;
- int64_t length;
- V9fsString name;
- V9fsString uid;
- V9fsString gid;
- V9fsString muid;
- /* 9p2000.u */
- V9fsString extension;
- int32_t n_uid;
- int32_t n_gid;
- int32_t n_muid;
-} V9fsStat;
-
enum {
P9_FID_NONE = 0,
P9_FID_FILE,
@@ -266,29 +234,6 @@ typedef struct V9fsStatState {
struct stat stbuf;
} V9fsStatState;
-typedef struct V9fsStatDotl {
- uint64_t st_result_mask;
- V9fsQID qid;
- uint32_t st_mode;
- uint32_t st_uid;
- uint32_t st_gid;
- uint64_t st_nlink;
- uint64_t st_rdev;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_atime_sec;
- uint64_t st_atime_nsec;
- uint64_t st_mtime_sec;
- uint64_t st_mtime_nsec;
- uint64_t st_ctime_sec;
- uint64_t st_ctime_nsec;
- uint64_t st_btime_sec;
- uint64_t st_btime_nsec;
- uint64_t st_gen;
- uint64_t st_data_version;
-} V9fsStatDotl;
-
typedef struct V9fsOpenState {
V9fsPDU *pdu;
size_t offset;
@@ -331,19 +276,6 @@ typedef struct V9fsWriteState {
int cnt;
} V9fsWriteState;
-typedef struct V9fsIattr
-{
- int32_t valid;
- int32_t mode;
- int32_t uid;
- int32_t gid;
- int64_t size;
- int64_t atime_sec;
- int64_t atime_nsec;
- int64_t mtime_sec;
- int64_t mtime_nsec;
-} V9fsIattr;
-
struct virtio_9p_config
{
/* number of characters in tag */
@@ -458,14 +390,17 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
extern void virtio_9p_set_fd_limit(void);
extern void v9fs_reclaim_fd(V9fsPDU *pdu);
-extern void v9fs_string_init(V9fsString *str);
-extern void v9fs_string_free(V9fsString *str);
-extern void v9fs_string_null(V9fsString *str);
-extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
-extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
extern void v9fs_path_init(V9fsPath *path);
extern void v9fs_path_free(V9fsPath *path);
extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
const char *name, V9fsPath *path);
+
+#define pdu_marshal(pdu, offset, fmt, args...) \
+ v9fs_marshal(pdu->elem.in_sg, pdu->elem.in_num, offset, \
+ 1 /* convert */, fmt, ##args)
+#define pdu_unmarshal(pdu, offset, fmt, args...) \
+ v9fs_unmarshal(pdu->elem.out_sg, pdu->elem.out_num, offset, \
+ 1 /* convert */, fmt, ##args)
+
#endif
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 02/12] hw/9pfs: Add new proxy filesystem driver
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 01/12] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
` (11 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add new proxy filesystem driver to add root privilege to qemu process.
It needs a helper process to be started by root user.
Following command line can be used to utilize proxy filesystem driver
-virtfs proxy,id=<id>,mount_tag=<tag>,socket_fd=<socket-fd>
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
Makefile.objs | 2 +-
fsdev/file-op-9p.h | 1 -
fsdev/qemu-fsdev.c | 1 +
fsdev/qemu-fsdev.h | 1 +
fsdev/virtio-9p-marshal.h | 2 +-
hw/9pfs/virtio-9p-proxy.c | 374 +++++++++++++++++++++++++++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.h | 10 ++
qemu-config.c | 6 +
vl.c | 6 +-
9 files changed, 399 insertions(+), 4 deletions(-)
create mode 100644 hw/9pfs/virtio-9p-proxy.c
create mode 100644 hw/9pfs/virtio-9p-proxy.h
diff --git a/Makefile.objs b/Makefile.objs
index c256fdc..8201202 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -311,7 +311,7 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
-9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o virtio-9p-proxy.o
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 22849c9..84e5375 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -60,7 +60,6 @@ typedef struct extended_ops {
#define V9FS_SEC_MASK 0x0000001C
-
typedef struct FileOperations FileOperations;
/*
* Structure to store the various fsdev's passed through command line.
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index efbfea1..b31d116 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -25,6 +25,7 @@ static FsDriverTable FsDrivers[] = {
{ .name = "local", .ops = &local_ops},
{ .name = "handle", .ops = &handle_ops},
{ .name = "synth", .ops = &synth_ops},
+ { .name = "proxy", .ops = &proxy_ops},
};
int qemu_fsdev_add(QemuOpts *opts)
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index 921452d..1af1f54 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -44,4 +44,5 @@ FsDriverEntry *get_fsdev_fsentry(char *id);
extern FileOperations local_ops;
extern FileOperations handle_ops;
extern FileOperations synth_ops;
+extern FileOperations proxy_ops;
#endif
diff --git a/fsdev/virtio-9p-marshal.h b/fsdev/virtio-9p-marshal.h
index fe2d34b..45dba20 100644
--- a/fsdev/virtio-9p-marshal.h
+++ b/fsdev/virtio-9p-marshal.h
@@ -30,7 +30,7 @@ typedef struct V9fsStat
V9fsString muid;
/* 9p2000.u */
V9fsString extension;
- int32_t n_uid;
+ int32_t n_uid;
int32_t n_gid;
int32_t n_muid;
} V9fsStat;
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
new file mode 100644
index 0000000..0e539e3
--- /dev/null
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -0,0 +1,374 @@
+/*
+ * Virtio 9p Proxy callback
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * M. Mohan Kumar <mohan@in.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/socket.h>
+#include <sys/un.h>
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-proxy.h"
+
+typedef struct V9fsProxy {
+ int sockfd;
+ QemuMutex mutex;
+ struct iovec iovec;
+} V9fsProxy;
+
+static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+ char *buf, size_t bufsz)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ return close(fs->fd);
+}
+
+static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ return closedir(fs->dir);
+}
+
+static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
+ int flags, V9fsFidOpenState *fs)
+{
+ fs->fd = -1;
+ return fs->fd;
+}
+
+static int proxy_opendir(FsContext *ctx,
+ V9fsPath *fs_path, V9fsFidOpenState *fs)
+{
+ fs->dir = NULL;
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ return rewinddir(fs->dir);
+}
+
+static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+{
+ return telldir(fs->dir);
+}
+
+static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
+ struct dirent *entry,
+ struct dirent **result)
+{
+ return readdir_r(fs->dir, entry, result);
+}
+
+static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
+{
+ return seekdir(fs->dir, off);
+}
+
+static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+ return preadv(fs->fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fs->fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ return readv(fs->fd, iov, iovcnt);
+ }
+#endif
+}
+
+static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
+ const struct iovec *iov,
+ int iovcnt, off_t offset)
+{
+ ssize_t ret;
+
+#ifdef CONFIG_PREADV
+ ret = pwritev(fs->fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fs->fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ ret = writev(fs->fd, iov, iovcnt);
+ }
+#endif
+#ifdef CONFIG_SYNC_FILE_RANGE
+ if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
+ /*
+ * Initiate a writeback. This is not a data integrity sync.
+ * We want to ensure that we don't leave dirty pages in the cache
+ * after write when writeout=immediate is sepcified.
+ */
+ sync_file_range(fs->fd, offset, ret,
+ SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
+ }
+#endif
+ return ret;
+}
+
+static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+ const char *name, FsCred *credp)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_fstat(FsContext *fs_ctx,
+ V9fsFidOpenState *fs, struct stat *stbuf)
+{
+ int err;
+ err = fstat(fs->fd, stbuf);
+ return err;
+}
+
+static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+ int flags, FsCred *credp, V9fsFidOpenState *fs)
+{
+ fs->fd = -1;
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+
+static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
+ V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
+ V9fsPath *dirpath, const char *name)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_rename(FsContext *ctx, const char *oldpath,
+ const char *newpath)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
+ const struct timespec *buf)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_remove(FsContext *ctx, const char *path)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
+{
+ if (datasync) {
+ return qemu_fdatasync(fs->fd);
+ } else {
+ return fsync(fs->fd);
+ }
+}
+
+static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+ const char *name, void *value, size_t size)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+ void *value, size_t size)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+ void *value, size_t size, int flags)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+ const char *name)
+{
+ errno = EOPNOTSUPP;
+ return -1;
+}
+
+static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+ const char *name, V9fsPath *target)
+{
+ if (dir_path) {
+ v9fs_string_sprintf((V9fsString *)target, "%s/%s",
+ dir_path->data, name);
+ } else {
+ v9fs_string_sprintf((V9fsString *)target, "%s", name);
+ }
+ /* Bump the size for including terminating NULL */
+ target->size++;
+ return 0;
+}
+
+static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
+ const char *old_name, V9fsPath *newdir,
+ const char *new_name)
+{
+ int ret;
+ V9fsString old_full_name, new_full_name;
+
+ v9fs_string_init(&old_full_name);
+ v9fs_string_init(&new_full_name);
+
+ v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
+ v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
+
+ ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
+ v9fs_string_free(&old_full_name);
+ v9fs_string_free(&new_full_name);
+ return ret;
+}
+
+static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
+ const char *name, int flags)
+{
+ int ret;
+ V9fsString fullname;
+ v9fs_string_init(&fullname);
+
+ v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+ ret = proxy_remove(ctx, fullname.data);
+ v9fs_string_free(&fullname);
+
+ return ret;
+}
+
+static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
+{
+ const char *sock_fd = qemu_opt_get(opts, "sock_fd");
+
+ if (sock_fd) {
+ fprintf(stderr, "sock_fd option not specified\n");
+ return -1;
+ }
+ fs->path = g_strdup(sock_fd);
+ return 0;
+}
+
+static int proxy_init(FsContext *ctx)
+{
+ V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
+ int sock_id;
+
+ sock_id = atoi(ctx->fs_root);
+ if (sock_id < 0) {
+ fprintf(stderr, "socket descriptor not initialized\n");
+ return -1;
+ }
+ g_free(ctx->fs_root);
+
+ proxy->iovec.iov_base = g_malloc(BUFF_SZ);
+ proxy->iovec.iov_len = BUFF_SZ;
+ ctx->private = proxy;
+ proxy->sockfd = sock_id;
+ qemu_mutex_init(&proxy->mutex);
+
+ ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
+ return 0;
+}
+
+FileOperations proxy_ops = {
+ .parse_opts = proxy_parse_opts,
+ .init = proxy_init,
+ .lstat = proxy_lstat,
+ .readlink = proxy_readlink,
+ .close = proxy_close,
+ .closedir = proxy_closedir,
+ .open = proxy_open,
+ .opendir = proxy_opendir,
+ .rewinddir = proxy_rewinddir,
+ .telldir = proxy_telldir,
+ .readdir_r = proxy_readdir_r,
+ .seekdir = proxy_seekdir,
+ .preadv = proxy_preadv,
+ .pwritev = proxy_pwritev,
+ .chmod = proxy_chmod,
+ .mknod = proxy_mknod,
+ .mkdir = proxy_mkdir,
+ .fstat = proxy_fstat,
+ .open2 = proxy_open2,
+ .symlink = proxy_symlink,
+ .link = proxy_link,
+ .truncate = proxy_truncate,
+ .rename = proxy_rename,
+ .chown = proxy_chown,
+ .utimensat = proxy_utimensat,
+ .remove = proxy_remove,
+ .fsync = proxy_fsync,
+ .statfs = proxy_statfs,
+ .lgetxattr = proxy_lgetxattr,
+ .llistxattr = proxy_llistxattr,
+ .lsetxattr = proxy_lsetxattr,
+ .lremovexattr = proxy_lremovexattr,
+ .name_to_path = proxy_name_to_path,
+ .renameat = proxy_renameat,
+ .unlinkat = proxy_unlinkat,
+};
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
new file mode 100644
index 0000000..f5e1a02
--- /dev/null
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -0,0 +1,10 @@
+#ifndef _QEMU_VIRTIO_9P_PROXY_H
+#define _QEMU_VIRTIO_9P_PROXY_H
+
+#define BUFF_SZ (4 * 1024)
+
+typedef struct {
+ int type;
+ int size;
+} ProxyHeader;
+#endif
diff --git a/qemu-config.c b/qemu-config.c
index 597d7e1..33367fe 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -183,6 +183,9 @@ QemuOptsList qemu_fsdev_opts = {
}, {
.name = "readonly",
.type = QEMU_OPT_BOOL,
+ }, {
+ .name = "sock_fd",
+ .type = QEMU_OPT_NUMBER,
},
{ /*End of list */ }
@@ -212,6 +215,9 @@ QemuOptsList qemu_virtfs_opts = {
}, {
.name = "readonly",
.type = QEMU_OPT_BOOL,
+ }, {
+ .name = "sock_fd",
+ .type = QEMU_OPT_NUMBER,
},
{ /*End of list */ }
diff --git a/vl.c b/vl.c
index e3b2443..1feaf37 100644
--- a/vl.c
+++ b/vl.c
@@ -2663,7 +2663,7 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_virtfs: {
QemuOpts *fsdev;
QemuOpts *device;
- const char *writeout;
+ const char *writeout, *sock_fd;
olist = qemu_find_opts("virtfs");
if (!olist) {
@@ -2703,6 +2703,10 @@ int main(int argc, char **argv, char **envp)
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
qemu_opt_set(fsdev, "security_model",
qemu_opt_get(opts, "security_model"));
+ sock_fd = qemu_opt_get(opts, "sock_fd");
+ if (sock_fd) {
+ qemu_opt_set(fsdev, "sock_fd", sock_fd);
+ }
qemu_opt_set_bool(fsdev, "readonly",
qemu_opt_get_bool(opts, "readonly", 0));
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 01/12] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 02/12] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 14:03 ` Stefan Hajnoczi
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 04/12] hw/9pfs: Open and create files M. Mohan Kumar
` (10 subsequent siblings)
13 siblings, 1 reply; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Provide root privilege access to QEMU 9p proxy filesystem using socket
communication.
Proxy helper is started by root user as:
~ # virtfs-proxy-helper -f|--fd <socket descriptor> -p|--path <path-to-share>
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
Makefile | 3 +
configure | 19 +++
fsdev/virtfs-proxy-helper.c | 271 +++++++++++++++++++++++++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.h | 10 ++
4 files changed, 303 insertions(+), 0 deletions(-)
create mode 100644 fsdev/virtfs-proxy-helper.c
diff --git a/Makefile b/Makefile
index ba8d738..19b481a 100644
--- a/Makefile
+++ b/Makefile
@@ -153,6 +153,9 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
+fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o
+fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
+
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
diff --git a/configure b/configure
index a6cf6d6..a2b55e8 100755
--- a/configure
+++ b/configure
@@ -1873,6 +1873,22 @@ else
fi
##########################################
+# libcap probe
+
+if test "$cap" != "no" ; then
+ cat > $TMPC <<EOF
+#include <stdio.h>
+#include <sys/capability.h>
+int main(void) { cap_t caps; caps = cap_init(); }
+EOF
+ if compile_prog "" "-lcap" ; then
+ cap=yes
+ else
+ cap=no
+ fi
+fi
+
+##########################################
# pthread probe
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
@@ -2662,6 +2678,9 @@ confdir=$sysconfdir$confsuffix
tools=
if test "$softmmu" = yes ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
+ if [ "$cap" = "yes" -a "$linux" = "yes" ] ; then
+ tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+ fi
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
tools="qemu-nbd\$(EXESUF) $tools"
if [ "$guest_agent" = "yes" ]; then
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
new file mode 100644
index 0000000..69daf7c
--- /dev/null
+++ b/fsdev/virtfs-proxy-helper.c
@@ -0,0 +1,271 @@
+/*
+ * Helper for QEMU Proxy FS Driver
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * M. Mohan Kumar <mohan@in.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 <stdio.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <sys/fsuid.h>
+#include <stdarg.h>
+#include "bswap.h"
+#include <sys/socket.h>
+#include "qemu-common.h"
+#include "virtio-9p-marshal.h"
+#include "hw/9pfs/virtio-9p-proxy.h"
+
+#define PROGNAME "virtfs-proxy-helper"
+
+static struct option helper_opts[] = {
+ {"fd", required_argument, NULL, 'f'},
+ {"path", required_argument, NULL, 'p'},
+ {"nodaemon", no_argument, NULL, 'n'},
+};
+
+int is_daemon;
+
+static void do_perror(const char *string)
+{
+ if (is_daemon) {
+ syslog(LOG_CRIT, "%s:%s", string, strerror(errno));
+ } else {
+ fprintf(stderr, "%s:%s\n", string, strerror(errno));
+ }
+}
+
+static void do_log(int level, const char *string)
+{
+ if (is_daemon) {
+ syslog(level, "%s", string);
+ } else {
+ fprintf(stderr, "%s\n", string);
+ }
+}
+
+static int cap_set(void)
+{
+ int retval;
+ cap_t caps;
+ cap_value_t cap_list[10];
+
+ /* helper needs following capbabilities only */
+ cap_list[0] = CAP_CHOWN;
+ cap_list[1] = CAP_DAC_OVERRIDE;
+ cap_list[2] = CAP_DAC_READ_SEARCH;
+ cap_list[3] = CAP_FOWNER;
+ cap_list[4] = CAP_FSETID;
+ cap_list[5] = CAP_SETGID;
+ cap_list[6] = CAP_MKNOD;
+ cap_list[7] = CAP_SETUID;
+
+ caps = cap_init();
+ if (caps == NULL) {
+ do_perror("cap_init");
+ return -1;
+ }
+ retval = cap_set_flag(caps, CAP_PERMITTED, 8, cap_list, CAP_SET);
+ if (retval < 0) {
+ do_perror("cap_set_flag");
+ goto error;
+ }
+ retval = cap_set_proc(caps);
+ if (retval < 0) {
+ do_perror("cap_set_proc");
+ }
+ retval = cap_set_flag(caps, CAP_EFFECTIVE, 8, cap_list, CAP_SET);
+ if (retval < 0) {
+ do_perror("cap_set_flag");
+ goto error;
+ }
+ retval = cap_set_proc(caps);
+ if (retval < 0) {
+ do_perror("cap_set_proc");
+ }
+
+error:
+ cap_free(caps);
+ return retval;
+}
+
+static int init_capabilities(void)
+{
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ do_perror("prctl");
+ return -1;
+ }
+ if (cap_set() < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static int socket_read(int sockfd, void *buff, ssize_t size)
+{
+ int retval;
+
+ do {
+ retval = read(sockfd, buff, size);
+ } while (retval < 0 && errno == EINTR);
+ if (retval != size) {
+ return -EIO;
+ }
+ return retval;
+}
+
+static int socket_write(int sockfd, void *buff, ssize_t size)
+{
+ int retval;
+
+ do {
+ retval = write(sockfd, buff, size);
+ } while (retval < 0 && errno == EINTR);
+ if (retval != size) {
+ return -EIO;
+ }
+ return retval;
+}
+
+static int read_request(int sockfd, struct iovec *iovec)
+{
+ int retval;
+ ProxyHeader header;
+
+ /* read the header */
+ retval = socket_read(sockfd, iovec->iov_base, sizeof(header));
+ if (retval != sizeof(header)) {
+ return -EIO;
+ }
+ /* unmarshal header */
+ proxy_unmarshal(iovec, 1, 0, "dd", &header.type, &header.size);
+ /* read the request */
+ retval = socket_read(sockfd, iovec->iov_base + sizeof(header), header.size);
+ if (retval != header.size) {
+ return -EIO;
+ }
+ return header.type;
+}
+
+static void usage(char *prog)
+{
+ fprintf(stderr, "usage: %s\n"
+ " -p|--path <path> 9p path to export\n"
+ " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
+ " [-n|--nodaemon] Run as a normal program\n",
+ basename(prog));
+}
+
+static int process_requests(int sock)
+{
+ int type;
+ struct iovec iovec;
+
+ iovec.iov_base = g_malloc(BUFF_SZ);
+ iovec.iov_len = BUFF_SZ;
+ while (1) {
+ type = read_request(sock, &iovec);
+ if (type <= 0) {
+ goto error;
+ }
+ }
+ (void)socket_write;
+error:
+ g_free(iovec.iov_base);
+ return -1;
+}
+
+int main(int argc, char **argv)
+{
+ int sock;
+ char rpath[PATH_MAX];
+ struct stat stbuf;
+ int c, option_index;
+
+ is_daemon = 1;
+ rpath[0] = '\0';
+ sock = -1;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
+ &option_index);
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case 'p':
+ strcpy(rpath, optarg);
+ break;
+ case 'n':
+ is_daemon = 0;
+ break;
+ case 'f':
+ sock = atoi(optarg);
+ break;
+ case '?':
+ case 'h':
+ default:
+ usage(argv[0]);
+ return -1;
+ break;
+ }
+ }
+
+ /* Parameter validation */
+ if (sock == -1 || rpath[0] == '\0') {
+ fprintf(stderr, "socket descriptor or path not specified\n");
+ usage(argv[0]);
+ return -1;
+ }
+
+ if (lstat(rpath, &stbuf) < 0) {
+ fprintf(stderr, "invalid path \"%s\" specified?\n", rpath);
+ return -1;
+ }
+
+ if (!S_ISDIR(stbuf.st_mode)) {
+ fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
+ return -1;
+ }
+
+ if (is_daemon) {
+ if (daemon(0, 0) < 0) {
+ fprintf(stderr, "daemon call failed\n");
+ return -1;
+ }
+ openlog(PROGNAME, LOG_PID, LOG_DAEMON);
+ }
+
+ do_log(LOG_INFO, "Started");
+
+ if (chroot(rpath) < 0) {
+ do_perror("chroot");
+ goto error;
+ }
+ umask(0);
+
+ if (init_capabilities() < 0) {
+ goto error;
+ }
+
+ process_requests(sock);
+error:
+ do_log(LOG_INFO, "Done");
+ closelog();
+ return 0;
+}
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index f5e1a02..120e940 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -3,6 +3,16 @@
#define BUFF_SZ (4 * 1024)
+#define proxy_unmarshal(in_sg, in_elem, offset, fmt, args...) \
+ v9fs_unmarshal(in_sg, in_elem, offset, 0 /* convert */, fmt, ##args)
+#define proxy_marshal(out_sg, out_elem, offset, fmt, args...) \
+ v9fs_marshal(out_sg, out_elem, offset, 0 /* convert */, fmt, ##args)
+
+union MsgControl {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(int))];
+};
+
typedef struct {
int type;
int size;
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
@ 2011-11-15 14:03 ` Stefan Hajnoczi
2011-11-16 8:51 ` M. Mohan Kumar
0 siblings, 1 reply; 20+ messages in thread
From: Stefan Hajnoczi @ 2011-11-15 14:03 UTC (permalink / raw)
To: M. Mohan Kumar; +Cc: qemu-devel, aneesh.kumar
On Tue, Nov 15, 2011 at 11:57 AM, M. Mohan Kumar <mohan@in.ibm.com> wrote:
> diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
> new file mode 100644
> index 0000000..69daf7c
> --- /dev/null
> +++ b/fsdev/virtfs-proxy-helper.c
> @@ -0,0 +1,271 @@
> +/*
> + * Helper for QEMU Proxy FS Driver
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + * M. Mohan Kumar <mohan@in.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 <stdio.h>
> +#include <sys/socket.h>
> +#include <string.h>
> +#include <sys/un.h>
> +#include <limits.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <sys/resource.h>
> +#include <sys/stat.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +#include <syslog.h>
> +#include <sys/prctl.h>
> +#include <sys/capability.h>
> +#include <sys/fsuid.h>
> +#include <stdarg.h>
> +#include "bswap.h"
Where is "bswap.h" used and why above <sys/socket.h>?
> +#include <sys/socket.h>
> +#include "qemu-common.h"
> +#include "virtio-9p-marshal.h"
> +#include "hw/9pfs/virtio-9p-proxy.h"
> +
> +#define PROGNAME "virtfs-proxy-helper"
> +
> +static struct option helper_opts[] = {
> + {"fd", required_argument, NULL, 'f'},
> + {"path", required_argument, NULL, 'p'},
> + {"nodaemon", no_argument, NULL, 'n'},
> +};
> +
> +int is_daemon;
static?
Also, please use the bool type from <stdbool.h>, it makes it easier
for readers who don't have to guess how the variable works (might be a
bitfield or reference count too).
> +static int socket_read(int sockfd, void *buff, ssize_t size)
> +{
> + int retval;
> +
> + do {
> + retval = read(sockfd, buff, size);
> + } while (retval < 0 && errno == EINTR);
> + if (retval != size) {
> + return -EIO;
> + }
Shouldn't this loop until size bytes have been read?
> + return retval;
> +}
> +
> +static int socket_write(int sockfd, void *buff, ssize_t size)
> +{
> + int retval;
> +
> + do {
> + retval = write(sockfd, buff, size);
> + } while (retval < 0 && errno == EINTR);
> + if (retval != size) {
> + return -EIO;
We could pass the actual -errno here if retval < 0.
> + }
> + return retval;
> +}
> +
> +static int read_request(int sockfd, struct iovec *iovec)
> +{
> + int retval;
> + ProxyHeader header;
> +
> + /* read the header */
> + retval = socket_read(sockfd, iovec->iov_base, sizeof(header));
> + if (retval != sizeof(header)) {
> + return -EIO;
> + }
> + /* unmarshal header */
> + proxy_unmarshal(iovec, 1, 0, "dd", &header.type, &header.size);
> + /* read the request */
> + retval = socket_read(sockfd, iovec->iov_base + sizeof(header), header.size);
> + if (retval != header.size) {
> + return -EIO;
> + }
> + return header.type;
> +}
Size checks are missing and we're trusting what the client sends!
> +
> +static void usage(char *prog)
> +{
> + fprintf(stderr, "usage: %s\n"
> + " -p|--path <path> 9p path to export\n"
> + " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
> + " [-n|--nodaemon] Run as a normal program\n",
> + basename(prog));
> +}
> +
> +static int process_requests(int sock)
> +{
> + int type;
> + struct iovec iovec;
> +
> + iovec.iov_base = g_malloc(BUFF_SZ);
> + iovec.iov_len = BUFF_SZ;
> + while (1) {
> + type = read_request(sock, &iovec);
> + if (type <= 0) {
> + goto error;
> + }
> + }
> + (void)socket_write;
> +error:
> + g_free(iovec.iov_base);
> + return -1;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int sock;
> + char rpath[PATH_MAX];
> + struct stat stbuf;
> + int c, option_index;
> +
> + is_daemon = 1;
> + rpath[0] = '\0';
> + sock = -1;
> + while (1) {
> + option_index = 0;
> + c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
> + &option_index);
> + if (c == -1) {
> + break;
> + }
> + switch (c) {
> + case 'p':
> + strcpy(rpath, optarg);
Buffer overflow. The whole thing would be simpler like this:
const char *rpath = "";
[...]
case 'p':
rpath = optarg;
break;
> + break;
> + case 'n':
> + is_daemon = 0;
> + break;
> + case 'f':
> + sock = atoi(optarg);
> + break;
> + case '?':
> + case 'h':
> + default:
> + usage(argv[0]);
> + return -1;
The convention is for programs to exit with 1 (EXIT_FAILURE) on error.
> + break;
> + }
> + }
> +
> + /* Parameter validation */
> + if (sock == -1 || rpath[0] == '\0') {
> + fprintf(stderr, "socket descriptor or path not specified\n");
> + usage(argv[0]);
> + return -1;
> + }
> +
> + if (lstat(rpath, &stbuf) < 0) {
> + fprintf(stderr, "invalid path \"%s\" specified?\n", rpath);
sterror() would provide further details on what went wrong.
> + return -1;
> + }
> +
> + if (!S_ISDIR(stbuf.st_mode)) {
> + fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
> + return -1;
> + }
> +
> + if (is_daemon) {
> + if (daemon(0, 0) < 0) {
> + fprintf(stderr, "daemon call failed\n");
> + return -1;
> + }
> + openlog(PROGNAME, LOG_PID, LOG_DAEMON);
> + }
> +
> + do_log(LOG_INFO, "Started");
> +
> + if (chroot(rpath) < 0) {
> + do_perror("chroot");
> + goto error;
> + }
> + umask(0);
> +
> + if (init_capabilities() < 0) {
> + goto error;
> + }
> +
> + process_requests(sock);
> +error:
> + do_log(LOG_INFO, "Done");
> + closelog();
> + return 0;
> +}
> diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
> index f5e1a02..120e940 100644
> --- a/hw/9pfs/virtio-9p-proxy.h
> +++ b/hw/9pfs/virtio-9p-proxy.h
> @@ -3,6 +3,16 @@
>
> #define BUFF_SZ (4 * 1024)
>
> +#define proxy_unmarshal(in_sg, in_elem, offset, fmt, args...) \
> + v9fs_unmarshal(in_sg, in_elem, offset, 0 /* convert */, fmt, ##args)
> +#define proxy_marshal(out_sg, out_elem, offset, fmt, args...) \
> + v9fs_marshal(out_sg, out_elem, offset, 0 /* convert */, fmt, ##args)
> +
> +union MsgControl {
> + struct cmsghdr cmsg;
> + char control[CMSG_SPACE(sizeof(int))];
> +};
This union isn't used in this patch.
Stefan
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS
2011-11-15 14:03 ` Stefan Hajnoczi
@ 2011-11-16 8:51 ` M. Mohan Kumar
2011-11-16 10:23 ` Stefan Hajnoczi
0 siblings, 1 reply; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-16 8:51 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: qemu-devel, aneesh.kumar
Stefan Hajnoczi wrote:
> On Tue, Nov 15, 2011 at 11:57 AM, M. Mohan Kumar<mohan@in.ibm.com> wrote:
>
>> diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
>> new file mode 100644
>> index 0000000..69daf7c
>> --- /dev/null
>> +++ b/fsdev/virtfs-proxy-helper.c
>> @@ -0,0 +1,271 @@
>> +/*
>> + * Helper for QEMU Proxy FS Driver
>> + * Copyright IBM, Corp. 2011
>> + *
>> + * Authors:
>> + * M. Mohan Kumar<mohan@in.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<stdio.h>
>> +#include<sys/socket.h>
>> +#include<string.h>
>> +#include<sys/un.h>
>> +#include<limits.h>
>> +#include<signal.h>
>> +#include<errno.h>
>> +#include<stdlib.h>
>> +#include<sys/resource.h>
>> +#include<sys/stat.h>
>> +#include<getopt.h>
>> +#include<unistd.h>
>> +#include<syslog.h>
>> +#include<sys/prctl.h>
>> +#include<sys/capability.h>
>> +#include<sys/fsuid.h>
>> +#include<stdarg.h>
>> +#include "bswap.h"
>>
> Where is "bswap.h" used and why above<sys/socket.h>?
>
I will fix it
>
>> +#include<sys/socket.h>
>> +#include "qemu-common.h"
>> +#include "virtio-9p-marshal.h"
>> +#include "hw/9pfs/virtio-9p-proxy.h"
>> +
>> +#define PROGNAME "virtfs-proxy-helper"
>> +
>> +static struct option helper_opts[] = {
>> + {"fd", required_argument, NULL, 'f'},
>> + {"path", required_argument, NULL, 'p'},
>> + {"nodaemon", no_argument, NULL, 'n'},
>> +};
>> +
>> +int is_daemon;
>>
> static?
>
> Also, please use the bool type from<stdbool.h>, it makes it easier
> for readers who don't have to guess how the variable works (might be a
> bitfield or reference count too).
>
>
I will fix it.
>> +static int socket_read(int sockfd, void *buff, ssize_t size)
>> +{
>> + int retval;
>> +
>> + do {
>> + retval = read(sockfd, buff, size);
>> + } while (retval< 0&& errno == EINTR);
>> + if (retval != size) {
>> + return -EIO;
>> + }
>>
> Shouldn't this loop until size bytes have been read?
>
>
Ok, I will fix this.
>> + return retval;
>> +}
>> +
>> +static int socket_write(int sockfd, void *buff, ssize_t size)
>> +{
>> + int retval;
>> +
>> + do {
>> + retval = write(sockfd, buff, size);
>> + } while (retval< 0&& errno == EINTR);
>> + if (retval != size) {
>> + return -EIO;
>>
> We could pass the actual -errno here if retval< 0.
>
>
Socket errors are treated fatal and the reason for failures are not used
by the code. When ever there is socket error, helper exits.
>> + }
>> + return retval;
>> +}
>> +
>> +static int read_request(int sockfd, struct iovec *iovec)
>> +{
>> + int retval;
>> + ProxyHeader header;
>> +
>> + /* read the header */
>> + retval = socket_read(sockfd, iovec->iov_base, sizeof(header));
>> + if (retval != sizeof(header)) {
>> + return -EIO;
>> + }
>> + /* unmarshal header */
>> + proxy_unmarshal(iovec, 1, 0, "dd",&header.type,&header.size);
>> + /* read the request */
>> + retval = socket_read(sockfd, iovec->iov_base + sizeof(header), header.size);
>> + if (retval != header.size) {
>> + return -EIO;
>> + }
>> + return header.type;
>> +}
>>
> Size checks are missing and we're trusting what the client sends!
>
Could you please elaborate?
>
>> +
>> +static void usage(char *prog)
>> +{
>> + fprintf(stderr, "usage: %s\n"
>> + " -p|--path<path> 9p path to export\n"
>> + " {-f|--fd<socket-descriptor>} socket file descriptor to be used\n"
>> + " [-n|--nodaemon] Run as a normal program\n",
>> + basename(prog));
>> +}
>> +
>> +static int process_requests(int sock)
>> +{
>> + int type;
>> + struct iovec iovec;
>> +
>> + iovec.iov_base = g_malloc(BUFF_SZ);
>> + iovec.iov_len = BUFF_SZ;
>> + while (1) {
>> + type = read_request(sock,&iovec);
>> + if (type<= 0) {
>> + goto error;
>> + }
>> + }
>> + (void)socket_write;
>> +error:
>> + g_free(iovec.iov_base);
>> + return -1;
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> + int sock;
>> + char rpath[PATH_MAX];
>> + struct stat stbuf;
>> + int c, option_index;
>> +
>> + is_daemon = 1;
>> + rpath[0] = '\0';
>> + sock = -1;
>> + while (1) {
>> + option_index = 0;
>> + c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
>> +&option_index);
>> + if (c == -1) {
>> + break;
>> + }
>> + switch (c) {
>> + case 'p':
>> + strcpy(rpath, optarg);
>>
> Buffer overflow. The whole thing would be simpler like this:
>
> const char *rpath = "";
> [...]
> case 'p':
> rpath = optarg;
> break;
>
>
I will fix it
>> + break;
>> + case 'n':
>> + is_daemon = 0;
>> + break;
>> + case 'f':
>> + sock = atoi(optarg);
>> + break;
>> + case '?':
>> + case 'h':
>> + default:
>> + usage(argv[0]);
>> + return -1;
>>
> The convention is for programs to exit with 1 (EXIT_FAILURE) on error.
>
>
I will fix it.
>> + break;
>> + }
>> + }
>> +
>> + /* Parameter validation */
>> + if (sock == -1 || rpath[0] == '\0') {
>> + fprintf(stderr, "socket descriptor or path not specified\n");
>> + usage(argv[0]);
>> + return -1;
>> + }
>> +
>> + if (lstat(rpath,&stbuf)< 0) {
>> + fprintf(stderr, "invalid path \"%s\" specified?\n", rpath);
>>
> sterror() would provide further details on what went wrong.
>
Ok
>
>> + return -1;
>> + }
>> +
>> + if (!S_ISDIR(stbuf.st_mode)) {
>> + fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
>> + return -1;
>> + }
>> +
>> + if (is_daemon) {
>> + if (daemon(0, 0)< 0) {
>> + fprintf(stderr, "daemon call failed\n");
>> + return -1;
>> + }
>> + openlog(PROGNAME, LOG_PID, LOG_DAEMON);
>> + }
>> +
>> + do_log(LOG_INFO, "Started");
>> +
>> + if (chroot(rpath)< 0) {
>> + do_perror("chroot");
>> + goto error;
>> + }
>> + umask(0);
>> +
>> + if (init_capabilities()< 0) {
>> + goto error;
>> + }
>> +
>> + process_requests(sock);
>> +error:
>> + do_log(LOG_INFO, "Done");
>> + closelog();
>> + return 0;
>> +}
>> diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
>> index f5e1a02..120e940 100644
>> --- a/hw/9pfs/virtio-9p-proxy.h
>> +++ b/hw/9pfs/virtio-9p-proxy.h
>> @@ -3,6 +3,16 @@
>>
>> #define BUFF_SZ (4 * 1024)
>>
>> +#define proxy_unmarshal(in_sg, in_elem, offset, fmt, args...) \
>> + v9fs_unmarshal(in_sg, in_elem, offset, 0 /* convert */, fmt, ##args)
>> +#define proxy_marshal(out_sg, out_elem, offset, fmt, args...) \
>> + v9fs_marshal(out_sg, out_elem, offset, 0 /* convert */, fmt, ##args)
>> +
>> +union MsgControl {
>> + struct cmsghdr cmsg;
>> + char control[CMSG_SPACE(sizeof(int))];
>> +};
>>
> This union isn't used in this patch.
>
>
I will fix it.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS
2011-11-16 8:51 ` M. Mohan Kumar
@ 2011-11-16 10:23 ` Stefan Hajnoczi
0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hajnoczi @ 2011-11-16 10:23 UTC (permalink / raw)
To: M. Mohan Kumar; +Cc: qemu-devel, aneesh.kumar
On Wed, Nov 16, 2011 at 8:51 AM, M. Mohan Kumar <mohan@in.ibm.com> wrote:
> Stefan Hajnoczi wrote:
>>> +static int socket_write(int sockfd, void *buff, ssize_t size)
>>> +{
>>> + int retval;
>>> +
>>> + do {
>>> + retval = write(sockfd, buff, size);
>>> + } while (retval< 0&& errno == EINTR);
>>> + if (retval != size) {
>>> + return -EIO;
>>>
>>
>> We could pass the actual -errno here if retval< 0.
>>
>>
>
> Socket errors are treated fatal and the reason for failures are not used
> by the code. When ever there is socket error, helper exits.
Exiting may be fine but errno or strerror(errno) needs to be printed
on exit. Otherwise we need to strace it to figure out what happened -
and the error exit may be hard to reproduce, so this is not
attractive. Therefore it makes sense to return the full -errno and
print it out when exiting.
>>> +static int read_request(int sockfd, struct iovec *iovec)
>>> +{
>>> + int retval;
>>> + ProxyHeader header;
>>> +
>>> + /* read the header */
>>> + retval = socket_read(sockfd, iovec->iov_base, sizeof(header));
>>> + if (retval != sizeof(header)) {
>>> + return -EIO;
>>> + }
>>> + /* unmarshal header */
>>> + proxy_unmarshal(iovec, 1, 0, "dd",&header.type,&header.size);
>>> + /* read the request */
>>> + retval = socket_read(sockfd, iovec->iov_base + sizeof(header),
>>> header.size);
>>> + if (retval != header.size) {
>>> + return -EIO;
>>> + }
>>> + return header.type;
>>> +}
>>>
>>
>> Size checks are missing and we're trusting what the client sends!
>>
>
> Could you please elaborate?
This function allows the client to overflow the iovec buffer. Check
what happens when header.size > 4096.
I'm alarmed by this because there are 9 more patches to review and
this is just the foundation of the helper. If the helper isn't secure
then isolating it from QEMU is useless since a malicious QEMU can take
over the helper. Input needs to be validated.
Stefan
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 04/12] hw/9pfs: Open and create files
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (2 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 03/12] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-17 15:46 ` Stefan Hajnoczi
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 05/12] hw/9pfs: Create other filesystem objects M. Mohan Kumar
` (9 subsequent siblings)
13 siblings, 1 reply; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add interfaces to open and create files for proxy file system driver.
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
fsdev/virtfs-proxy-helper.c | 136 +++++++++++++++++++++++++++++++-
hw/9pfs/virtio-9p-proxy.c | 180 +++++++++++++++++++++++++++++++++++++++++--
hw/9pfs/virtio-9p-proxy.h | 9 ++
3 files changed, 314 insertions(+), 11 deletions(-)
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 69daf7c..68d27f1 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -30,6 +30,8 @@
#include "qemu-common.h"
#include "virtio-9p-marshal.h"
#include "hw/9pfs/virtio-9p-proxy.h"
+#include "fsdev/virtio-9p-marshal.h"
+
#define PROGNAME "virtfs-proxy-helper"
@@ -148,20 +150,125 @@ static int read_request(int sockfd, struct iovec *iovec)
ProxyHeader header;
/* read the header */
- retval = socket_read(sockfd, iovec->iov_base, sizeof(header));
- if (retval != sizeof(header)) {
+ retval = socket_read(sockfd, iovec->iov_base, HDR_SZ);
+ if (retval != HDR_SZ) {
return -EIO;
}
/* unmarshal header */
proxy_unmarshal(iovec, 1, 0, "dd", &header.type, &header.size);
/* read the request */
- retval = socket_read(sockfd, iovec->iov_base + sizeof(header), header.size);
+ retval = socket_read(sockfd, iovec->iov_base + HDR_SZ, header.size);
if (retval != header.size) {
return -EIO;
}
return header.type;
}
+static void send_fd(int sockfd, int fd)
+{
+ struct msghdr msg = { };
+ struct iovec iov;
+ struct cmsghdr *cmsg;
+ int retval, data;
+ union MsgControl msg_control;
+
+ iov.iov_base = &data;
+ iov.iov_len = sizeof(data);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ /* No ancillary data on error */
+ if (fd < 0) {
+ /*
+ * fd is really negative errno if the request failed. Or simply
+ * zero if the request is successful and it doesn't need a file
+ * descriptor.
+ */
+ data = fd;
+ } else {
+ data = V9FS_FD_VALID;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+ cmsg = &msg_control.cmsg;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+ }
+
+ do {
+ retval = sendmsg(sockfd, &msg, 0);
+ } while (retval < 0 && errno == EINTR);
+ if (retval < 0) {
+ do_perror("sendmsg");
+ exit(1);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
+/*
+ * from man 7 capabilities, section
+ * Effect of User ID Changes on Capabilities:
+ * 4. If the file system user ID is changed from 0 to nonzero (see setfsuid(2))
+ * then the following capabilities are cleared from the effective set:
+ * CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID,
+ * CAP_LINUX_IMMUTABLE (since Linux 2.2.30), CAP_MAC_OVERRIDE, and CAP_MKNOD
+ * (since Linux 2.2.30). If the file system UID is changed from nonzero to 0,
+ * then any of these capabilities that are enabled in the permitted set
+ * are enabled in the effective set.
+ */
+static int setfsugid(int uid, int gid)
+{
+ setfsgid(gid);
+ setfsuid(uid);
+ return cap_set();
+}
+
+/*
+ * create a file and send fd on success
+ * return -errno on error
+ */
+static int do_create(struct iovec *iovec)
+{
+ V9fsString path;
+ int flags, fd, mode, uid, gid, cur_uid, cur_gid;
+ proxy_unmarshal(iovec, 1, HDR_SZ, "sdddd",
+ &path, &flags, &mode, &uid, &gid);
+ cur_uid = geteuid();
+ cur_gid = getegid();
+ if (setfsugid(uid, gid) < 0) {
+ return -EPERM;
+ }
+ fd = open(path.data, flags, mode);
+ if (fd < 0) {
+ fd = -errno;
+ }
+ v9fs_string_free(&path);
+ setfsugid(cur_uid, cur_gid);
+ return fd;
+}
+
+/*
+ * open a file and send fd on success
+ * return -errno on error
+ */
+static int do_open(struct iovec *iovec)
+{
+ V9fsString path;
+ int flags, fd;
+ proxy_unmarshal(iovec, 1, HDR_SZ, "sd", &path, &flags);
+ fd = open(path.data, flags);
+ if (fd < 0) {
+ fd = -errno;
+ }
+ v9fs_string_free(&path);
+ return fd;
+}
+
static void usage(char *prog)
{
fprintf(stderr, "usage: %s\n"
@@ -173,15 +280,34 @@ static void usage(char *prog)
static int process_requests(int sock)
{
- int type;
+ int type, retval = 0;
struct iovec iovec;
iovec.iov_base = g_malloc(BUFF_SZ);
iovec.iov_len = BUFF_SZ;
while (1) {
type = read_request(sock, &iovec);
- if (type <= 0) {
+ switch (type) {
+ case T_OPEN:
+ retval = do_open(&iovec);
+ break;
+ case T_CREATE:
+ retval = do_create(&iovec);
+ break;
+ default:
+ goto error;
+ break;
+ }
+
+ /* Send response */
+ switch (type) {
+ case T_OPEN:
+ case T_CREATE:
+ send_fd(sock, retval);
+ break;
+ default:
goto error;
+ break;
}
}
(void)socket_write;
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index 0e539e3..8cc55d6 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -22,6 +22,144 @@ typedef struct V9fsProxy {
struct iovec iovec;
} V9fsProxy;
+/*
+ * Return received file descriptor on success and -errno on failure.
+ * sock_error is set to 1 whenever there is error in socket IO
+ */
+static int v9fs_receivefd(int sockfd, int *sock_error)
+{
+ struct msghdr msg = { };
+ struct iovec iov;
+ union MsgControl msg_control;
+ struct cmsghdr *cmsg;
+ int retval, data, fd;
+
+ iov.iov_base = &data;
+ iov.iov_len = sizeof(data);
+
+ *sock_error = 0;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+ do {
+ retval = recvmsg(sockfd, &msg, 0);
+ } while (retval < 0 && errno == EINTR);
+ if (retval <= 0) {
+ *sock_error = 1;
+ return -EIO;
+ }
+
+ /*
+ * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
+ * request doesn't need ancillary data (fd) or an error occurred,
+ * data is set to negative errno value.
+ */
+ if (data != V9FS_FD_VALID) {
+ return data;
+ }
+
+ /*
+ * File descriptor (fd) is sent in the ancillary data. Check if we
+ * indeed received it. One of the reasons to fail to receive it is if
+ * we exceeded the maximum number of file descriptors!
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+ cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS) {
+ continue;
+ }
+ fd = *((int *)CMSG_DATA(cmsg));
+ return fd;
+ }
+
+ return -ENFILE; /* Ancillary data sent but not received */
+}
+
+/*
+ * Proxy->header and proxy->request written to socket by QEMU process.
+ * This request read by proxy helper process
+ * returns 0 on success and -errno on error
+ */
+static int v9fs_request(V9fsProxy *proxy, int type,
+ void *response, const char *fmt, ...)
+{
+ int retval;
+ ProxyHeader header;
+ va_list ap;
+ V9fsString *path;
+ int sock_error, flags, mode, uid, gid;
+ struct iovec *iovec = NULL;
+
+ qemu_mutex_lock(&proxy->mutex);
+
+ if (proxy->sockfd == -1) {
+ goto error;
+ }
+ iovec = &proxy->iovec;
+
+ va_start(ap, fmt);
+ switch (type) {
+ case T_OPEN:
+ path = va_arg(ap, V9fsString *);
+ flags = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ,
+ "sd", path, flags);
+ header.type = T_OPEN;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_CREATE:
+ path = va_arg(ap, V9fsString *);
+ flags = va_arg(ap, int);
+ mode = va_arg(ap, int);
+ uid = va_arg(ap, int);
+ gid = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sdddd", path,
+ flags, mode, uid, gid);
+ header.type = T_CREATE;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ default:
+ error_report("Invalid type %d\n", type);
+ va_end(ap);
+ goto close_error;
+ break;
+ }
+ va_end(ap);
+
+ retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
+ if (retval != header.size) {
+ goto close_error;
+ }
+
+ switch (type) {
+ case T_OPEN:
+ case T_CREATE:
+ /*
+ * A file descriptor is returned as response for
+ * T_OPEN,T_CREATE on success
+ */
+ retval = v9fs_receivefd(proxy->sockfd, &sock_error);
+ if (sock_error) {
+ goto close_error;
+ }
+ break;
+ }
+ qemu_mutex_unlock(&proxy->mutex);
+ return retval;
+close_error:
+ close(proxy->sockfd);
+ proxy->sockfd = -1;
+error:
+ qemu_mutex_unlock(&proxy->mutex);
+ return -EIO;
+}
+
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
errno = EOPNOTSUPP;
@@ -48,16 +186,35 @@ static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- fs->fd = -1;
+ fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd",
+ fs_path, flags);
+ if (fs->fd < 0) {
+ errno = -fs->fd;
+ fs->fd = -1;
+ }
return fs->fd;
}
static int proxy_opendir(FsContext *ctx,
V9fsPath *fs_path, V9fsFidOpenState *fs)
{
+ int serrno, fd;
+
fs->dir = NULL;
- errno = EOPNOTSUPP;
- return -1;
+ fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd",
+ fs_path, O_DIRECTORY);
+ if (fd < 0) {
+ errno = -fd;
+ return -1;
+ }
+ fs->dir = fdopendir(fd);
+ if (!fs->dir) {
+ serrno = errno;
+ close(fd);
+ errno = serrno;
+ return -1;
+ }
+ return 0;
}
static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
@@ -159,9 +316,20 @@ static int proxy_fstat(FsContext *fs_ctx,
static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
int flags, FsCred *credp, V9fsFidOpenState *fs)
{
- fs->fd = -1;
- errno = EOPNOTSUPP;
- return -1;
+ V9fsString fullname;
+
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+
+ fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
+ &fullname, flags, credp->fc_mode,
+ credp->fc_uid, credp->fc_gid);
+ v9fs_string_free(&fullname);
+ if (fs->fd < 0) {
+ errno = -fs->fd;
+ fs->fd = -1;
+ }
+ return fs->fd;
}
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index 120e940..f30e367 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -2,6 +2,7 @@
#define _QEMU_VIRTIO_9P_PROXY_H
#define BUFF_SZ (4 * 1024)
+#define V9FS_FD_VALID INT_MAX
#define proxy_unmarshal(in_sg, in_elem, offset, fmt, args...) \
v9fs_unmarshal(in_sg, in_elem, offset, 0 /* convert */, fmt, ##args)
@@ -17,4 +18,12 @@ typedef struct {
int type;
int size;
} ProxyHeader;
+
+#define HDR_SZ (sizeof(ProxyHeader))
+
+enum {
+ T_OPEN = 1,
+ T_CREATE,
+};
+
#endif
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 04/12] hw/9pfs: Open and create files
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 04/12] hw/9pfs: Open and create files M. Mohan Kumar
@ 2011-11-17 15:46 ` Stefan Hajnoczi
0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hajnoczi @ 2011-11-17 15:46 UTC (permalink / raw)
To: M. Mohan Kumar; +Cc: qemu-devel, aneesh.kumar
On Tue, Nov 15, 2011 at 11:57 AM, M. Mohan Kumar <mohan@in.ibm.com> wrote:
> +static void send_fd(int sockfd, int fd)
> +{
> + struct msghdr msg = { };
> + struct iovec iov;
> + struct cmsghdr *cmsg;
> + int retval, data;
> + union MsgControl msg_control;
> +
> + iov.iov_base = &data;
> + iov.iov_len = sizeof(data);
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.msg_iov = &iov;
> + msg.msg_iovlen = 1;
> + /* No ancillary data on error */
> + if (fd < 0) {
> + /*
> + * fd is really negative errno if the request failed. Or simply
> + * zero if the request is successful and it doesn't need a file
> + * descriptor.
> + */
It cannot be zero because the if statement is fd < 0. The comment is confusing.
> +/*
> + * create a file and send fd on success
> + * return -errno on error
> + */
> +static int do_create(struct iovec *iovec)
> +{
> + V9fsString path;
> + int flags, fd, mode, uid, gid, cur_uid, cur_gid;
> + proxy_unmarshal(iovec, 1, HDR_SZ, "sdddd",
> + &path, &flags, &mode, &uid, &gid);
Unmarshalling can fail if the iovec size does not match what the
format string describes. We should fail here rather than continuing
on. If execution continues some of the variables may be
uninitialized.
Stefan
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 05/12] hw/9pfs: Create other filesystem objects
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (3 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 04/12] hw/9pfs: Open and create files M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 06/12] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
` (8 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add interfaces to create filesystem objects like directory,
device nodes, symbolic links, links for proxy filesytem driver
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
fsdev/virtfs-proxy-helper.c | 105 ++++++++++++++++++++++++--
hw/9pfs/virtio-9p-proxy.c | 173 +++++++++++++++++++++++++++++++++++++++----
hw/9pfs/virtio-9p-proxy.h | 8 ++-
3 files changed, 261 insertions(+), 25 deletions(-)
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 68d27f1..377e91a 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -210,6 +210,28 @@ static void send_fd(int sockfd, int fd)
}
}
+static int send_status(int sockfd, struct iovec *iovec, int status)
+{
+ int retval, msg_size;;
+ ProxyHeader header;
+
+ if (status < 0) {
+ header.type = T_ERROR;
+ } else {
+ header.type = T_SUCCESS;
+ }
+ header.size = sizeof(status);
+
+ /* marshal the return status */
+ msg_size = proxy_marshal(iovec, 1, 0, "ddd", header.type, header.size,
+ status);
+ retval = socket_write(sockfd, iovec->iov_base, msg_size);
+ if (retval != msg_size) {
+ return -EIO;
+ }
+ return 0;
+}
+
/*
* from man 7 capabilities, section
* Effect of User ID Changes on Capabilities:
@@ -229,6 +251,49 @@ static int setfsugid(int uid, int gid)
}
/*
+ * create a other filesystem objects and send 0 on success
+ * return -errno on error
+ */
+static int do_create_others(int type, struct iovec *iovec)
+{
+ dev_t rdev;
+ int retval = 0;
+ V9fsString oldpath, path;
+ int mode, uid, gid, cur_uid, cur_gid;
+ int offset = HDR_SZ;
+
+ cur_uid = geteuid();
+ cur_gid = getegid();
+
+ offset += proxy_unmarshal(iovec, 1, offset, "dd", &uid, &gid);
+ if (setfsugid(uid, gid) < 0) {
+ return -EPERM;
+ }
+ switch (type) {
+ case T_MKNOD:
+ proxy_unmarshal(iovec, 1, offset, "sdq", &path, &mode, &rdev);
+ retval = mknod(path.data, mode, rdev);
+ break;
+ case T_MKDIR:
+ proxy_unmarshal(iovec, 1, offset, "sd", &path, &mode);
+ retval = mkdir(path.data, mode);
+ break;
+ case T_SYMLINK:
+ proxy_unmarshal(iovec, 1, offset, "ss", &oldpath, &path);
+ retval = symlink(oldpath.data, path.data);
+ v9fs_string_free(&oldpath);
+ break;
+ }
+
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ setfsugid(cur_uid, cur_gid);
+ return retval;
+}
+
+/*
* create a file and send fd on success
* return -errno on error
*/
@@ -281,18 +346,36 @@ static void usage(char *prog)
static int process_requests(int sock)
{
int type, retval = 0;
- struct iovec iovec;
+ V9fsString oldpath, path;
+ struct iovec in_iovec, out_iovec;
+
+ in_iovec.iov_base = g_malloc(BUFF_SZ);
+ in_iovec.iov_len = BUFF_SZ;
+ out_iovec.iov_base = g_malloc(BUFF_SZ);
+ out_iovec.iov_len = BUFF_SZ;
- iovec.iov_base = g_malloc(BUFF_SZ);
- iovec.iov_len = BUFF_SZ;
while (1) {
- type = read_request(sock, &iovec);
+ type = read_request(sock, &in_iovec);
switch (type) {
case T_OPEN:
- retval = do_open(&iovec);
+ retval = do_open(&in_iovec);
break;
case T_CREATE:
- retval = do_create(&iovec);
+ retval = do_create(&in_iovec);
+ break;
+ case T_MKNOD:
+ case T_MKDIR:
+ case T_SYMLINK:
+ retval = do_create_others(type, &in_iovec);
+ break;
+ case T_LINK:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ, "ss", &oldpath, &path);
+ retval = link(oldpath.data, path.data);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&oldpath);
+ v9fs_string_free(&path);
break;
default:
goto error;
@@ -305,14 +388,20 @@ static int process_requests(int sock)
case T_CREATE:
send_fd(sock, retval);
break;
+ case T_MKNOD:
+ case T_MKDIR:
+ case T_SYMLINK:
+ case T_LINK:
+ send_status(sock, &out_iovec, retval);
+ break;
default:
goto error;
break;
}
}
- (void)socket_write;
error:
- g_free(iovec.iov_base);
+ g_free(in_iovec.iov_base);
+ g_free(out_iovec.iov_base);
return -1;
}
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index 8cc55d6..683d762 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -19,7 +19,8 @@
typedef struct V9fsProxy {
int sockfd;
QemuMutex mutex;
- struct iovec iovec;
+ struct iovec in_iovec;
+ struct iovec out_iovec;
} V9fsProxy;
/*
@@ -79,6 +80,38 @@ static int v9fs_receivefd(int sockfd, int *sock_error)
return -ENFILE; /* Ancillary data sent but not received */
}
+static ssize_t socket_read(int sockfd, void *buff, size_t size)
+{
+ ssize_t retval;
+ do {
+ retval = read(sockfd, buff, size);
+ } while (retval < 0 && errno == EINTR);
+ return retval;
+}
+
+
+static int v9fs_receive_status(V9fsProxy *proxy, int *sock_error,
+ struct iovec *reply)
+{
+ ProxyHeader header;
+ int retval;
+
+ *sock_error = 0;
+ retval = socket_read(proxy->sockfd, reply->iov_base, HDR_SZ);
+ if (retval != HDR_SZ) {
+ *sock_error = 1;
+ return -EIO;
+ }
+ proxy_unmarshal(reply, 1, 0, "dd", &header.type, &header.size);
+ retval = socket_read(proxy->sockfd, reply->iov_base + HDR_SZ, header.size);
+ if (retval != header.size) {
+ *sock_error = 1;
+ return -EIO;
+ }
+ proxy_unmarshal(reply, 1, HDR_SZ, "d", &retval);
+ return retval;
+}
+
/*
* Proxy->header and proxy->request written to socket by QEMU process.
* This request read by proxy helper process
@@ -90,17 +123,18 @@ static int v9fs_request(V9fsProxy *proxy, int type,
int retval;
ProxyHeader header;
va_list ap;
- V9fsString *path;
+ V9fsString *path, *oldpath;
int sock_error, flags, mode, uid, gid;
- struct iovec *iovec = NULL;
+ struct iovec *iovec = NULL, *reply = NULL;
+ dev_t rdev;
qemu_mutex_lock(&proxy->mutex);
if (proxy->sockfd == -1) {
goto error;
}
- iovec = &proxy->iovec;
-
+ iovec = &proxy->out_iovec;
+ reply = &proxy->in_iovec;
va_start(ap, fmt);
switch (type) {
case T_OPEN:
@@ -124,6 +158,49 @@ static int v9fs_request(V9fsProxy *proxy, int type,
proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
header.size += HDR_SZ;
break;
+ case T_MKNOD:
+ path = va_arg(ap, V9fsString *);
+ mode = va_arg(ap, int);
+ rdev = va_arg(ap, long int);
+ uid = va_arg(ap, int);
+ gid = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ddsdq",
+ uid, gid, path, mode, rdev);
+ header.type = T_MKNOD;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_MKDIR:
+ path = va_arg(ap, V9fsString *);
+ mode = va_arg(ap, int);
+ uid = va_arg(ap, int);
+ gid = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ddsd",
+ uid, gid, path, mode);
+ header.type = T_MKDIR;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_SYMLINK:
+ oldpath = va_arg(ap, V9fsString *);
+ path = va_arg(ap, V9fsString *);
+ uid = va_arg(ap, int);
+ gid = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ddss",
+ uid, gid, oldpath, path);
+ header.type = T_SYMLINK;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_LINK:
+ oldpath = va_arg(ap, V9fsString *);
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ss",
+ oldpath, path);
+ header.type = T_LINK;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
default:
error_report("Invalid type %d\n", type);
va_end(ap);
@@ -149,6 +226,15 @@ static int v9fs_request(V9fsProxy *proxy, int type,
goto close_error;
}
break;
+ case T_MKNOD:
+ case T_MKDIR:
+ case T_SYMLINK:
+ case T_LINK:
+ retval = v9fs_receive_status(proxy, &sock_error, reply);
+ if (sock_error) {
+ goto close_error;
+ }
+ break;
}
qemu_mutex_unlock(&proxy->mutex);
return retval;
@@ -294,15 +380,40 @@ static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
const char *name, FsCred *credp)
{
- errno = EOPNOTSUPP;
- return -1;
+ V9fsString fullname;
+ int retval;
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+
+ retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
+ &fullname, credp->fc_mode, credp->fc_rdev,
+ credp->fc_uid, credp->fc_gid);
+ v9fs_string_free(&fullname);
+ if (retval < 0) {
+ errno = -retval;
+ retval = -1;
+ }
+ return retval;
}
static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
const char *name, FsCred *credp)
{
- errno = EOPNOTSUPP;
- return -1;
+ V9fsString fullname;
+ int retval;
+
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+
+ retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
+ credp->fc_mode, credp->fc_uid, credp->fc_gid);
+ v9fs_string_free(&fullname);
+ if (retval < 0) {
+ errno = -retval;
+ retval = -1;
+ }
+ v9fs_string_free(&fullname);
+ return retval;
}
static int proxy_fstat(FsContext *fs_ctx,
@@ -332,19 +443,46 @@ static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
return fs->fd;
}
-
static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
V9fsPath *dir_path, const char *name, FsCred *credp)
{
- errno = EOPNOTSUPP;
- return -1;
+ V9fsString fullname, target;
+ int retval;
+
+ v9fs_string_init(&fullname);
+ v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+ v9fs_string_init(&target);
+ v9fs_string_sprintf(&target, "%s", oldpath);
+
+ retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
+ &target, &fullname, credp->fc_uid, credp->fc_gid);
+ v9fs_string_free(&fullname);
+ v9fs_string_free(&target);
+ if (retval < 0) {
+ errno = -retval;
+ retval = -1;
+ }
+ return retval;
}
static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
V9fsPath *dirpath, const char *name)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString newpath;
+
+ v9fs_string_init(&newpath);
+ v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
+
+ retval = v9fs_request(ctx->private, T_LINK, NULL, "ss",
+ oldpath, &newpath);
+ v9fs_string_free(&newpath);
+ if (retval < 0) {
+ errno = -retval;
+ retval = -1;
+ }
+ v9fs_string_free(&newpath);
+ return retval;
}
static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
@@ -493,8 +631,11 @@ static int proxy_init(FsContext *ctx)
}
g_free(ctx->fs_root);
- proxy->iovec.iov_base = g_malloc(BUFF_SZ);
- proxy->iovec.iov_len = BUFF_SZ;
+ proxy->in_iovec.iov_base = g_malloc(BUFF_SZ);
+ proxy->in_iovec.iov_len = BUFF_SZ;
+ proxy->out_iovec.iov_base = g_malloc(BUFF_SZ);
+ proxy->out_iovec.iov_len = BUFF_SZ;
+
ctx->private = proxy;
proxy->sockfd = sock_id;
qemu_mutex_init(&proxy->mutex);
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index f30e367..32610e0 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -22,8 +22,14 @@ typedef struct {
#define HDR_SZ (sizeof(ProxyHeader))
enum {
- T_OPEN = 1,
+ T_SUCCESS = 0,
+ T_ERROR,
+ T_OPEN,
T_CREATE,
+ T_MKNOD,
+ T_MKDIR,
+ T_SYMLINK,
+ T_LINK,
};
#endif
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 06/12] hw/9pfs: Add stat/readlink/statfs for proxy FS
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (4 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 05/12] hw/9pfs: Create other filesystem objects M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 07/12] hw/9pfs: File ownership and others M. Mohan Kumar
` (7 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
fsdev/virtfs-proxy-helper.c | 165 ++++++++++++++++++++++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.c | 174 +++++++++++++++++++++++++++++++++++++++++--
hw/9pfs/virtio-9p-proxy.h | 34 +++++++++
3 files changed, 367 insertions(+), 6 deletions(-)
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 377e91a..eb33504 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -27,6 +27,8 @@
#include <stdarg.h>
#include "bswap.h"
#include <sys/socket.h>
+#include <sys/vfs.h>
+#include <sys/stat.h>
#include "qemu-common.h"
#include "virtio-9p-marshal.h"
#include "hw/9pfs/virtio-9p-proxy.h"
@@ -251,6 +253,154 @@ static int setfsugid(int uid, int gid)
}
/*
+ * send response in two parts
+ * 1) ProxyHeader
+ * 2) Response or error status
+ * This function should be called with marshaling response
+ * send_response constructs header part and error part only.
+ * send response sends {ProxyHeader,Response} if the request was success
+ * otherwise sends {ProxyHeader,error status}
+ */
+static int send_response(int sock, struct iovec *iovec, int size)
+{
+ int retval;
+ ProxyHeader header;
+
+ if (size < 0) {
+ header.type = T_ERROR;
+ header.size = sizeof(size);
+ proxy_marshal(iovec, 1, HDR_SZ, "d", size);
+ } else {
+ header.type = T_SUCCESS;
+ header.size = size;
+ }
+
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ retval = socket_write(sock, iovec->iov_base, header.size + HDR_SZ);
+ if (retval != header.size + HDR_SZ) {
+ return -EIO;
+ }
+ return 0;
+}
+
+static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat)
+{
+ memset(pr_stat, 0, sizeof(*pr_stat));
+ pr_stat->st_dev = stat->st_dev;
+ pr_stat->st_ino = stat->st_ino;
+ pr_stat->st_nlink = stat->st_nlink;
+ pr_stat->st_mode = stat->st_mode;
+ pr_stat->st_uid = stat->st_uid;
+ pr_stat->st_gid = stat->st_gid;
+ pr_stat->st_rdev = stat->st_rdev;
+ pr_stat->st_size = stat->st_size;
+ pr_stat->st_blksize = stat->st_blksize;
+ pr_stat->st_blocks = stat->st_blocks;
+ pr_stat->st_atim_sec = stat->st_atim.tv_sec;
+ pr_stat->st_atim_nsec = stat->st_atim.tv_nsec;
+ pr_stat->st_mtim_sec = stat->st_mtim.tv_sec;
+ pr_stat->st_mtim_nsec = stat->st_mtim.tv_nsec;
+ pr_stat->st_ctim_sec = stat->st_ctim.tv_sec;
+ pr_stat->st_ctim_nsec = stat->st_ctim.tv_nsec;
+}
+
+static void statfs_to_prstatfs(ProxyStatFS *pr_stfs, struct statfs *stfs)
+{
+ memset(pr_stfs, 0, sizeof(*pr_stfs));
+ pr_stfs->f_type = stfs->f_type;
+ pr_stfs->f_bsize = stfs->f_bsize;
+ pr_stfs->f_blocks = stfs->f_blocks;
+ pr_stfs->f_bfree = stfs->f_bfree;
+ pr_stfs->f_bavail = stfs->f_bavail;
+ pr_stfs->f_files = stfs->f_files;
+ pr_stfs->f_ffree = stfs->f_ffree;
+ pr_stfs->f_fsid[0] = stfs->f_fsid.__val[0];
+ pr_stfs->f_fsid[1] = stfs->f_fsid.__val[1];
+ pr_stfs->f_namelen = stfs->f_namelen;
+ pr_stfs->f_frsize = stfs->f_frsize;
+}
+
+/*
+ * Gets stat/statfs information and packs in out_iovec structure
+ * on success returns number of bytes packed in out_iovec struture
+ * otherwise returns -errno
+ */
+static int do_stat(int type, struct iovec *iovec, struct iovec *out_iovec)
+{
+ V9fsString path;
+ int retval = 0;
+
+ proxy_unmarshal(iovec, 1, HDR_SZ, "s", &path);
+
+ switch (type) {
+ case T_LSTAT: {
+ struct stat st_buf;
+ ProxyStat pr_stat;
+
+ retval = lstat(path.data, &st_buf);
+ if (retval < 0) {
+ retval = -errno;
+ } else {
+ stat_to_prstat(&pr_stat, &st_buf);
+ retval = proxy_marshal(out_iovec, 1, HDR_SZ,
+ "qqqdddqqqqqqqqqq", pr_stat.st_dev,
+ pr_stat.st_ino, pr_stat.st_nlink,
+ pr_stat.st_mode, pr_stat.st_uid,
+ pr_stat.st_gid, pr_stat.st_rdev,
+ pr_stat.st_size, pr_stat.st_blksize,
+ pr_stat.st_blocks,
+ pr_stat.st_atim_sec, pr_stat.st_atim_nsec,
+ pr_stat.st_mtim_sec, pr_stat.st_mtim_nsec,
+ pr_stat.st_ctim_sec, pr_stat.st_ctim_nsec);
+ }
+ break;
+ }
+ case T_STATFS: {
+ struct statfs stfs_buf;
+ ProxyStatFS pr_stfs;
+
+ retval = statfs(path.data, &stfs_buf);
+ if (retval < 0) {
+ retval = -errno;
+ } else {
+ statfs_to_prstatfs(&pr_stfs, &stfs_buf);
+ retval = proxy_marshal(out_iovec, 1, HDR_SZ,
+ "qqqqqqqqqqq", pr_stfs.f_type, pr_stfs.f_bsize,
+ pr_stfs.f_blocks, pr_stfs.f_bfree, pr_stfs.f_bavail,
+ pr_stfs.f_files, pr_stfs.f_ffree,
+ pr_stfs.f_fsid[0], pr_stfs.f_fsid[1],
+ pr_stfs.f_namelen, pr_stfs.f_frsize);
+ }
+ break;
+ }
+ }
+ v9fs_string_free(&path);
+ return retval;
+}
+
+static int do_readlink(struct iovec *iovec, struct iovec *out_iovec)
+{
+ V9fsString target, path;
+ int size, retval;
+ char *buffer;
+
+ proxy_unmarshal(iovec, 1, HDR_SZ, "sd", &path, &size);
+ buffer = g_malloc(size);
+ v9fs_string_init(&target);
+ retval = readlink(path.data, buffer, size);
+ if (retval > 0) {
+ buffer[retval] = '\0';
+ v9fs_string_sprintf(&target, "%s", buffer);
+ retval = proxy_marshal(out_iovec, 1, HDR_SZ, "s", &target);
+ } else {
+ retval = -errno;
+ }
+ v9fs_string_free(&target);
+ v9fs_string_free(&path);
+ return retval;
+}
+
+/*
* create a other filesystem objects and send 0 on success
* return -errno on error
*/
@@ -348,6 +498,7 @@ static int process_requests(int sock)
int type, retval = 0;
V9fsString oldpath, path;
struct iovec in_iovec, out_iovec;
+ int size = 0;
in_iovec.iov_base = g_malloc(BUFF_SZ);
in_iovec.iov_len = BUFF_SZ;
@@ -377,6 +528,13 @@ static int process_requests(int sock)
v9fs_string_free(&oldpath);
v9fs_string_free(&path);
break;
+ case T_LSTAT:
+ case T_STATFS:
+ size = do_stat(type, &in_iovec, &out_iovec);
+ break;
+ case T_READLINK:
+ size = do_readlink(&in_iovec, &out_iovec);
+ break;
default:
goto error;
break;
@@ -394,6 +552,13 @@ static int process_requests(int sock)
case T_LINK:
send_status(sock, &out_iovec, retval);
break;
+ case T_LSTAT:
+ case T_STATFS:
+ case T_READLINK:
+ if (send_response(sock, &out_iovec, size) < 0) {
+ goto error;
+ }
+ break;
default:
goto error;
break;
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index 683d762..090db44 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -89,6 +89,120 @@ static ssize_t socket_read(int sockfd, void *buff, size_t size)
return retval;
}
+/* Converts proxy_statfs to VFS statfs structure */
+static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
+{
+ memset(stfs, 0, sizeof(*stfs));
+ stfs->f_type = prstfs->f_type;
+ stfs->f_bsize = prstfs->f_bsize;
+ stfs->f_blocks = prstfs->f_blocks;
+ stfs->f_bfree = prstfs->f_bfree;
+ stfs->f_bavail = prstfs->f_bavail;
+ stfs->f_files = prstfs->f_files;
+ stfs->f_ffree = prstfs->f_ffree;
+ stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFUL;
+ stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFFUL;
+ stfs->f_namelen = prstfs->f_namelen;
+ stfs->f_frsize = prstfs->f_frsize;
+}
+
+/* Converts proxy_stat structure to VFS stat structure */
+static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
+{
+ memset(stbuf, 0, sizeof(*stbuf));
+ stbuf->st_dev = prstat->st_dev;
+ stbuf->st_ino = prstat->st_ino;
+ stbuf->st_nlink = prstat->st_nlink;
+ stbuf->st_mode = prstat->st_mode;
+ stbuf->st_uid = prstat->st_uid;
+ stbuf->st_gid = prstat->st_gid;
+ stbuf->st_rdev = prstat->st_rdev;
+ stbuf->st_size = prstat->st_size;
+ stbuf->st_blksize = prstat->st_blksize;
+ stbuf->st_blocks = prstat->st_blocks;
+ stbuf->st_atim.tv_sec = prstat->st_atim_sec;
+ stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
+ stbuf->st_mtime = prstat->st_mtim_sec;
+ stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
+ stbuf->st_ctime = prstat->st_ctim_sec;
+ stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
+}
+
+/*
+ * Response contains two parts
+ * {header, data}
+ * header.type == T_ERROR, data -> -errno
+ * header.type == T_SUCCESS, data -> response
+ * size of errno/response is given by header.size
+ */
+static int v9fs_receive_response(V9fsProxy *proxy, int type,
+ int *sock_error, void *response)
+{
+ int retval, error;
+ ProxyHeader header;
+ struct iovec *reply = &proxy->in_iovec;
+
+ *sock_error = 0;
+
+ retval = socket_read(proxy->sockfd, reply->iov_base, HDR_SZ);
+ if (retval != HDR_SZ) {
+ *sock_error = 1;
+ return -EIO;
+ }
+ proxy_unmarshal(reply, 1, 0, "dd", &header.type, &header.size);
+
+ retval = socket_read(proxy->sockfd, reply->iov_base + HDR_SZ, header.size);
+ if (retval != header.size) {
+ *sock_error = 1;
+ return -EIO;
+ }
+ /* there was an error during processing request */
+ if (header.type == T_ERROR) {
+ proxy_unmarshal(reply, 1, HDR_SZ, "d", &error);
+ return error;
+ }
+
+ switch (type) {
+ case T_LSTAT: {
+ ProxyStat prstat;
+ proxy_unmarshal(reply, 1, HDR_SZ,
+ "qqqdddqqqqqqqqqq", &prstat.st_dev,
+ &prstat.st_ino, &prstat.st_nlink,
+ &prstat.st_mode, &prstat.st_uid,
+ &prstat.st_gid, &prstat.st_rdev,
+ &prstat.st_size, &prstat.st_blksize,
+ &prstat.st_blocks,
+ &prstat.st_atim_sec, &prstat.st_atim_nsec,
+ &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
+ &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
+ prstat_to_stat(response, &prstat);
+ break;
+ }
+ case T_STATFS: {
+ ProxyStatFS prstfs;
+ proxy_unmarshal(reply, 1, HDR_SZ,
+ "qqqqqqqqqqq", &prstfs.f_type, &prstfs.f_bsize,
+ &prstfs.f_blocks, &prstfs.f_bfree, &prstfs.f_bavail,
+ &prstfs.f_files, &prstfs.f_ffree,
+ &prstfs.f_fsid[0], &prstfs.f_fsid[1],
+ &prstfs.f_namelen, &prstfs.f_frsize);
+ prstatfs_to_statfs(response, &prstfs);
+ break;
+ }
+ case T_READLINK: {
+ V9fsString target;
+ proxy_unmarshal(reply, 1, HDR_SZ, "s", &target);
+ strcpy(response, target.data);
+ v9fs_string_free(&target);
+ break;
+ }
+ default:
+ *sock_error = 1;
+ return -1;
+ }
+
+ return 0;
+}
static int v9fs_receive_status(V9fsProxy *proxy, int *sock_error,
struct iovec *reply)
@@ -127,6 +241,7 @@ static int v9fs_request(V9fsProxy *proxy, int type,
int sock_error, flags, mode, uid, gid;
struct iovec *iovec = NULL, *reply = NULL;
dev_t rdev;
+ int size = 0;
qemu_mutex_lock(&proxy->mutex);
@@ -201,6 +316,29 @@ static int v9fs_request(V9fsProxy *proxy, int type,
proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
header.size += HDR_SZ;
break;
+ case T_LSTAT:
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path);
+ header.type = T_LSTAT;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_READLINK:
+ path = va_arg(ap, V9fsString *);
+ size = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sd",
+ path, size);
+ header.type = T_READLINK;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_STATFS:
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path);
+ header.type = T_STATFS;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
default:
error_report("Invalid type %d\n", type);
va_end(ap);
@@ -235,6 +373,14 @@ static int v9fs_request(V9fsProxy *proxy, int type,
goto close_error;
}
break;
+ case T_LSTAT:
+ case T_READLINK:
+ case T_STATFS:
+ retval = v9fs_receive_response(proxy, type, &sock_error, response);
+ if (sock_error) {
+ goto close_error;
+ }
+ break;
}
qemu_mutex_unlock(&proxy->mutex);
return retval;
@@ -248,15 +394,26 @@ error:
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
+ if (retval < 0) {
+ errno = -retval;
+ return -1;
+ }
+ return retval;
}
static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char *buf, size_t bufsz)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
+ fs_path, bufsz);
+ if (retval < 0) {
+ errno = -retval;
+ return -1;
+ }
+ return strlen(buf);
}
static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
@@ -528,8 +685,13 @@ static int proxy_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
+ if (retval < 0) {
+ errno = -retval;
+ return -1;
+ }
+ return retval;
}
static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index 32610e0..578ca19 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -30,6 +30,40 @@ enum {
T_MKDIR,
T_SYMLINK,
T_LINK,
+ T_LSTAT,
+ T_READLINK,
+ T_STATFS,
};
+typedef struct {
+ uint64_t st_dev;
+ uint64_t st_ino;
+ uint64_t st_nlink;
+ uint32_t st_mode;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_atim_sec;
+ uint64_t st_atim_nsec;
+ uint64_t st_mtim_sec;
+ uint64_t st_mtim_nsec;
+ uint64_t st_ctim_sec;
+ uint64_t st_ctim_nsec;
+} ProxyStat;
+
+typedef struct {
+ uint64_t f_type;
+ uint64_t f_bsize;
+ uint64_t f_blocks;
+ uint64_t f_bfree;
+ uint64_t f_bavail;
+ uint64_t f_files;
+ uint64_t f_ffree;
+ uint64_t f_fsid[2];
+ uint64_t f_namelen;
+ uint64_t f_frsize;
+} ProxyStatFS;
#endif
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 07/12] hw/9pfs: File ownership and others
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (5 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 06/12] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 08/12] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
` (6 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add file ownership interfaces like chmod/chown, utime update, rename,
remove and truncating files for proxy FS
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
Makefile | 2 +-
fsdev/virtfs-proxy-helper.c | 66 +++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.c | 134 +++++++++++++++++++++++++++++++++++++++----
hw/9pfs/virtio-9p-proxy.h | 6 ++
4 files changed, 195 insertions(+), 13 deletions(-)
diff --git a/Makefile b/Makefile
index 19b481a..378ee4d 100644
--- a/Makefile
+++ b/Makefile
@@ -153,7 +153,7 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
-fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o
+fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index eb33504..ded0ead 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -495,6 +495,9 @@ static void usage(char *prog)
static int process_requests(int sock)
{
+ uint64_t offset;
+ int mode, uid, gid;
+ struct timespec spec[2];
int type, retval = 0;
V9fsString oldpath, path;
struct iovec in_iovec, out_iovec;
@@ -535,6 +538,63 @@ static int process_requests(int sock)
case T_READLINK:
size = do_readlink(&in_iovec, &out_iovec);
break;
+ case T_CHMOD:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sd",
+ &path, &mode);
+ retval = chmod(path.data, mode);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ break;
+ case T_CHOWN:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sdd", &path,
+ &uid, &gid);
+ retval = lchown(path.data, uid, gid);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ break;
+ case T_TRUNCATE:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sq",
+ &path, &offset);
+ retval = truncate(path.data, offset);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ break;
+ case T_UTIME:
+ proxy_unmarshal(&in_iovec, 1,
+ HDR_SZ, "sqqqq", &path,
+ &spec[0].tv_sec, &spec[0].tv_nsec,
+ &spec[1].tv_sec, &spec[1].tv_nsec);
+ retval = qemu_utimensat(AT_FDCWD, path.data, spec,
+ AT_SYMLINK_NOFOLLOW);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ break;
+ case T_RENAME:
+ proxy_unmarshal(&in_iovec, 1,
+ HDR_SZ, "ss", &oldpath, &path);
+ retval = rename(oldpath.data, path.data);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&oldpath);
+ v9fs_string_free(&path);
+ break;
+ case T_REMOVE:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ, "s", &path);
+ retval = remove(path.data);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ break;
default:
goto error;
break;
@@ -550,6 +610,12 @@ static int process_requests(int sock)
case T_MKDIR:
case T_SYMLINK:
case T_LINK:
+ case T_CHMOD:
+ case T_CHOWN:
+ case T_TRUNCATE:
+ case T_UTIME:
+ case T_RENAME:
+ case T_REMOVE:
send_status(sock, &out_iovec, retval);
break;
case T_LSTAT:
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index 090db44..aefdc61 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -242,6 +242,8 @@ static int v9fs_request(V9fsProxy *proxy, int type,
struct iovec *iovec = NULL, *reply = NULL;
dev_t rdev;
int size = 0;
+ struct timespec spec[2];
+ uint64_t offset;
qemu_mutex_lock(&proxy->mutex);
@@ -339,6 +341,63 @@ static int v9fs_request(V9fsProxy *proxy, int type,
proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
header.size += HDR_SZ;
break;
+ case T_CHMOD:
+ path = va_arg(ap, V9fsString *);
+ mode = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sd",
+ path, mode);
+ header.type = T_CHMOD;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_CHOWN:
+ path = va_arg(ap, V9fsString *);
+ uid = va_arg(ap, int);
+ gid = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sdd",
+ path, uid, gid);
+ header.type = T_CHOWN;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_TRUNCATE:
+ path = va_arg(ap, V9fsString *);
+ offset = va_arg(ap, uint64_t);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sq",
+ path, offset);
+ header.type = T_TRUNCATE;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_UTIME:
+ path = va_arg(ap, V9fsString *);
+ spec[0].tv_sec = va_arg(ap, long);
+ spec[0].tv_nsec = va_arg(ap, long);
+ spec[1].tv_sec = va_arg(ap, long);
+ spec[1].tv_nsec = va_arg(ap, long);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sqqqq",
+ path, spec[0].tv_sec, spec[1].tv_nsec,
+ spec[1].tv_sec, spec[1].tv_nsec);
+ header.type = T_UTIME;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_RENAME:
+ oldpath = va_arg(ap, V9fsString *);
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ss",
+ oldpath, path);
+ header.type = T_RENAME;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_REMOVE:
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path);
+ header.type = T_REMOVE;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
default:
error_report("Invalid type %d\n", type);
va_end(ap);
@@ -368,6 +427,12 @@ static int v9fs_request(V9fsProxy *proxy, int type,
case T_MKDIR:
case T_SYMLINK:
case T_LINK:
+ case T_CHMOD:
+ case T_CHOWN:
+ case T_RENAME:
+ case T_TRUNCATE:
+ case T_UTIME:
+ case T_REMOVE:
retval = v9fs_receive_status(proxy, &sock_error, reply);
if (sock_error) {
goto close_error;
@@ -530,8 +595,13 @@ static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
+ fs_path, credp->fc_mode);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
@@ -644,34 +714,74 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+
+ retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
+ if (retval < 0) {
+ errno = -retval;
+ return -1;
+ }
+ return 0;
}
static int proxy_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString oldname, newname;
+
+ v9fs_string_init(&oldname);
+ v9fs_string_init(&newname);
+
+ v9fs_string_sprintf(&oldname, "%s", oldpath);
+ v9fs_string_sprintf(&newname, "%s", newpath);
+ retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
+ &oldname, &newname);
+ v9fs_string_free(&oldname);
+ v9fs_string_free(&newname);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
+ fs_path, credp->fc_uid, credp->fc_gid);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
const struct timespec *buf)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
+ fs_path,
+ buf[0].tv_sec, buf[0].tv_nsec,
+ buf[1].tv_sec, buf[1].tv_nsec);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_remove(FsContext *ctx, const char *path)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString name;
+ v9fs_string_init(&name);
+ v9fs_string_sprintf(&name, "%s", path);
+ retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
+ v9fs_string_free(&name);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync)
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index 578ca19..ef8a0f3 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -33,6 +33,12 @@ enum {
T_LSTAT,
T_READLINK,
T_STATFS,
+ T_CHMOD,
+ T_CHOWN,
+ T_TRUNCATE,
+ T_UTIME,
+ T_RENAME,
+ T_REMOVE,
};
typedef struct {
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 08/12] hw/9pfs: xattr interfaces in proxy filesystem driver
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (6 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 07/12] hw/9pfs: File ownership and others M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 09/12] hw/9pfs: Proxy getversion M. Mohan Kumar
` (5 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add xattr support for proxy FS
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
fsdev/virtfs-proxy-helper.c | 78 ++++++++++++++++++++++++++++-
hw/9pfs/virtio-9p-proxy.c | 119 +++++++++++++++++++++++++++++++++++++++----
hw/9pfs/virtio-9p-proxy.h | 4 ++
3 files changed, 190 insertions(+), 11 deletions(-)
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index ded0ead..ccd7ed8 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -29,6 +29,7 @@
#include <sys/socket.h>
#include <sys/vfs.h>
#include <sys/stat.h>
+#include <attr/xattr.h>
#include "qemu-common.h"
#include "virtio-9p-marshal.h"
#include "hw/9pfs/virtio-9p-proxy.h"
@@ -283,6 +284,50 @@ static int send_response(int sock, struct iovec *iovec, int size)
return 0;
}
+static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec)
+{
+ int size = 0, offset, retval;
+ V9fsString path, name, xattr;
+
+ v9fs_string_init(&xattr);
+
+ offset = HDR_SZ;
+ offset += proxy_unmarshal(iovec, 1, HDR_SZ, "ds", &size, &path);
+ if (size) {
+ xattr.data = g_malloc(size);
+ xattr.size = size;
+ }
+ switch (type) {
+ case T_LGETXATTR:
+ proxy_unmarshal(iovec, 1, offset, "s", &name);
+ retval = lgetxattr(path.data, name.data, xattr.data, size);
+ if (retval < 0) {
+ retval = -errno;
+ v9fs_string_free(&name);
+ goto error;
+ }
+ v9fs_string_free(&name);
+ break;
+ case T_LLISTXATTR:
+ retval = llistxattr(path.data, xattr.data, size);
+ if (retval < 0) {
+ retval = -errno;
+ goto error;
+ }
+ break;
+ }
+
+ if (!size) {
+ proxy_marshal(out_iovec, 1, HDR_SZ, "d", retval);
+ retval = sizeof(retval);
+ } else {
+ retval = proxy_marshal(out_iovec, 1, HDR_SZ, "s", &xattr);
+ }
+error:
+ v9fs_string_free(&path);
+ return retval;
+}
+
static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat)
{
memset(pr_stat, 0, sizeof(*pr_stat));
@@ -499,9 +544,10 @@ static int process_requests(int sock)
int mode, uid, gid;
struct timespec spec[2];
int type, retval = 0;
+ V9fsString name, value;
V9fsString oldpath, path;
struct iovec in_iovec, out_iovec;
- int size = 0;
+ int size = 0, flags;
in_iovec.iov_base = g_malloc(BUFF_SZ);
in_iovec.iov_len = BUFF_SZ;
@@ -595,6 +641,32 @@ static int process_requests(int sock)
}
v9fs_string_free(&path);
break;
+ case T_LGETXATTR:
+ case T_LLISTXATTR:
+ size = do_getxattr(type, &in_iovec, &out_iovec);
+ break;
+ case T_LSETXATTR:
+ proxy_unmarshal(&in_iovec, 1, HDR_SZ,
+ "sssdd", &path, &name, &value, &size,
+ &flags);
+ retval = lsetxattr(path.data, name.data, value.data, size, flags);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ v9fs_string_free(&name);
+ v9fs_string_free(&value);
+ break;
+ case T_LREMOVEXATTR:
+ proxy_unmarshal(&in_iovec, 1,
+ HDR_SZ, "ss", &path, &name);
+ retval = lremovexattr(path.data, name.data);
+ if (retval < 0) {
+ retval = -errno;
+ }
+ v9fs_string_free(&path);
+ v9fs_string_free(&name);
+ break;
default:
goto error;
break;
@@ -616,11 +688,15 @@ static int process_requests(int sock)
case T_UTIME:
case T_RENAME:
case T_REMOVE:
+ case T_LSETXATTR:
+ case T_LREMOVEXATTR:
send_status(sock, &out_iovec, retval);
break;
case T_LSTAT:
case T_STATFS:
case T_READLINK:
+ case T_LGETXATTR:
+ case T_LLISTXATTR:
if (send_response(sock, &out_iovec, size) < 0) {
goto error;
}
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index aefdc61..f672ac3 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -136,7 +136,7 @@ static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
* size of errno/response is given by header.size
*/
static int v9fs_receive_response(V9fsProxy *proxy, int type,
- int *sock_error, void *response)
+ int *sock_error, int size, void *response)
{
int retval, error;
ProxyHeader header;
@@ -196,6 +196,19 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
v9fs_string_free(&target);
break;
}
+ case T_LGETXATTR:
+ case T_LLISTXATTR: {
+ V9fsString xattr;
+ if (!size) {
+ proxy_unmarshal(reply, 1, HDR_SZ, "d", &size);
+ return size;
+ } else {
+ proxy_unmarshal(reply, 1, HDR_SZ, "s", &xattr);
+ memcpy(response, xattr.data, xattr.size);
+ v9fs_string_free(&xattr);
+ }
+ break;
+ }
default:
*sock_error = 1;
return -1;
@@ -244,6 +257,7 @@ static int v9fs_request(V9fsProxy *proxy, int type,
int size = 0;
struct timespec spec[2];
uint64_t offset;
+ V9fsString *name, *value;
qemu_mutex_lock(&proxy->mutex);
@@ -398,6 +412,44 @@ static int v9fs_request(V9fsProxy *proxy, int type,
proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
header.size += HDR_SZ;
break;
+ case T_LGETXATTR:
+ size = va_arg(ap, int);
+ path = va_arg(ap, V9fsString *);
+ name = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "dss", size,
+ path, name);
+ header.type = T_LGETXATTR;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_LLISTXATTR:
+ size = va_arg(ap, int);
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ds", size, path);
+ header.type = T_LLISTXATTR;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_LSETXATTR:
+ path = va_arg(ap, V9fsString *);
+ name = va_arg(ap, V9fsString *);
+ value = va_arg(ap, V9fsString *);
+ size = va_arg(ap, int);
+ flags = va_arg(ap, int);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "sssdd",
+ path, name, value, size, flags);
+ header.type = T_LSETXATTR;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
+ case T_LREMOVEXATTR:
+ path = va_arg(ap, V9fsString *);
+ name = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "ss", path, name);
+ header.type = T_LREMOVEXATTR;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
default:
error_report("Invalid type %d\n", type);
va_end(ap);
@@ -433,6 +485,8 @@ static int v9fs_request(V9fsProxy *proxy, int type,
case T_TRUNCATE:
case T_UTIME:
case T_REMOVE:
+ case T_LSETXATTR:
+ case T_LREMOVEXATTR:
retval = v9fs_receive_status(proxy, &sock_error, reply);
if (sock_error) {
goto close_error;
@@ -441,7 +495,10 @@ static int v9fs_request(V9fsProxy *proxy, int type,
case T_LSTAT:
case T_READLINK:
case T_STATFS:
- retval = v9fs_receive_response(proxy, type, &sock_error, response);
+ case T_LGETXATTR:
+ case T_LLISTXATTR:
+ retval = v9fs_receive_response(proxy, type, &sock_error, size,
+ response);
if (sock_error) {
goto close_error;
}
@@ -807,29 +864,71 @@ static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
const char *name, void *value, size_t size)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString xname;
+
+ v9fs_string_init(&xname);
+ v9fs_string_sprintf(&xname, "%s", name);
+ retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
+ fs_path, &xname);
+ v9fs_string_free(&xname);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
void *value, size_t size)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
+ fs_path);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
void *value, size_t size, int flags)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString xname, xvalue;
+
+ v9fs_string_init(&xname);
+ v9fs_string_sprintf(&xname, "%s", name);
+
+ v9fs_string_init(&xvalue);
+ xvalue.size = size;
+ xvalue.data = g_malloc(size);
+ memcpy(xvalue.data, value, size);
+
+ retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
+ fs_path, &xname, &xvalue, size, flags);
+ v9fs_string_free(&xname);
+ v9fs_string_free(&xvalue);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
const char *name)
{
- errno = EOPNOTSUPP;
- return -1;
+ int retval;
+ V9fsString xname;
+
+ v9fs_string_init(&xname);
+ v9fs_string_sprintf(&xname, "%s", name);
+ retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
+ fs_path, &xname);
+ v9fs_string_free(&xname);
+ if (retval < 0) {
+ errno = -retval;
+ }
+ return retval;
}
static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index ef8a0f3..4c691a8 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -39,6 +39,10 @@ enum {
T_UTIME,
T_RENAME,
T_REMOVE,
+ T_LGETXATTR,
+ T_LLISTXATTR,
+ T_LSETXATTR,
+ T_LREMOVEXATTR,
};
typedef struct {
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 09/12] hw/9pfs: Proxy getversion
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (7 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 08/12] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 10/12] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
` (4 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add proxy getversion to get generation number
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
fsdev/virtfs-proxy-helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.c | 31 ++++++++++++++++++
hw/9pfs/virtio-9p-proxy.h | 1 +
3 files changed, 106 insertions(+), 0 deletions(-)
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index ccd7ed8..917bb26 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -30,6 +30,11 @@
#include <sys/vfs.h>
#include <sys/stat.h>
#include <attr/xattr.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#ifdef CONFIG_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
#include "qemu-common.h"
#include "virtio-9p-marshal.h"
#include "hw/9pfs/virtio-9p-proxy.h"
@@ -38,6 +43,19 @@
#define PROGNAME "virtfs-proxy-helper"
+#ifndef XFS_SUPER_MAGIC
+#define XFS_SUPER_MAGIC 0x58465342
+#endif
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC 0xEF53
+#endif
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC 0x52654973
+#endif
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC 0x9123683E
+#endif
+
static struct option helper_opts[] = {
{"fd", required_argument, NULL, 'f'},
{"path", required_argument, NULL, 'p'},
@@ -45,6 +63,7 @@ static struct option helper_opts[] = {
};
int is_daemon;
+int get_version; /* IOC getversion IOCTL supported */
static void do_perror(const char *string)
{
@@ -284,6 +303,42 @@ static int send_response(int sock, struct iovec *iovec, int size)
return 0;
}
+/*
+ * gets generation number
+ * returns -errno on failure and sizeof(generation number) on success
+ */
+static int do_getversion(struct iovec *iovec, struct iovec *out_iovec)
+{
+ int fd, retval;
+ uint64_t version;
+ V9fsString path;
+
+ retval = sizeof(version);
+ /* no need to issue ioctl */
+ if (!get_version) {
+ version = 0;
+ proxy_marshal(out_iovec, 1, HDR_SZ, "q", version);
+ return retval;
+ }
+
+ proxy_unmarshal(iovec, 1, HDR_SZ, "s", &path);
+
+ fd = open(path.data, O_RDONLY);
+ if (fd < 0) {
+ retval = -errno;
+ goto done;
+ }
+ if (ioctl(fd, FS_IOC_GETVERSION, &version) < 0) {
+ retval = -errno;
+ } else {
+ proxy_marshal(out_iovec, 1, HDR_SZ, "q", version);
+ }
+ close(fd);
+done:
+ v9fs_string_free(&path);
+ return retval;
+}
+
static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec)
{
int size = 0, offset, retval;
@@ -667,6 +722,9 @@ static int process_requests(int sock)
v9fs_string_free(&path);
v9fs_string_free(&name);
break;
+ case T_GETVERSION:
+ size = do_getversion(&in_iovec, &out_iovec);
+ break;
default:
goto error;
break;
@@ -697,6 +755,7 @@ static int process_requests(int sock)
case T_READLINK:
case T_LGETXATTR:
case T_LLISTXATTR:
+ case T_GETVERSION:
if (send_response(sock, &out_iovec, size) < 0) {
goto error;
}
@@ -718,6 +777,8 @@ int main(int argc, char **argv)
char rpath[PATH_MAX];
struct stat stbuf;
int c, option_index;
+ int retval;
+ struct statfs st_fs;
is_daemon = 1;
rpath[0] = '\0';
@@ -775,6 +836,19 @@ int main(int argc, char **argv)
do_log(LOG_INFO, "Started");
+ /* check whether underlying FS support IOC_GETVERSION */
+ retval = statfs(rpath, &st_fs);
+ if (!retval) {
+ switch (st_fs.f_type) {
+ case EXT2_SUPER_MAGIC:
+ case BTRFS_SUPER_MAGIC:
+ case REISERFS_SUPER_MAGIC:
+ case XFS_SUPER_MAGIC:
+ get_version = 1;
+ break;
+ }
+ }
+
if (chroot(rpath) < 0) {
do_perror("chroot");
goto error;
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index f672ac3..bc63835 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -209,6 +209,9 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type,
}
break;
}
+ case T_GETVERSION:
+ proxy_unmarshal(reply, 1, HDR_SZ, "q", response);
+ break;
default:
*sock_error = 1;
return -1;
@@ -450,6 +453,13 @@ static int v9fs_request(V9fsProxy *proxy, int type,
proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
header.size += HDR_SZ;
break;
+ case T_GETVERSION:
+ path = va_arg(ap, V9fsString *);
+ header.size = proxy_marshal(iovec, 1, HDR_SZ, "s", path);
+ header.type = T_GETVERSION;
+ proxy_marshal(iovec, 1, 0, "dd", header.type, header.size);
+ header.size += HDR_SZ;
+ break;
default:
error_report("Invalid type %d\n", type);
va_end(ap);
@@ -497,6 +507,7 @@ static int v9fs_request(V9fsProxy *proxy, int type,
case T_STATFS:
case T_LGETXATTR:
case T_LLISTXATTR:
+ case T_GETVERSION:
retval = v9fs_receive_response(proxy, type, &sock_error, size,
response);
if (sock_error) {
@@ -978,6 +989,25 @@ static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
return ret;
}
+static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
+ mode_t st_mode, uint64_t *st_gen)
+{
+ int err;
+
+ /* Do not try to open special files like device nodes, fifos etc
+ * we can get fd for regular files and directories only
+ */
+ if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
+ return 0;
+ }
+ err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
+ if (err < 0) {
+ errno = -err;
+ err = -1;
+ }
+ return err;
+}
+
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
{
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
@@ -1012,6 +1042,7 @@ static int proxy_init(FsContext *ctx)
qemu_mutex_init(&proxy->mutex);
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
+ ctx->exops.get_st_gen = proxy_ioc_getversion;
return 0;
}
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index 4c691a8..37c260b 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -43,6 +43,7 @@ enum {
T_LLISTXATTR,
T_LSETXATTR,
T_LREMOVEXATTR,
+ T_GETVERSION,
};
typedef struct {
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 10/12] hw/9pfs: Documentation changes related to proxy fs
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (8 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 09/12] hw/9pfs: Proxy getversion M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 11/12] hw/9pfs: man page for proxy helper M. Mohan Kumar
` (3 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
qemu-options.hx | 25 ++++++++++++++++---------
1 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/qemu-options.hx b/qemu-options.hx
index 681eaf1..cde17ed 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -530,19 +530,19 @@ DEFHEADING()
DEFHEADING(File system options:)
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
- "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
- " [,writeout=immediate][,readonly]\n",
+ "-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n"
+ " [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
QEMU_ARCH_ALL)
STEXI
-@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly]
+@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
@findex -fsdev
Define a new file system device. Valid options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
-Currently "local" and "handle" file system drivers are supported.
+Currently "local", "handle" and "proxy" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
@@ -559,7 +559,7 @@ file attributes. Directories exported by this security model cannot
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory
-only for local fsdriver. Other fsdrivers (like handle) don't take
+only for local fsdriver. Other fsdrivers (like handle, proxy) don't take
security model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
@@ -569,6 +569,10 @@ reported as written by the storage subsystem.
@item readonly
Enables exporting 9p share as a readonly mount for guests. By default
read-write access is given.
+@item sock_fd=@var{sock_fd}
+Enables proxy filesystem driver to use passed socket descriptor for
+communicating with virtfs-proxy-helper. Usually a helper like libvirt
+will create socketpair and pass one of the fds as sock_fd
@end table
-fsdev option is used along with -device driver "virtio-9p-pci".
@@ -589,19 +593,19 @@ DEFHEADING(Virtual File system pass-through options:)
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
- " [,writeout=immediate][,readonly]\n",
+ " [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
QEMU_ARCH_ALL)
STEXI
-@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}][,readonly]
+@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
@findex -virtfs
The general form of a Virtual File system pass-through options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
-Currently "local" and "handle" file system drivers are supported.
+Currently "local", "handle" and "proxy" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
@@ -618,7 +622,7 @@ file attributes. Directories exported by this security model cannot
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory only
-for local fsdriver. Other fsdrivers (like handle) don't take security
+for local fsdriver. Other fsdrivers (like handle, proxy) don't take security
model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
@@ -628,6 +632,9 @@ reported as written by the storage subsystem.
@item readonly
Enables exporting 9p share as a readonly mount for guests. By default
read-write access is given.
+@item sock_fd
+Enables proxy filesystem driver to use passed 'sock_fd' as the socket
+descriptor for interfacing with virtfs-proxy-helper
@end table
ETEXI
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 11/12] hw/9pfs: man page for proxy helper
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (9 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 10/12] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 12/12] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar
` (2 subsequent siblings)
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
Makefile | 12 +++++++-
fsdev/virtfs-proxy-helper.texi | 59 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 1 deletions(-)
create mode 100644 fsdev/virtfs-proxy-helper.texi
diff --git a/Makefile b/Makefile
index 378ee4d..29ae332 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,7 @@ LIBS+=-lz $(LIBS_TOOLS)
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
+DOCS+=fsdev/virtfs-proxy-helper.1
else
DOCS=
endif
@@ -280,7 +281,10 @@ ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
-
+ifdef CONFIG_VIRTFS
+ $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
+endif
install-sysconfig:
$(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
@@ -358,6 +362,12 @@ qemu-img.1: qemu-img.texi qemu-img-cmds.texi
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
" GEN $@")
+fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
+ $(call quiet-command, \
+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
+ pod2man --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
+ " GEN $@")
+
qemu-nbd.8: qemu-nbd.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
diff --git a/fsdev/virtfs-proxy-helper.texi b/fsdev/virtfs-proxy-helper.texi
new file mode 100644
index 0000000..3816382
--- /dev/null
+++ b/fsdev/virtfs-proxy-helper.texi
@@ -0,0 +1,59 @@
+@example
+@c man begin SYNOPSIS
+usage: virtfs-proxy-helper options
+@c man end
+@end example
+
+@c man begin DESCRIPTION
+@table @description
+Pass-through security model in QEMU 9p server needs root privilege to do
+few file operations (like chown, chmod to any mode/uid:gid). There are two
+issues in pass-through security model
+
+1) TOCTTOU vulnerability: Following symbolic links in the server could
+provide access to files beyond 9p export path.
+
+2) Running QEMU with root privilege could be a security issue.
+
+To overcome above issues, following approach is used: A new filesytem
+type 'proxy' is introduced. Proxy FS uses chroot + socket combination
+for securing the vulnerability known with following symbolic links.
+Intention of adding a new filesystem type is to allow qemu to run
+in non-root mode, but doing privileged operations using socket IO.
+
+Proxy helper(a stand alone binary part of qemu) is invoked with
+root privileges. Proxy helper chroots into 9p export path and creates
+a socket pair or a named socket based on the command line parameter.
+Qemu and proxy helper communicate using this socket. QEMU proxy fs
+driver sends filesystem request to proxy helper and receives the
+response from it.
+
+Proxy helper is designed so that it can drop the root privilege with
+retaining capbilities needed for doing filesystem operations only.
+
+@end table
+@c man end
+
+@c man begin OPTIONS
+The following options are supported:
+@table @option
+@item -h
+@findex -h
+Display help and exit
+@item -p|--path path
+Path to export for proxy filesystem driver
+@item -f|--fd socket-id
+Use given file descriptor as socket descriptor for communicating with
+qemu proxy fs drier. Usually a helper like libvirt will create
+socketpair and pass one of the fds as parameter to -f|--fd
+@item -n|--nodaemon
+Run as a normal program. By default program will run in daemon mode
+@end table
+@c man end
+
+@setfilename virtfs-proxy-helper
+@settitle QEMU 9p virtfs proxy filesystem helper
+
+@c man begin AUTHOR
+M. Mohan Kumar
+@c man end
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH V2 12/12] hw/9pfs: Add support to use named socket for proxy FS
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (10 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 11/12] hw/9pfs: man page for proxy helper M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 11:57 ` [Qemu-devel] [PATCH 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
2011-11-15 12:09 ` [Qemu-devel] [PATCH V2 " M. Mohan Kumar
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Add option to use named socket for communicating between proxy helper
and qemu proxy FS. Access to socket can be given by using command line
options -u and -g. We can achive the same using a shell script over
qemu and virtfs-proxy-helper using exec fd<><socket-path>, and then
passing that fd as argument to qemu and virtfs-proxy-helper. Also having
a server like virtfs-proxy-helper listening on a pathname without any
authentication is little bit scary. So we have to decide whether this
patch is really needed.
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
fsdev/file-op-9p.h | 2 +
fsdev/virtfs-proxy-helper.c | 88 ++++++++++++++++++++++++++++++++++++++--
fsdev/virtfs-proxy-helper.texi | 4 ++
hw/9pfs/virtio-9p-proxy.c | 52 ++++++++++++++++++++---
qemu-config.c | 7 +++
qemu-options.hx | 15 +++++--
vl.c | 6 ++-
7 files changed, 158 insertions(+), 16 deletions(-)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 84e5375..ac98e10 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -57,6 +57,8 @@ typedef struct extended_ops {
*/
#define V9FS_SM_NONE 0x00000010
#define V9FS_RDONLY 0x00000020
+#define V9FS_PROXY_SOCK_FD 0x00000040
+#define V9FS_PROXY_SOCK_NAME 0x00000080
#define V9FS_SEC_MASK 0x0000001C
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 917bb26..6c9ee3b 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -60,6 +60,9 @@ static struct option helper_opts[] = {
{"fd", required_argument, NULL, 'f'},
{"path", required_argument, NULL, 'p'},
{"nodaemon", no_argument, NULL, 'n'},
+ {"socket", required_argument, NULL, 's'},
+ {"uid", required_argument, NULL, 'u'},
+ {"gid", required_argument, NULL, 'g'},
};
int is_daemon;
@@ -584,11 +587,61 @@ static int do_open(struct iovec *iovec)
return fd;
}
+/* create unix domain socket and return the descriptor */
+static int proxy_socket(const char *path, uid_t uid, gid_t gid)
+{
+ int sock, client;
+ struct sockaddr_un proxy, qemu;
+ socklen_t size;
+
+ /* requested socket already exists, refuse to start */
+ if (!access(path, F_OK)) {
+ do_log(LOG_CRIT, "socket already exists\n");
+ return -1;
+ }
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ do_perror("socket");
+ return -1;
+ }
+
+ /* mask other part of mode bits */
+ umask(7);
+
+ proxy.sun_family = AF_UNIX;
+ strcpy(proxy.sun_path, path);
+ if (bind(sock, (struct sockaddr *)&proxy,
+ sizeof(struct sockaddr_un)) < 0) {
+ do_perror("bind");
+ return -1;
+ }
+ if (chown(proxy.sun_path, uid, gid) < 0) {
+ do_perror("chown");
+ return -1;
+ }
+ if (listen(sock, 1) < 0) {
+ do_perror("listen");
+ return -1;
+ }
+
+ client = accept(sock, (struct sockaddr *)&qemu, &size);
+ if (client < 0) {
+ do_perror("accept");
+ return -1;
+ }
+ return client;
+}
+
static void usage(char *prog)
{
fprintf(stderr, "usage: %s\n"
" -p|--path <path> 9p path to export\n"
" {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
+ " {-s|--socket <socketname> socket file used for communication\n"
+ " \t-u|--uid <uid> -g|--gid <gid>} - uid:gid combination to give "
+ " access to this socket\n"
+ " \tNote: -s & -f can not be used together\n"
" [-n|--nodaemon] Run as a normal program\n",
basename(prog));
}
@@ -774,18 +827,22 @@ error:
int main(int argc, char **argv)
{
int sock;
+ char sock_name[PATH_MAX];
char rpath[PATH_MAX];
struct stat stbuf;
int c, option_index;
int retval;
struct statfs st_fs;
+ uid_t own_u;
+ gid_t own_g;
is_daemon = 1;
- rpath[0] = '\0';
+ sock_name[0] = rpath[0] = '\0';
sock = -1;
+ own_u = own_g = -1;
while (1) {
option_index = 0;
- c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
+ c = getopt_long(argc, argv, "p:nh?f:s:u:g:", helper_opts,
&option_index);
if (c == -1) {
break;
@@ -800,6 +857,15 @@ int main(int argc, char **argv)
case 'f':
sock = atoi(optarg);
break;
+ case 's':
+ strcpy(sock_name, optarg);
+ break;
+ case 'u':
+ own_u = atoi(optarg);
+ break;
+ case 'g':
+ own_g = atoi(optarg);
+ break;
case '?':
case 'h':
default:
@@ -810,8 +876,16 @@ int main(int argc, char **argv)
}
/* Parameter validation */
- if (sock == -1 || rpath[0] == '\0') {
- fprintf(stderr, "socket descriptor or path not specified\n");
+ if ((sock_name[0] == '\0' && sock == -1) || rpath[0] == '\0') {
+ fprintf(stderr, "socket, socket descriptor or path not specified\n");
+ usage(argv[0]);
+ return -1;
+ }
+
+ if (*sock_name && (own_u == -1 || own_g == -1)) {
+ fprintf(stderr, "owner uid:gid not specified, ");
+ fprintf(stderr,
+ "owner uid:gid specifies who can access the socket file\n");
usage(argv[0]);
return -1;
}
@@ -835,6 +909,12 @@ int main(int argc, char **argv)
}
do_log(LOG_INFO, "Started");
+ if (*sock_name) {
+ sock = proxy_socket(sock_name, own_u, own_g);
+ if (sock < 0) {
+ goto error;
+ }
+ }
/* check whether underlying FS support IOC_GETVERSION */
retval = statfs(rpath, &st_fs);
diff --git a/fsdev/virtfs-proxy-helper.texi b/fsdev/virtfs-proxy-helper.texi
index 3816382..faa0434 100644
--- a/fsdev/virtfs-proxy-helper.texi
+++ b/fsdev/virtfs-proxy-helper.texi
@@ -46,6 +46,10 @@ Path to export for proxy filesystem driver
Use given file descriptor as socket descriptor for communicating with
qemu proxy fs drier. Usually a helper like libvirt will create
socketpair and pass one of the fds as parameter to -f|--fd
+@item -s|--socket socket-file
+Creates named socket file for communicating with qemu proxy fs driver
+@item -u|--uid uid -g|--gid gid
+uid:gid combination to give access to named socket file
@item -n|--nodaemon
Run as a normal program. By default program will run in daemon mode
@end table
diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c
index bc63835..b16e076 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -1008,15 +1008,49 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
return err;
}
+static int connect_namedsocket(const char *path)
+{
+ int sockfd, size;
+ struct sockaddr_un helper;
+
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ fprintf(stderr, "socket %s\n", strerror(errno));
+ return -1;
+ }
+ strcpy(helper.sun_path, path);
+ helper.sun_family = AF_UNIX;
+ size = strlen(helper.sun_path) + sizeof(helper.sun_family);
+ if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
+ fprintf(stderr, "socket error\n");
+ return -1;
+ }
+
+ /* remove the socket for security reasons */
+ unlink(path);
+ return sockfd;
+}
+
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
{
+ const char *socket = qemu_opt_get(opts, "socket");
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
- if (sock_fd) {
- fprintf(stderr, "sock_fd option not specified\n");
+ if (!socket && !sock_fd) {
+ fprintf(stderr, "socket and sock_fd none of the option specified\n");
+ return -1;
+ }
+ if (socket && sock_fd) {
+ fprintf(stderr, "Both socket and sock_fd options specified\n");
return -1;
}
- fs->path = g_strdup(sock_fd);
+ if (socket) {
+ fs->path = g_strdup(socket);
+ fs->export_flags = V9FS_PROXY_SOCK_NAME;
+ } else {
+ fs->path = g_strdup(sock_fd);
+ fs->export_flags = V9FS_PROXY_SOCK_FD;
+ }
return 0;
}
@@ -1025,10 +1059,14 @@ static int proxy_init(FsContext *ctx)
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
int sock_id;
- sock_id = atoi(ctx->fs_root);
- if (sock_id < 0) {
- fprintf(stderr, "socket descriptor not initialized\n");
- return -1;
+ if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
+ sock_id = connect_namedsocket(ctx->fs_root);
+ } else {
+ sock_id = atoi(ctx->fs_root);
+ if (sock_id < 0) {
+ fprintf(stderr, "socket descriptor not initialized\n");
+ return -1;
+ }
}
g_free(ctx->fs_root);
diff --git a/qemu-config.c b/qemu-config.c
index 33367fe..48093ca 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -183,6 +183,10 @@ QemuOptsList qemu_fsdev_opts = {
}, {
.name = "readonly",
.type = QEMU_OPT_BOOL,
+
+ }, {
+ .name = "socket",
+ .type = QEMU_OPT_STRING,
}, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
@@ -216,6 +220,9 @@ QemuOptsList qemu_virtfs_opts = {
.name = "readonly",
.type = QEMU_OPT_BOOL,
}, {
+ .name = "socket",
+ .type = QEMU_OPT_STRING,
+ }, {
.name = "sock_fd",
.type = QEMU_OPT_NUMBER,
},
diff --git a/qemu-options.hx b/qemu-options.hx
index cde17ed..a686f87 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -531,12 +531,12 @@ DEFHEADING(File system options:)
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n"
- " [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
+ " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
QEMU_ARCH_ALL)
STEXI
-@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
+@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
@findex -fsdev
Define a new file system device. Valid options are:
@table @option
@@ -569,6 +569,9 @@ reported as written by the storage subsystem.
@item readonly
Enables exporting 9p share as a readonly mount for guests. By default
read-write access is given.
+@item socket=@var{socket}
+Enables proxy filesystem driver to use passed socket file for communicating
+with virtfs-proxy-helper
@item sock_fd=@var{sock_fd}
Enables proxy filesystem driver to use passed socket descriptor for
communicating with virtfs-proxy-helper. Usually a helper like libvirt
@@ -593,12 +596,12 @@ DEFHEADING(Virtual File system pass-through options:)
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
- " [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
+ " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
QEMU_ARCH_ALL)
STEXI
-@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
+@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
@findex -virtfs
The general form of a Virtual File system pass-through options are:
@@ -632,6 +635,10 @@ reported as written by the storage subsystem.
@item readonly
Enables exporting 9p share as a readonly mount for guests. By default
read-write access is given.
+@item socket=@var{socket}
+Enables proxy filesystem driver to use passed socket file for
+communicating with virtfs-proxy-helper. Usually a helper like libvirt
+will create socketpair and pass one of the fds as sock_fd
@item sock_fd
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
descriptor for interfacing with virtfs-proxy-helper
diff --git a/vl.c b/vl.c
index 1feaf37..697f92a 100644
--- a/vl.c
+++ b/vl.c
@@ -2663,7 +2663,7 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_virtfs: {
QemuOpts *fsdev;
QemuOpts *device;
- const char *writeout, *sock_fd;
+ const char *writeout, *sock_fd, *socket;
olist = qemu_find_opts("virtfs");
if (!olist) {
@@ -2703,6 +2703,10 @@ int main(int argc, char **argv, char **envp)
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
qemu_opt_set(fsdev, "security_model",
qemu_opt_get(opts, "security_model"));
+ socket = qemu_opt_get(opts, "socket");
+ if (socket) {
+ qemu_opt_set(fsdev, "socket", socket);
+ }
sock_fd = qemu_opt_get(opts, "sock_fd");
if (sock_fd) {
qemu_opt_set(fsdev, "sock_fd", sock_fd);
--
1.7.6
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 00/12] Proxy FS driver for VirtFS
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (11 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH V2 12/12] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar
@ 2011-11-15 11:57 ` M. Mohan Kumar
2011-11-15 12:09 ` [Qemu-devel] [PATCH V2 " M. Mohan Kumar
13 siblings, 0 replies; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 11:57 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Pass-through security model in QEMU 9p server needs root privilege to do
few file operations (like chown, chmod to any mode/uid:gid). There are two
issues in pass-through security model
1) TOCTTOU vulnerability: Following symbolic links in the server could
provide access to files beyond 9p export path.
2) Running QEMU with root privilege could be a security issue.
To overcome above issues, following approach is used: A new filesytem
type 'proxy' is introduced. Proxy FS uses chroot + socket combination
for securing the vulnerability known with following symbolic links.
Intention of adding a new filesystem type is to allow qemu to run
in non-root mode, but doing privileged operations using socket IO.
Proxy helper(a stand alone binary part of qemu) is invoked with
root privileges. Proxy helper chroots into 9p export path and creates
a socket pair or a named socket based on the command line parameter.
Qemu and proxy helper communicate using this socket. QEMU proxy fs
driver sends filesystem request to proxy helper and receives the
response from it.
Proxy helper is designed so that it can drop the root privilege but
retaining capbilities that are needed for doing filesystem operations
(like CAP_DAC_OVERRIDE, CAP_FOWNER etc)
M. Mohan Kumar (12):
hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
hw/9pfs: Add new proxy filesystem driver
hw/9pfs: File system helper process for qemu 9p proxy FS
hw/9pfs: Open and create files
hw/9pfs: Create other filesystem objects
hw/9pfs: Add stat/readlink/statfs for proxy FS
hw/9pfs: File ownership and others
hw/9pfs: xattr interfaces in proxy filesystem driver
hw/9pfs: Proxy getversion
hw/9pfs: Documentation changes related to proxy fs
hw/9pfs: man page for proxy helper
hw/9pfs: Add support to use named socket for proxy FS
Makefile | 15 +-
Makefile.objs | 4 +-
configure | 19 +
fsdev/file-op-9p.h | 3 +-
fsdev/qemu-fsdev.c | 1 +
fsdev/qemu-fsdev.h | 1 +
fsdev/virtfs-proxy-helper.c | 947 +++++++++++++++++++++++++++++++++
fsdev/virtfs-proxy-helper.texi | 63 +++
fsdev/virtio-9p-marshal.c | 338 ++++++++++++
fsdev/virtio-9p-marshal.h | 87 +++
hw/9pfs/virtio-9p-proxy.c | 1123 ++++++++++++++++++++++++++++++++++++++++
hw/9pfs/virtio-9p-proxy.h | 80 +++
hw/9pfs/virtio-9p.c | 297 +-----------
hw/9pfs/virtio-9p.h | 85 +---
qemu-config.c | 13 +
qemu-options.hx | 32 +-
vl.c | 10 +-
17 files changed, 2736 insertions(+), 382 deletions(-)
create mode 100644 fsdev/virtfs-proxy-helper.c
create mode 100644 fsdev/virtfs-proxy-helper.texi
create mode 100644 fsdev/virtio-9p-marshal.c
create mode 100644 fsdev/virtio-9p-marshal.h
create mode 100644 hw/9pfs/virtio-9p-proxy.c
create mode 100644 hw/9pfs/virtio-9p-proxy.h
--
1.7.6
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS
2011-11-15 11:57 [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
` (12 preceding siblings ...)
2011-11-15 11:57 ` [Qemu-devel] [PATCH 00/12] Proxy FS driver for VirtFS M. Mohan Kumar
@ 2011-11-15 12:09 ` M. Mohan Kumar
2011-11-17 16:00 ` Stefan Hajnoczi
13 siblings, 1 reply; 20+ messages in thread
From: M. Mohan Kumar @ 2011-11-15 12:09 UTC (permalink / raw)
To: qemu-devel, aneesh.kumar, stefanha, berrange
Changes from previous version:
1) Communication between qemu and helper process is similar to 9p way of
packing
elements (pdu marshaling).
M. Mohan Kumar wrote:
> Pass-through security model in QEMU 9p server needs root privilege to do
> few file operations (like chown, chmod to any mode/uid:gid). There are two
> issues in pass-through security model
>
> 1) TOCTTOU vulnerability: Following symbolic links in the server could
> provide access to files beyond 9p export path.
>
> 2) Running QEMU with root privilege could be a security issue.
>
> To overcome above issues, following approach is used: A new filesytem
> type 'proxy' is introduced. Proxy FS uses chroot + socket combination
> for securing the vulnerability known with following symbolic links.
> Intention of adding a new filesystem type is to allow qemu to run
> in non-root mode, but doing privileged operations using socket IO.
>
> Proxy helper(a stand alone binary part of qemu) is invoked with
> root privileges. Proxy helper chroots into 9p export path and creates
> a socket pair or a named socket based on the command line parameter.
> Qemu and proxy helper communicate using this socket. QEMU proxy fs
> driver sends filesystem request to proxy helper and receives the
> response from it.
>
> Proxy helper is designed so that it can drop the root privilege but
> retaining capbilities that are needed for doing filesystem operations
> (like CAP_DAC_OVERRIDE, CAP_FOWNER etc)
>
> M. Mohan Kumar (12):
> hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
> hw/9pfs: Add new proxy filesystem driver
> hw/9pfs: File system helper process for qemu 9p proxy FS
> hw/9pfs: Open and create files
> hw/9pfs: Create other filesystem objects
> hw/9pfs: Add stat/readlink/statfs for proxy FS
> hw/9pfs: File ownership and others
> hw/9pfs: xattr interfaces in proxy filesystem driver
> hw/9pfs: Proxy getversion
> hw/9pfs: Documentation changes related to proxy fs
> hw/9pfs: man page for proxy helper
> hw/9pfs: Add support to use named socket for proxy FS
>
> Makefile | 15 +-
> Makefile.objs | 4 +-
> configure | 19 +
> fsdev/file-op-9p.h | 3 +-
> fsdev/qemu-fsdev.c | 1 +
> fsdev/qemu-fsdev.h | 1 +
> fsdev/virtfs-proxy-helper.c | 947 +++++++++++++++++++++++++++++++++
> fsdev/virtfs-proxy-helper.texi | 63 +++
> fsdev/virtio-9p-marshal.c | 338 ++++++++++++
> fsdev/virtio-9p-marshal.h | 87 +++
> hw/9pfs/virtio-9p-proxy.c | 1123 ++++++++++++++++++++++++++++++++++++++++
> hw/9pfs/virtio-9p-proxy.h | 80 +++
> hw/9pfs/virtio-9p.c | 297 +-----------
> hw/9pfs/virtio-9p.h | 85 +---
> qemu-config.c | 13 +
> qemu-options.hx | 32 +-
> vl.c | 10 +-
> 17 files changed, 2736 insertions(+), 382 deletions(-)
> create mode 100644 fsdev/virtfs-proxy-helper.c
> create mode 100644 fsdev/virtfs-proxy-helper.texi
> create mode 100644 fsdev/virtio-9p-marshal.c
> create mode 100644 fsdev/virtio-9p-marshal.h
> create mode 100644 hw/9pfs/virtio-9p-proxy.c
> create mode 100644 hw/9pfs/virtio-9p-proxy.h
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH V2 00/12] Proxy FS driver for VirtFS
2011-11-15 12:09 ` [Qemu-devel] [PATCH V2 " M. Mohan Kumar
@ 2011-11-17 16:00 ` Stefan Hajnoczi
0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hajnoczi @ 2011-11-17 16:00 UTC (permalink / raw)
To: M. Mohan Kumar; +Cc: qemu-devel, aneesh.kumar
On Tue, Nov 15, 2011 at 12:09 PM, M. Mohan Kumar <mohan@in.ibm.com> wrote:
> Changes from previous version:
>
> 1) Communication between qemu and helper process is similar to 9p way of
> packing
> elements (pdu marshaling).
There is code I haven't reviewed yet but I think it will change as you
add input validation, so I will wait for v3.
Stefan
^ permalink raw reply [flat|nested] 20+ messages in thread