All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH V3 00/13]  Proxy FS driver for VirtFS
@ 2011-11-21 13:36 M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 01/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
                   ` (12 more replies)
  0 siblings, 13 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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)

Changes from previous version V2:
* Added check to handle failures in marshaling/unmarshaling code. Also make
  sure that request/response will not exceed maximum buffer size (BUFF_SZ)
* Addressed Stefan's review comments

Changes from previous version:
*) Communication between qemu and helper process is similar to 9p way of packing
elements (pdu marshaling).

Tested with fsstress.

M. Mohan Kumar (13):
  hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
  hw/9pfs: Validating marshal code
  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    | 1029 ++++++++++++++++++++++++++++++++++
 fsdev/virtfs-proxy-helper.texi |   63 +++
 fsdev/virtio-9p-marshal.c      |  365 +++++++++++++
 fsdev/virtio-9p-marshal.h      |   87 +++
 hw/9pfs/virtio-9p-proxy.c      | 1181 ++++++++++++++++++++++++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.h      |   80 +++
 hw/9pfs/virtio-9p.c            |  524 ++++++------------
 hw/9pfs/virtio-9p.h            |   83 +---
 qemu-config.c                  |   13 +
 qemu-options.hx                |   32 +-
 vl.c                           |   10 +-
 17 files changed, 3069 insertions(+), 441 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 01/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code M. Mohan Kumar
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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       |   83 +----------
 5 files changed, 438 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..6569c78 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,15 @@ 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, fmt, ##args)
+#define pdu_unmarshal(pdu, offset, fmt, args...)  \
+    v9fs_unmarshal(pdu->elem.out_sg, pdu->elem.out_num, offset, 1, fmt, ##args)
+
 #endif
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 01/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 14:38   ` Aneesh Kumar K.V
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 03/13] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

Add validatio check to {un}marshal code.

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 fsdev/virtio-9p-marshal.c |   97 ++++++++++++-------
 fsdev/virtio-9p-marshal.h |    8 +-
 hw/9pfs/virtio-9p.c       |  231 +++++++++++++++++++++++++++++++++------------
 3 files changed, 236 insertions(+), 100 deletions(-)

diff --git a/fsdev/virtio-9p-marshal.c b/fsdev/virtio-9p-marshal.c
index 2da0a34..74161df 100644
--- a/fsdev/virtio-9p-marshal.c
+++ b/fsdev/virtio-9p-marshal.c
@@ -62,14 +62,14 @@ void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
 }
 
 
-static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
-                              size_t offset, size_t size, int pack)
+static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
+                              ssize_t offset, ssize_t size, int pack)
 {
     int i = 0;
-    size_t copied = 0;
+    ssize_t copied = 0;
 
     for (i = 0; size && i < sg_count; i++) {
-        size_t len;
+        ssize_t len;
         if (offset >= sg[i].iov_len) {
             /* skip this sg */
             offset -= sg[i].iov_len;
@@ -91,25 +91,29 @@ static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
         }
     }
 
+    /* could not copy requested 'size' */
+    if (copied < 0) {
+        return -1;
+    }
     return copied;
 }
 
-static size_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
-                          size_t offset, size_t size)
+static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
+                          ssize_t offset, ssize_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)
+ssize_t v9fs_pack(struct iovec *in_sg, int in_num, ssize_t offset,
+                const void *src, ssize_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)
+                        ssize_t offset, struct iovec *sg)
 {
-    size_t pos = 0;
+    ssize_t pos = 0;
     int i, j;
 
     j = 0;
@@ -131,10 +135,10 @@ static int v9fs_copy_sg(struct iovec *src_sg, unsigned int num,
     return j;
 }
 
-size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
-                int convert, const char *fmt, ...)
+ssize_t v9fs_unmarshal(struct iovec *out_sg,
+                int out_num, ssize_t offset, int convert, const char *fmt, ...)
 {
-    size_t old_offset = offset;
+    ssize_t old_offset = offset, copied;
     va_list ap;
     int i;
 
@@ -143,13 +147,13 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         switch (fmt[i]) {
         case 'b': {
             uint8_t *valp = va_arg(ap, uint8_t *);
-            offset += v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
+            copied = 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));
+            copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
             if (convert) {
                 *valp = le16_to_cpu(val);
             } else {
@@ -160,7 +164,7 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         case 'd': {
             uint32_t val, *valp;
             valp = va_arg(ap, uint32_t *);
-            offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+            copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
             if (convert) {
                 *valp = le32_to_cpu(val);
             } else {
@@ -171,7 +175,7 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         case 'q': {
             uint64_t val, *valp;
             valp = va_arg(ap, uint64_t *);
-            offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+            copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
             if (convert) {
                 *valp = le64_to_cpu(val);
             } else {
@@ -187,24 +191,31 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         }
         case 's': {
             V9fsString *str = va_arg(ap, V9fsString *);
-            offset += v9fs_unmarshal(out_sg, out_num, offset, convert,
+            copied = v9fs_unmarshal(out_sg, out_num, offset, convert,
                             "w", &str->size);
-            /* FIXME: sanity check str->size */
+            if (copied < 0) {
+                goto out;
+            }
+            offset += copied;
             str->data = g_malloc(str->size + 1);
-            offset += v9fs_unpack(str->data, out_sg, out_num, offset,
+            copied = v9fs_unpack(str->data, out_sg, out_num, offset,
                             str->size);
+            if (copied < 0) {
+                g_free(str->data);
+                goto out;
+            }
             str->data[str->size] = 0;
             break;
         }
         case 'Q': {
             V9fsQID *qidp = va_arg(ap, V9fsQID *);
-            offset += v9fs_unmarshal(out_sg, out_num, offset, convert, "bdq",
+            copied = 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,
+            copied = v9fs_unmarshal(out_sg, out_num, offset, convert,
                                     "wwdQdddqsssssddd",
                                      &statp->size, &statp->type, &statp->dev,
                                      &statp->qid, &statp->mode, &statp->atime,
@@ -217,7 +228,7 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         }
         case 'I': {
             V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
-            offset += v9fs_unmarshal(out_sg, out_num, offset, convert,
+            copied = v9fs_unmarshal(out_sg, out_num, offset, convert,
                                      "ddddqqqqq",
                                      &iattr->valid, &iattr->mode,
                                      &iattr->uid, &iattr->gid, &iattr->size,
@@ -228,6 +239,12 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
         default:
             break;
         }
+out:
+        if (copied < 0) {
+            va_end(ap);
+            return copied;
+        }
+        offset += copied;
     }
 
     va_end(ap);
@@ -235,10 +252,10 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
     return offset - old_offset;
 }
 
-size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
-                int convert, const char *fmt, ...)
+ssize_t v9fs_marshal(struct iovec *in_sg, int in_num,
+                ssize_t offset, int convert, const char *fmt, ...)
 {
-    size_t old_offset = offset;
+    ssize_t old_offset = offset, copied;
     va_list ap;
     int i;
 
@@ -247,7 +264,7 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
         switch (fmt[i]) {
         case 'b': {
             uint8_t val = va_arg(ap, int);
-            offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+            copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
             break;
         }
         case 'w': {
@@ -257,7 +274,7 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
             } else {
                 val =  va_arg(ap, int);
             }
-            offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+            copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
             break;
         }
         case 'd': {
@@ -267,7 +284,7 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
             } else {
                 val =  va_arg(ap, uint32_t);
             }
-            offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+            copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
             break;
         }
         case 'q': {
@@ -277,7 +294,7 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
             } else {
                 val =  va_arg(ap, uint64_t);
             }
-            offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
+            copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
             break;
         }
         case 'v': {
@@ -288,20 +305,24 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
         }
         case 's': {
             V9fsString *str = va_arg(ap, V9fsString *);
-            offset += v9fs_marshal(in_sg, in_num, offset, convert,
+            copied = v9fs_marshal(in_sg, in_num, offset, convert,
                             "w", str->size);
-            offset += v9fs_pack(in_sg, in_num, offset, str->data, str->size);
+            if (copied < 0) {
+                goto out;
+            }
+            offset += copied;
+            copied = 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",
+            copied = 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,
+            copied = v9fs_marshal(in_sg, in_num, offset, convert,
                                    "wwdQdddqsssssddd",
                                    statp->size, statp->type, statp->dev,
                                    &statp->qid, statp->mode, statp->atime,
@@ -313,7 +334,7 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
         }
         case 'A': {
             V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
-            offset += v9fs_marshal(in_sg, in_num, offset, convert,
+            copied = v9fs_marshal(in_sg, in_num, offset, convert,
                                    "qQdddqqqqqqqqqqqqqqq",
                                    statp->st_result_mask,
                                    &statp->qid, statp->st_mode,
@@ -331,6 +352,12 @@ size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
         default:
             break;
         }
+out:
+        if (copied < 0) {
+            va_end(ap);
+            return copied;
+        }
+        offset += copied;
     }
     va_end(ap);
 
diff --git a/fsdev/virtio-9p-marshal.h b/fsdev/virtio-9p-marshal.h
index fe2d34b..b268cbf 100644
--- a/fsdev/virtio-9p-marshal.h
+++ b/fsdev/virtio-9p-marshal.h
@@ -77,11 +77,11 @@ 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,
+ssize_t v9fs_pack(struct iovec *in_sg, int in_num, ssize_t offset,
+                 const void *src, ssize_t size);
+ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, ssize_t offset,
                       int convert, const char *fmt, ...);
-size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
+ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, ssize_t offset,
                     int convert, const char *fmt, ...);
 
 #endif
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 2a8ac56..774e945 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -897,6 +897,7 @@ static void v9fs_version(void *opaque)
     V9fsState *s = pdu->s;
     V9fsString version;
     size_t offset = 7;
+    ssize_t copied;
 
     pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
     trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
@@ -909,11 +910,15 @@ static void v9fs_version(void *opaque)
         v9fs_string_sprintf(&version, "unknown");
     }
 
-    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
+    copied = pdu_marshal(pdu, offset, "ds", s->msize, &version);
+    if (copied < 0) {
+        offset = -EOVERFLOW;
+        goto out;
+    }
+    offset += copied;
     trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
-
+out:
     complete_pdu(s, pdu, offset);
-
     v9fs_string_free(&version);
     return;
 }
@@ -950,8 +955,13 @@ static void v9fs_attach(void *opaque)
         clunk_fid(s, fid);
         goto out;
     }
-    offset += pdu_marshal(pdu, offset, "Q", &qid);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "Q", &qid);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        clunk_fid(s, fid);
+        goto out;
+    }
+    err += offset;
     trace_v9fs_attach_return(pdu->tag, pdu->id,
                              qid.type, qid.version, qid.path);
 out:
@@ -989,10 +999,15 @@ static void v9fs_stat(void *opaque)
     if (err < 0) {
         goto out;
     }
-    offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        v9fs_stat_free(&v9stat);
+        goto out;
+    }
     trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
                            v9stat.atime, v9stat.mtime, v9stat.length);
+    err += offset;
     v9fs_stat_free(&v9stat);
 out:
     put_fid(pdu, fidp);
@@ -1038,8 +1053,12 @@ static void v9fs_getattr(void *opaque)
         }
         v9stat_dotl.st_result_mask |= P9_STATS_GEN;
     }
-    retval = offset;
-    retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
+    retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
+    if (retval < 0) {
+        retval = -EOVERFLOW;
+        goto out;
+    }
+    retval += offset;
     trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
                               v9stat_dotl.st_mode, v9stat_dotl.st_uid,
                               v9stat_dotl.st_gid);
@@ -1147,9 +1166,18 @@ static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
 {
     int i;
     size_t offset = 7;
-    offset += pdu_marshal(pdu, offset, "w", nwnames);
+    ssize_t copied;
+    copied = pdu_marshal(pdu, offset, "w", nwnames);
+    if (copied < 0) {
+        return -EOVERFLOW;
+    }
+    offset += copied;
     for (i = 0; i < nwnames; i++) {
-        offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
+        copied = pdu_marshal(pdu, offset, "Q", &qids[i]);
+        if (copied < 0) {
+            return -EOVERFLOW;
+        }
+        offset += copied;
     }
     return offset;
 }
@@ -1170,8 +1198,7 @@ static void v9fs_walk(void *opaque)
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
-    offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
-                            &newfid, &nwnames);
+    offset += pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
 
     trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
 
@@ -1302,8 +1329,12 @@ static void v9fs_open(void *opaque)
             goto out;
         }
         fidp->fid_type = P9_FID_DIR;
-        offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
-        err = offset;
+        err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset;
     } else {
         if (s->proto_version == V9FS_PROTO_2000L) {
             flags = get_dotl_openflags(s, mode);
@@ -1332,8 +1363,12 @@ static void v9fs_open(void *opaque)
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
         iounit = get_iounit(pdu, &fidp->path);
-        offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
-        err = offset;
+        err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset;
     }
     trace_v9fs_open_return(pdu->tag, pdu->id,
                            qid.type, qid.version, qid.path, iounit);
@@ -1356,8 +1391,8 @@ static void v9fs_lcreate(void *opaque)
     int32_t iounit;
     V9fsPDU *pdu = opaque;
 
-    pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
-                  &mode, &gid);
+    offset += pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
+                            &mode, &gid);
     trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
 
     fidp = get_fid(pdu, dfid);
@@ -1383,8 +1418,12 @@ static void v9fs_lcreate(void *opaque)
     }
     iounit =  get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
-    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_lcreate_return(pdu->tag, pdu->id,
                               qid.type, qid.version, qid.path, iounit);
 out:
@@ -1456,6 +1495,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
     size_t offset = 7;
     int read_count;
     int64_t xattr_len;
+    ssize_t copied;
 
     xattr_len = fidp->fs.xattr.len;
     read_count = xattr_len - off;
@@ -1467,11 +1507,18 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
          */
         read_count = 0;
     }
-    offset += pdu_marshal(pdu, offset, "d", read_count);
-    offset += v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
+    copied = pdu_marshal(pdu, offset, "d", read_count);
+    if (copied < 0) {
+        return -1;
+    }
+    offset += copied;
+    copied = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
                         ((char *)fidp->fs.xattr.value) + off,
                         read_count);
-
+    if (copied < 0) {
+        return -1;
+    }
+    offset += copied;
     return offset;
 }
 
@@ -1566,9 +1613,12 @@ static void v9fs_read(void *opaque)
             err = count;
             goto out;
         }
-        err = offset;
-        err += pdu_marshal(pdu, offset, "d", count);
-        err += count;
+        err = pdu_marshal(pdu, offset, "d", count);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset + count;
     } else if (fidp->fid_type == P9_FID_FILE) {
         int32_t cnt;
         int32_t len;
@@ -1576,7 +1626,11 @@ static void v9fs_read(void *opaque)
         struct iovec iov[128]; /* FIXME: bad, bad, bad */
 
         sg = iov;
-        pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
+        err = pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
         sg = cap_sg(sg, max_count, &cnt);
         do {
             if (0) {
@@ -1597,9 +1651,12 @@ static void v9fs_read(void *opaque)
             }
             sg = adjust_sg(sg, len, &cnt);
         } while (count < max_count && len > 0);
-        err = offset;
-        err += pdu_marshal(pdu, offset, "d", count);
-        err += count;
+        err = pdu_marshal(pdu, offset, "d", count);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset + count;
     } else if (fidp->fid_type == P9_FID_XATTR) {
         err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
     } else {
@@ -1669,6 +1726,9 @@ static int v9fs_do_readdir(V9fsPDU *pdu,
         len = pdu_marshal(pdu, 11 + count, "Qqbs",
                           &qid, dent->d_off,
                           dent->d_type, &name);
+        if (len < 0) {
+            return -EOVERFLOW;
+        }
         count += len;
         v9fs_string_free(&name);
         saved_dir_pos = dent->d_off;
@@ -1714,9 +1774,12 @@ static void v9fs_readdir(void *opaque)
         retval = count;
         goto out;
     }
-    retval = offset;
-    retval += pdu_marshal(pdu, offset, "d", count);
-    retval += count;
+    retval = pdu_marshal(pdu, offset, "d", count);
+    if (retval < 0) {
+        retval = -EOVERFLOW;
+        goto out;
+    }
+    retval += count + offset;
     trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
 out:
     put_fid(pdu, fidp);
@@ -1747,8 +1810,11 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
         err = -ENOSPC;
         goto out;
     }
-    offset += pdu_marshal(pdu, offset, "d", write_count);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "d", write_count);
+    if (err < 0) {
+        return -EOVERFLOW;
+    }
+    err += offset;
     fidp->fs.xattr.copied_len += write_count;
     /*
      * Now copy the content from sg list
@@ -1827,8 +1893,12 @@ static void v9fs_write(void *opaque)
         }
         sg = adjust_sg(sg, len, &cnt);
     } while (total < count && len > 0);
-    offset += pdu_marshal(pdu, offset, "d", total);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "d", total);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
 out:
     put_fid(pdu, fidp);
@@ -1987,8 +2057,12 @@ static void v9fs_create(void *opaque)
     }
     iounit = get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
-    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_create_return(pdu->tag, pdu->id,
                              qid.type, qid.version, qid.path, iounit);
 out:
@@ -2026,8 +2100,12 @@ static void v9fs_symlink(void *opaque)
         goto out;
     }
     stat_to_qid(&stbuf, &qid);
-    offset += pdu_marshal(pdu, offset, "Q", &qid);
-    err = offset;
+    err =  pdu_marshal(pdu, offset, "Q", &qid);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_symlink_return(pdu->tag, pdu->id,
                               qid.type, qid.version, qid.path);
 out:
@@ -2535,8 +2613,12 @@ static void v9fs_statfs(void *opaque)
     if (retval < 0) {
         goto out;
     }
-    retval = offset;
-    retval += v9fs_fill_statfs(s, pdu, &stbuf);
+    retval = v9fs_fill_statfs(s, pdu, &stbuf);
+    if (retval < 0) {
+        retval = -EOVERFLOW;
+        goto out;
+    }
+    retval += offset;
 out:
     put_fid(pdu, fidp);
 out_nofid:
@@ -2575,8 +2657,12 @@ static void v9fs_mknod(void *opaque)
         goto out;
     }
     stat_to_qid(&stbuf, &qid);
-    err = offset;
-    err += pdu_marshal(pdu, offset, "Q", &qid);
+    err = pdu_marshal(pdu, offset, "Q", &qid);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_mknod_return(pdu->tag, pdu->id,
                             qid.type, qid.version, qid.path);
 out:
@@ -2633,8 +2719,12 @@ static void v9fs_lock(void *opaque)
 out:
     put_fid(pdu, fidp);
 out_nofid:
-    err = offset;
-    err += pdu_marshal(pdu, offset, "b", status);
+    err = pdu_marshal(pdu, offset, "b", status);
+    if (err < 0) {
+        err = -EOVERFLOW;
+    } else {
+        err += offset;
+    }
     trace_v9fs_lock_return(pdu->tag, pdu->id, status);
     complete_pdu(s, pdu, err);
     v9fs_string_free(&flock->client_id);
@@ -2673,10 +2763,14 @@ static void v9fs_getlock(void *opaque)
         goto out;
     }
     glock->type = P9_LOCK_TYPE_UNLCK;
-    offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
+    err = pdu_marshal(pdu, offset, "bqqds", glock->type,
                           glock->start, glock->length, glock->proc_id,
                           &glock->client_id);
-    err = offset;
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
                               glock->length, glock->proc_id);
 out:
@@ -2701,7 +2795,6 @@ static void v9fs_mkdir(void *opaque)
     int err = 0;
 
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
-
     trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
 
     fidp = get_fid(pdu, fid);
@@ -2714,8 +2807,12 @@ static void v9fs_mkdir(void *opaque)
         goto out;
     }
     stat_to_qid(&stbuf, &qid);
-    offset += pdu_marshal(pdu, offset, "Q", &qid);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "Q", &qid);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        goto out;
+    }
+    err += offset;
     trace_v9fs_mkdir_return(pdu->tag, pdu->id,
                             qid.type, qid.version, qid.path, err);
 out:
@@ -2777,8 +2874,12 @@ static void v9fs_xattrwalk(void *opaque)
                 goto out;
             }
         }
-        offset += pdu_marshal(pdu, offset, "q", size);
-        err = offset;
+        err = pdu_marshal(pdu, offset, "q", size);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset;
     } else {
         /*
          * specific xattr fid. We check for xattr
@@ -2807,8 +2908,12 @@ static void v9fs_xattrwalk(void *opaque)
                 goto out;
             }
         }
-        offset += pdu_marshal(pdu, offset, "q", size);
-        err = offset;
+        err = pdu_marshal(pdu, offset, "q", size);
+        if (err < 0) {
+            err = -EOVERFLOW;
+            goto out;
+        }
+        err += offset;
     }
     trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
 out:
@@ -2834,8 +2939,7 @@ static void v9fs_xattrcreate(void *opaque)
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
-    pdu_unmarshal(pdu, offset, "dsqd",
-                  &fid, &name, &size, &flags);
+    pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
     trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
 
     file_fidp = get_fid(pdu, fid);
@@ -2885,8 +2989,13 @@ static void v9fs_readlink(void *opaque)
     if (err < 0) {
         goto out;
     }
-    offset += pdu_marshal(pdu, offset, "s", &target);
-    err = offset;
+    err = pdu_marshal(pdu, offset, "s", &target);
+    if (err < 0) {
+        err = -EOVERFLOW;
+        v9fs_string_free(&target);
+        goto out;
+    }
+    err += offset;
     trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
     v9fs_string_free(&target);
 out:
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH V3 03/13] hw/9pfs: Add new proxy filesystem driver
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 01/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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 b268cbf..36302b7 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (2 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 03/13] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 05/13] hw/9pfs: Open and create files M. Mohan Kumar
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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 |  280 +++++++++++++++++++++++++++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.h   |    7 +-
 4 files changed, 308 insertions(+), 1 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..dc222d4
--- /dev/null
+++ b/fsdev/virtfs-proxy-helper.c
@@ -0,0 +1,280 @@
+/*
+ * 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 <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 <stdbool.h>
+#include "qemu-common.h"
+#include "virtio-9p-marshal.h"
+#include "hw/9pfs/virtio-9p-proxy.h"
+
+#define PROGNAME "virtfs-proxy-helper"
+
+#define do_log(loglevel, fmt, args...) \
+    do { \
+        if (is_daemon) {\
+            syslog(loglevel, fmt, ##args); \
+        } else { \
+            fprintf(stderr, fmt, ##args); \
+        } \
+    } while (0)
+
+#define do_perror(string) \
+    do { \
+        if (is_daemon) {\
+            syslog(LOG_CRIT, string ":%s", strerror(errno)); \
+        } else { \
+            fprintf(stderr, string ":%s\n", strerror(errno)); \
+        } \
+    } while (0)
+
+static struct option helper_opts[] = {
+    {"fd", required_argument, NULL, 'f'},
+    {"path", required_argument, NULL, 'p'},
+    {"nodaemon", no_argument, NULL, 'n'},
+};
+
+static bool is_daemon;
+
+static int cap_set(void)
+{
+    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;
+    }
+    if (cap_set_flag(caps, CAP_PERMITTED, 8, cap_list, CAP_SET) < 0) {
+        do_perror("cap_set_flag");
+        goto error;
+    }
+    if (cap_set_proc(caps) < 0) {
+        do_perror("cap_set_proc");
+        goto error;
+    }
+    if (cap_set_flag(caps, CAP_EFFECTIVE, 8, cap_list, CAP_SET)) {
+        do_perror("cap_set_flag");
+        goto error;
+    }
+    if (cap_set_proc(caps) < 0) {
+        do_perror("cap_set_proc");
+        goto error;
+    }
+    cap_free(caps);
+    return 0;
+
+error:
+    cap_free(caps);
+    return -1;
+}
+
+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)
+{
+    ssize_t retval, total = 0;
+
+    while (size) {
+        retval = read(sockfd, buff, size);
+        if (retval == 0) {
+            break;
+        }
+        if (retval < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            break;
+        }
+        size -= retval;
+        buff += retval;
+        total += retval;
+    }
+    return total;
+}
+
+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 -errno;
+    }
+    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);
+    if (header.size > BUFF_SZ) {
+        do_log(LOG_CRIT, "header.size exceeds maximum size\n");
+        return -E2BIG;
+    }
+    /* 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 = NULL;
+    struct stat stbuf;
+    int c, option_index;
+
+    is_daemon = true;
+    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':
+            rpath = optarg;
+            break;
+        case 'n':
+            is_daemon = false;
+            break;
+        case 'f':
+            sock = atoi(optarg);
+            break;
+        case '?':
+        case 'h':
+        default:
+            usage(argv[0]);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    /* Parameter validation */
+    if (sock == -1 || rpath[0] == '\0') {
+        fprintf(stderr, "socket descriptor or path not specified\n");
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (lstat(rpath, &stbuf) < 0) {
+        fprintf(stderr, "invalid path \"%s\" specified, %s\n",
+                        rpath, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    if (!S_ISDIR(stbuf.st_mode)) {
+        fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
+        exit(EXIT_FAILURE);
+    }
+
+    if (is_daemon) {
+        if (daemon(0, 0) < 0) {
+            fprintf(stderr, "daemon call failed\n");
+            exit(EXIT_FAILURE);
+        }
+        openlog(PROGNAME, LOG_PID, LOG_DAEMON);
+    }
+
+    do_log(LOG_INFO, "Started\n");
+
+    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\n");
+    closelog();
+    return 0;
+}
diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h
index f5e1a02..7be44bd 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -1,7 +1,12 @@
 #ifndef _QEMU_VIRTIO_9P_PROXY_H
 #define _QEMU_VIRTIO_9P_PROXY_H
 
-#define BUFF_SZ (4 * 1024)
+#define BUFF_SZ (64 * 1024)
+
+#define proxy_unmarshal(in_sg, in_elem, offset, fmt, args...) \
+    v9fs_unmarshal(in_sg, in_elem, offset, 0, fmt, ##args)
+#define proxy_marshal(out_sg, out_elem, offset, fmt, args...) \
+    v9fs_marshal(out_sg, out_elem, offset, 0, fmt, ##args)
 
 typedef struct {
     int type;
-- 
1.7.6

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH V3 05/13] hw/9pfs: Open and create files
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (3 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 06/13] hw/9pfs: Create other filesystem objects M. Mohan Kumar
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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 |  133 ++++++++++++++++++++++++++++++-
 hw/9pfs/virtio-9p-proxy.c   |  187 +++++++++++++++++++++++++++++++++++++++++--
 hw/9pfs/virtio-9p-proxy.h   |   14 +++
 3 files changed, 326 insertions(+), 8 deletions(-)

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index dc222d4..867fdcc 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -9,6 +9,7 @@
  * 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>
@@ -28,6 +29,7 @@
 #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"
 
@@ -172,6 +174,114 @@ static int read_request(int sockfd, struct iovec *iovec)
     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  */
+        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;
+
+    if (proxy_unmarshal(iovec, 1, HDR_SZ, "sdddd",
+                   &path, &flags, &mode, &uid, &gid) < 0) {
+        return -EOVERFLOW;
+    }
+    cur_uid = geteuid();
+    cur_gid = getegid();
+    if (setfsugid(uid, gid) < 0) {
+        v9fs_string_free(&path);
+        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;
+
+    if (proxy_unmarshal(iovec, 1, HDR_SZ, "sd", &path, &flags) < 0) {
+        return -EOVERFLOW;
+    }
+    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"
@@ -183,15 +293,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..3472337 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -22,6 +22,153 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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;
+out_overflow:
+    va_end(ap);
+    qemu_mutex_unlock(&proxy->mutex);
+    return -EOVERFLOW;
+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 +195,33 @@ 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 +323,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 7be44bd..27f2507 100644
--- a/hw/9pfs/virtio-9p-proxy.h
+++ b/hw/9pfs/virtio-9p-proxy.h
@@ -2,14 +2,28 @@
 #define _QEMU_VIRTIO_9P_PROXY_H
 
 #define BUFF_SZ (64 * 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, fmt, ##args)
 #define proxy_marshal(out_sg, out_elem, offset, fmt, args...) \
     v9fs_marshal(out_sg, out_elem, offset, 0, fmt, ##args)
 
+union MsgControl {
+    struct cmsghdr cmsg;
+    char control[CMSG_SPACE(sizeof(int))];
+};
+
 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 06/13] hw/9pfs: Create other filesystem objects
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (4 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 05/13] hw/9pfs: Open and create files M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 07/13] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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 |  120 ++++++++++++++++++++++++++--
 hw/9pfs/virtio-9p-proxy.c   |  185 +++++++++++++++++++++++++++++++++++++++----
 hw/9pfs/virtio-9p-proxy.h   |    8 ++-
 3 files changed, 287 insertions(+), 26 deletions(-)

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 867fdcc..246be77 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -216,6 +216,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:
@@ -235,6 +257,59 @@ 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:
+        if (proxy_unmarshal(iovec, 1, offset, "sdq", &path, &mode, &rdev) < 0) {
+            retval = -EOVERFLOW;
+            goto out;
+        }
+        retval = mknod(path.data, mode, rdev);
+        break;
+    case T_MKDIR:
+        if (proxy_unmarshal(iovec, 1, offset, "sd", &path, &mode) < 0) {
+            retval = -EOVERFLOW;
+            goto out;
+        }
+        retval = mkdir(path.data, mode);
+        break;
+    case T_SYMLINK:
+        if (proxy_unmarshal(iovec, 1, offset, "ss", &oldpath, &path) < 0) {
+            retval = -EOVERFLOW;
+            goto out;
+        }
+        retval = symlink(oldpath.data, path.data);
+        v9fs_string_free(&oldpath);
+        break;
+    }
+
+    if (retval < 0) {
+        retval = -errno;
+    }
+    v9fs_string_free(&path);
+out:
+    setfsugid(cur_uid, cur_gid);
+    return retval;
+}
+
+/*
  * create a file and send fd on success
  * return -errno on error
  */
@@ -294,38 +369,65 @@ 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:
+            if (proxy_unmarshal(&in_iovec, 1, HDR_SZ, "ss",
+                                    &oldpath, &path) < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = link(oldpath.data, path.data);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&oldpath);
+            v9fs_string_free(&path);
             break;
         default:
             goto error;
             break;
         }
-
         /* Send response */
         switch (type) {
         case T_OPEN:
         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 3472337..f116773 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:
@@ -129,6 +163,61 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
@@ -154,6 +243,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;
@@ -301,15 +399,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,
@@ -339,19 +462,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)
@@ -500,8 +650,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 27f2507..9a43f64 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 07/13] hw/9pfs: Add stat/readlink/statfs for proxy FS
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (5 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 06/13] hw/9pfs: Create other filesystem objects M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 08/13] hw/9pfs: File ownership and others M. Mohan Kumar
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 fsdev/virtfs-proxy-helper.c |  182 +++++++++++++++++++++++++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.c   |  189 +++++++++++++++++++++++++++++++++++++++++--
 hw/9pfs/virtio-9p-proxy.h   |   34 ++++++++
 3 files changed, 397 insertions(+), 8 deletions(-)

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 246be77..7510827 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -26,6 +26,8 @@
 #include <sys/fsuid.h>
 #include <stdarg.h>
 #include <stdbool.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"
@@ -257,6 +259,171 @@ 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 response size exceeds available iovec->iov_len,
+     * we return EOVERFLOW
+     */
+    if (size > (int)iovec->iov_len) {
+        size = -EOVERFLOW;
+    }
+
+    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;
+    struct stat st_buf;
+    ProxyStat pr_stat;
+    struct statfs stfs_buf;
+    ProxyStatFS pr_stfs;
+    int retval = 0;
+
+    if (proxy_unmarshal(iovec, 1, HDR_SZ, "s", &path) < 0) {
+        return -EOVERFLOW;
+    }
+
+    switch (type) {
+    case T_LSTAT:
+        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);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+            }
+        }
+        break;
+    case T_STATFS:
+        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);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+            }
+        }
+        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;
+
+    if (proxy_unmarshal(iovec, 1, HDR_SZ, "sd", &path, &size) < 0) {
+        return -EOVERFLOW;
+    }
+    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);
+        if (retval < 0) {
+            retval = -EOVERFLOW;
+        }
+    } 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
  */
@@ -371,6 +538,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;
@@ -404,6 +572,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;
@@ -420,6 +595,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 f116773..aca799e 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -89,6 +89,124 @@ 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);
+    if (header.size > BUFF_SZ) {
+        error_report("response exceeds maximum size\n");
+        return -EIO;
+    }
+
+    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 +245,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);
 
@@ -218,6 +337,37 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
@@ -252,6 +402,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;
@@ -269,15 +427,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)
@@ -493,8 +662,7 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
     v9fs_string_init(&newpath);
     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
 
-    retval = v9fs_request(ctx->private, T_LINK, NULL, "ss",
-                          oldpath, &newpath);
+    retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
     v9fs_string_free(&newpath);
     if (retval < 0) {
         errno = -retval;
@@ -547,8 +715,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 9a43f64..4d8dcc2 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 08/13] hw/9pfs: File ownership and others
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (6 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 07/13] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 09/13] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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 |   88 +++++++++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.c   |  148 +++++++++++++++++++++++++++++++++++++++----
 hw/9pfs/virtio-9p-proxy.h   |    6 ++
 4 files changed, 231 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 7510827..c11538c 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -535,6 +535,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;
@@ -579,6 +582,85 @@ static int process_requests(int sock)
         case T_READLINK:
             size = do_readlink(&in_iovec, &out_iovec);
             break;
+        case T_CHMOD:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sd", &path, &mode);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = chmod(path.data, mode);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            break;
+        case T_CHOWN:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sdd", &path,
+                            &uid, &gid);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = lchown(path.data, uid, gid);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            break;
+        case T_TRUNCATE:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sq",
+                            &path, &offset);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = truncate(path.data, offset);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            break;
+        case T_UTIME:
+            retval = 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);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = qemu_utimensat(AT_FDCWD, path.data, spec,
+                            AT_SYMLINK_NOFOLLOW);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            break;
+        case T_RENAME:
+            retval = proxy_unmarshal(&in_iovec, 1,
+                           HDR_SZ, "ss", &oldpath, &path);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = rename(oldpath.data, path.data);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&oldpath);
+            v9fs_string_free(&path);
+            break;
+        case T_REMOVE:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "s", &path);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = remove(path.data);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            break;
         default:
             goto error;
             break;
@@ -593,6 +675,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 aca799e..186d681 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -246,6 +246,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);
 
@@ -368,6 +370,77 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+	}
+        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);
@@ -397,6 +470,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;
@@ -561,8 +640,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,
@@ -674,34 +758,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 4d8dcc2..6a95e9c 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 09/13] hw/9pfs: xattr interfaces in proxy filesystem driver
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (7 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 08/13] hw/9pfs: File ownership and others M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 10/13] hw/9pfs: Proxy getversion M. Mohan Kumar
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

Add xattr support for proxy FS

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 fsdev/virtfs-proxy-helper.c |   93 ++++++++++++++++++++++++++++++-
 hw/9pfs/virtio-9p-proxy.c   |  130 +++++++++++++++++++++++++++++++++++++++---
 hw/9pfs/virtio-9p-proxy.h   |    4 +
 3 files changed, 216 insertions(+), 11 deletions(-)

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index c11538c..652fda6 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -28,6 +28,7 @@
 #include <stdbool.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"
@@ -297,6 +298,59 @@ 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);
+    retval = proxy_unmarshal(iovec, 1, HDR_SZ, "ds", &size, &path);
+    if (retval < 0) {
+        return -EOVERFLOW;
+    }
+    offset = HDR_SZ + retval;
+
+    if (size) {
+        xattr.data = g_malloc(size);
+        xattr.size = size;
+    }
+    switch (type) {
+    case T_LGETXATTR:
+        if (proxy_unmarshal(iovec, 1, offset, "s", &name)) {
+            retval = -EOVERFLOW;
+            goto error;
+        }
+        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);
+        if (retval < 0) {
+            retval = -EOVERFLOW;
+        }
+    }
+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));
@@ -539,9 +593,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;
@@ -661,6 +716,38 @@ 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:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "sssdd", &path,
+                            &name, &value, &size, &flags);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            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:
+            retval = proxy_unmarshal(&in_iovec, 1, HDR_SZ, "ss", &path, &name);
+            if (retval < 0) {
+                retval = -EOVERFLOW;
+                break;
+            }
+            retval = lremovexattr(path.data, name.data);
+            if (retval < 0) {
+                retval = -errno;
+            }
+            v9fs_string_free(&path);
+            v9fs_string_free(&name);
+            break;
         default:
             goto error;
             break;
@@ -681,11 +768,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 186d681..0d6af6d 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;
@@ -200,6 +200,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;
@@ -248,6 +261,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);
 
@@ -441,6 +455,55 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
@@ -476,6 +539,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;
@@ -484,7 +549,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;
         }
@@ -851,29 +919,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 6a95e9c..b1bfd03 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 10/13] hw/9pfs: Proxy getversion
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (8 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 09/13] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 11/13] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

Add proxy getversion to get generation number

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 fsdev/virtfs-proxy-helper.c |   77 +++++++++++++++++++++++++++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.c   |   34 +++++++++++++++++++
 hw/9pfs/virtio-9p-proxy.h   |    1 +
 3 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 652fda6..08ea316 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -29,6 +29,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"
@@ -54,6 +59,19 @@
         } \
     } while (0)
 
+#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'},
@@ -61,6 +79,7 @@ static struct option helper_opts[] = {
 };
 
 static bool is_daemon;
+static bool get_version; /* IOC getversion IOCTL supported */
 
 static int cap_set(void)
 {
@@ -298,6 +317,44 @@ 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;
+    }
+
+    if (proxy_unmarshal(iovec, 1, HDR_SZ, "s", &path) < 0) {
+        return -EOVERFLOW;
+    }
+
+    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;
@@ -748,6 +805,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;
@@ -777,6 +837,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;
             }
@@ -798,6 +859,8 @@ int main(int argc, char **argv)
     char *rpath = NULL;
     struct stat stbuf;
     int c, option_index;
+    int retval;
+    struct statfs st_fs;
 
     is_daemon = true;
     sock = -1;
@@ -854,6 +917,20 @@ int main(int argc, char **argv)
 
     do_log(LOG_INFO, "Started\n");
 
+    get_version = false;
+    /* 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 = true;
+            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 0d6af6d..44d4860 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -213,6 +213,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;
@@ -504,6 +507,16 @@ 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);
+        if (header.size < 0) {
+            goto out_overflow;
+        }
+        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);
@@ -551,6 +564,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) {
@@ -1033,6 +1047,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");
@@ -1067,6 +1100,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 b1bfd03..2312673 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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 11/13] hw/9pfs: Documentation changes related to proxy fs
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (9 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 10/13] hw/9pfs: Proxy getversion M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 12/13] hw/9pfs: man page for proxy helper M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 13/13] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 12/13] hw/9pfs: man page for proxy helper
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (10 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 11/13] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 13/13] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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] 15+ messages in thread

* [Qemu-devel] [PATCH V3 13/13] hw/9pfs: Add support to use named socket for proxy FS
  2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
                   ` (11 preceding siblings ...)
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 12/13] hw/9pfs: man page for proxy helper M. Mohan Kumar
@ 2011-11-21 13:36 ` M. Mohan Kumar
  12 siblings, 0 replies; 15+ messages in thread
From: M. Mohan Kumar @ 2011-11-21 13:36 UTC (permalink / raw)
  To: qemu-devel, aneesh.kumar, stefanha, berrange; +Cc: M. Mohan Kumar

From: "M. Mohan Kumar" <mohan@in.ibm.com>

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    |   86 ++++++++++++++++++++++++++++++++++++++-
 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, 157 insertions(+), 15 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 08ea316..18ced26 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -76,6 +76,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'},
 };
 
 static bool is_daemon;
@@ -635,11 +638,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));
 }
@@ -857,16 +910,20 @@ int main(int argc, char **argv)
 {
     int sock;
     char *rpath = NULL;
+    char *sock_name = NULL;
     struct stat stbuf;
     int c, option_index;
     int retval;
     struct statfs st_fs;
+    uid_t own_u;
+    gid_t own_g;
 
     is_daemon = true;
     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;
@@ -881,6 +938,15 @@ int main(int argc, char **argv)
         case 'f':
             sock = atoi(optarg);
             break;
+        case 's':
+            sock_name = strdup(optarg);
+            break;
+        case 'u':
+            own_u = atoi(optarg);
+            break;
+        case 'g':
+            own_g = atoi(optarg);
+            break;
         case '?':
         case 'h':
         default:
@@ -890,8 +956,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]);
         exit(EXIT_FAILURE);
     }
@@ -916,6 +990,12 @@ int main(int argc, char **argv)
     }
 
     do_log(LOG_INFO, "Started\n");
+    if (*sock_name) {
+        sock = proxy_socket(sock_name, own_u, own_g);
+        if (sock < 0) {
+            goto error;
+        }
+    }
 
     get_version = false;
     /* check whether underlying FS support IOC_GETVERSION */
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 44d4860..5c70395 100644
--- a/hw/9pfs/virtio-9p-proxy.c
+++ b/hw/9pfs/virtio-9p-proxy.c
@@ -1066,15 +1066,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;
 }
 
@@ -1083,10 +1117,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] 15+ messages in thread

* Re: [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code
  2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code M. Mohan Kumar
@ 2011-11-21 14:38   ` Aneesh Kumar K.V
  0 siblings, 0 replies; 15+ messages in thread
From: Aneesh Kumar K.V @ 2011-11-21 14:38 UTC (permalink / raw)
  To: M. Mohan Kumar, qemu-devel, stefanha, berrange

On Mon, 21 Nov 2011 19:06:07 +0530, "M. Mohan Kumar" <mohan@in.ibm.com> wrote:
> From: "M. Mohan Kumar" <mohan@in.ibm.com>
> 
> Add validatio check to {un}marshal code.
> 
> Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
> ---
>  fsdev/virtio-9p-marshal.c |   97 ++++++++++++-------
>  fsdev/virtio-9p-marshal.h |    8 +-
>  hw/9pfs/virtio-9p.c       |  231 +++++++++++++++++++++++++++++++++------------
>  3 files changed, 236 insertions(+), 100 deletions(-)
> 
> diff --git a/fsdev/virtio-9p-marshal.c b/fsdev/virtio-9p-marshal.c
> index 2da0a34..74161df 100644
> --- a/fsdev/virtio-9p-marshal.c
> +++ b/fsdev/virtio-9p-marshal.c
> @@ -62,14 +62,14 @@ void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
>  }
> 
> 
> -static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
> -                              size_t offset, size_t size, int pack)
> +static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
> +                              ssize_t offset, ssize_t size, int pack)
>  {
>      int i = 0;
> -    size_t copied = 0;
> +    ssize_t copied = 0;
> 
>      for (i = 0; size && i < sg_count; i++) {
> -        size_t len;
> +        ssize_t len;
>          if (offset >= sg[i].iov_len) {
>              /* skip this sg */
>              offset -= sg[i].iov_len;
> @@ -91,25 +91,29 @@ static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
>          }
>      }
> 
> +    /* could not copy requested 'size' */
> +    if (copied < 0) {
> +        return -1;
> +    }

I am not sure copied will be < 0 here even in error case


>      return copied;
>  }
> 
> -static size_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
> -                          size_t offset, size_t size)
> +static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
> +                          ssize_t offset, ssize_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)
> +ssize_t v9fs_pack(struct iovec *in_sg, int in_num, ssize_t offset,
> +                const void *src, ssize_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)
> +                        ssize_t offset, struct iovec *sg)
>  {
> -    size_t pos = 0;
> +    ssize_t pos = 0;
>      int i, j;
> 
>      j = 0;
> @@ -131,10 +135,10 @@ static int v9fs_copy_sg(struct iovec *src_sg, unsigned int num,
>      return j;
>  }
> 
> -size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
> -                int convert, const char *fmt, ...)
> +ssize_t v9fs_unmarshal(struct iovec *out_sg,
> +                int out_num, ssize_t offset, int convert, const char *fmt, ...)
>  {
> -    size_t old_offset = offset;
> +    ssize_t old_offset = offset, copied;
>      va_list ap;
>      int i;
> 
> @@ -143,13 +147,13 @@ size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
>          switch (fmt[i]) {
>          case 'b': {
>              uint8_t *valp = va_arg(ap, uint8_t *);
> -            offset += v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
> +            copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
>              break;
>          }

Do we really need error checking for unpack ? unpack reads the value
from the buffer and store them in arguments passed. So what is the
failure condition here ? We always will have enough space to unpack.


>          case 'w': {
>              uint16_t val, *valp;
>              valp = va_arg(ap, uint16_t *);
> -            offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
> +            copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
>              if (convert) {
>                  *valp = le16_to_cpu(val);
>              } else {

-aneesh

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-11-21 14:39 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-21 13:36 [Qemu-devel] [PATCH V3 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 01/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 02/13] hw/9pfs: Add validation to marshal code M. Mohan Kumar
2011-11-21 14:38   ` Aneesh Kumar K.V
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 03/13] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 05/13] hw/9pfs: Open and create files M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 06/13] hw/9pfs: Create other filesystem objects M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 07/13] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 08/13] hw/9pfs: File ownership and others M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 09/13] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 10/13] hw/9pfs: Proxy getversion M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 11/13] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 12/13] hw/9pfs: man page for proxy helper M. Mohan Kumar
2011-11-21 13:36 ` [Qemu-devel] [PATCH V3 13/13] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.