[libvirt] [PATCH V3] Add proxy FS support to libvirt
M. Mohan Kumar
mohan at in.ibm.com
Fri Aug 31 14:21:16 UTC 2012
Hi Daniel,
Any comment?
On Thu, 23 Aug 2012 14:36:40 +0530, "M. Mohan Kumar" <mohan at in.ibm.com> wrote:
> From: "M. Mohan Kumar" <mohan at in.ibm.com>
>
> A new FS driver type 'proxy' is added to QEMU 9p server. This patch adds
> support for using proxy FS driver from libvirt.
>
> QEMU proxy FS driver uses socket for communicating between helper and qemu
> proxy FS driver. Proxy helper (a stand alone binary part of qemu) is invoked
> with one of the descriptors created using socketpair call and the share path.
> Similarly QEMU is invoked with another descriptor created using the same
> socketpair system call and with other required FS driver parameters.
>
> Need for proxy FS driver
> ========================
> Pass through security model in QEMU 9p server has following issues:
> 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 (pass
> through security model needs root privilege).
>
> Proxy FS driver is implemented to solve these issues.
>
> 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 in a chroot environment using socket IO.
>
> Proxy helper is invoked with root privileges and chroots into 9p export path.
> QEMU proxy fs driver sends filesystem request to proxy helper and receives the
> response from it.
>
> Proxy helper is designed such a way that it needs only few capabilities related
> to filesystem operations (such as CAP_DAC_OVERRIDE, CAP_FOWNER, etc) and all
> other capabilities are dropped (CAP_SYS_CHROOT, etc)
>
> Proxy patches
> http://permalink.gmane.org/gmane.comp.emulators.qemu/128735
>
> Signed-off-by: M. Mohan Kumar <mohan at in.ibm.com>
> ---
> Changes from previous version V3
> * Addressed Daniel's review comments
>
> Changes from previous version V2
> * Rebased on top of current libvirt git level
>
> Changes from previous version
> * Remove the xml node for specifying the virtfs-proxy-helper path, now it is
> determined from qemu binary path.
>
> docs/formatdomain.html.in | 2 +
> src/conf/domain_conf.c | 3 +-
> src/conf/domain_conf.h | 2 +-
> src/qemu/qemu_capabilities.c | 5 ++-
> src/qemu/qemu_capabilities.h | 1 +
> src/qemu/qemu_command.c | 83 ++++++++++++++++++++++++++++++++++++++++--
> src/qemu/qemu_command.h | 3 +-
> tests/qemuhelptest.c | 7 +++-
> 8 files changed, 96 insertions(+), 10 deletions(-)
>
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index 2c5c456..bf74ed8 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -1621,6 +1621,8 @@
> while the value <code>immediate</code> means that a host writeback
> is immediately triggered for all pages touched during a guest file
> write operation <span class="since">(since 0.9.10)</span>.
> + or <code>type='proxy'</code> <span class="since">(since
> + 1.0)</span>.
> </dd>
> <dt><code>type='template'</code></dt>
> <dd>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 851284a..79ca2b7 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -268,7 +268,8 @@ VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
> VIR_ENUM_IMPL(virDomainFSDriverType, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
> "default",
> "path",
> - "handle")
> + "handle",
> + "proxy")
>
> VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
> "passthrough",
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index fd0e89e..a296f49 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -660,6 +660,7 @@ enum virDomainFSDriverType {
> VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT = 0,
> VIR_DOMAIN_FS_DRIVER_TYPE_PATH,
> VIR_DOMAIN_FS_DRIVER_TYPE_HANDLE,
> + VIR_DOMAIN_FS_DRIVER_TYPE_PROXY,
>
> VIR_DOMAIN_FS_DRIVER_TYPE_LAST
> };
> @@ -698,7 +699,6 @@ struct _virDomainFSDef {
> unsigned long long space_soft_limit; /* in bytes */
> };
>
> -
> /* 5 different types of networking config */
> enum virDomainNetType {
> VIR_DOMAIN_NET_TYPE_USER,
> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index 5472267..88b7e87 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
> @@ -144,7 +144,6 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
> "ich9-ahci",
> "no-acpi",
> "fsdev-readonly",
> -
> "virtio-blk-pci.scsi", /* 80 */
> "blk-sg-io",
> "drive-copy-on-read",
> @@ -172,7 +171,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
> "bridge", /* 100 */
> "lsi",
> "virtio-scsi-pci",
> -
> + "fsdev-proxy",
> );
>
> struct qemu_feature_flags {
> @@ -1133,6 +1132,8 @@ qemuCapsComputeCmdFlags(const char *help,
> qemuCapsSet(flags, QEMU_CAPS_FSDEV_READONLY);
> if (strstr(fsdev, "writeout"))
> qemuCapsSet(flags, QEMU_CAPS_FSDEV_WRITEOUT);
> + if (strstr(fsdev, "sock_fd"))
> + qemuCapsSet(flags, QEMU_CAPS_FSDEV_PROXY);
> }
> if (strstr(help, "-smbios type"))
> qemuCapsSet(flags, QEMU_CAPS_SMBIOS_TYPE);
> diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
> index d606890..073a1cd 100644
> --- a/src/qemu/qemu_capabilities.h
> +++ b/src/qemu/qemu_capabilities.h
> @@ -138,6 +138,7 @@ enum qemuCapsFlags {
> QEMU_CAPS_NETDEV_BRIDGE = 100, /* bridge helper support */
> QEMU_CAPS_SCSI_LSI = 101, /* -device lsi */
> QEMU_CAPS_VIRTIO_SCSI_PCI = 102, /* -device virtio-scsi-pci */
> + QEMU_CAPS_FSDEV_PROXY = 103, /* -fsdev proxy supported */
>
> QEMU_CAPS_LAST, /* this must always be the last item */
> };
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 4ca3047..3f78635 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -46,6 +46,7 @@
> #include <sys/utsname.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> +#include <libgen.h>
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
>
> @@ -116,7 +117,8 @@ VIR_ENUM_DECL(qemuDomainFSDriver)
> VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
> "local",
> "local",
> - "handle");
> + "handle",
> + "proxy");
>
>
> static void
> @@ -2632,9 +2634,59 @@ error:
> return NULL;
> }
>
> +/*
> + * Invokes the Proxy Helper with one of the socketpair as its parameter
> + *
> + */
> +static int qemuInvokeProxyHelper(const char *emulator, int sock, const char *path)
> +{
> +#define HELPER "virtfs-proxy-helper"
> + int ret_val, status;
> + virCommandPtr cmd;
> + char *helper, *dname, *dp;
> +
> + dp = strdup(emulator);
> + if (!dp) {
> + virReportOOMError();
> + return -1;
> + }
> + dname = strrchr(dp, '/');
> + if (!dname) {
> + VIR_FREE(dp);
> + VIR_FORCE_CLOSE(sock);
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to get path details from %s"), dp);
> + return -1;
> + }
> + *dname = '\0';
> + if (virAsprintf(&helper, "%s/%s", dp, HELPER) < 0) {
> + VIR_FREE(dp);
> + VIR_FORCE_CLOSE(sock);
> + virReportOOMError();
> + return -1;
> + }
> +
> + cmd = virCommandNewArgList(helper, NULL);
> + virCommandAddArg(cmd, "-f");
> + virCommandAddArgFormat(cmd, "%d", sock);
> + virCommandAddArg(cmd, "-p");
> + virCommandAddArgFormat(cmd, "%s", path);
> + virCommandTransferFD(cmd, sock);
> + virCommandDaemonize(cmd);
> + ret_val = virCommandRun(cmd, &status);
> + if (ret_val < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("%s can't execute"), helper);
> + VIR_FORCE_CLOSE(sock);
> + }
> + virCommandFree(cmd);
> + VIR_FREE(helper);
> + VIR_FREE(dp);
> + return ret_val;
> +}
>
> char *qemuBuildFSStr(virDomainFSDefPtr fs,
> - virBitmapPtr qemuCaps ATTRIBUTE_UNUSED)
> + virBitmapPtr qemuCaps ATTRIBUTE_UNUSED, int qemuSocket)
> {
> virBuffer opt = VIR_BUFFER_INITIALIZER;
> const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
> @@ -2683,6 +2735,10 @@ char *qemuBuildFSStr(virDomainFSDefPtr fs,
> }
>
> virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
> +
> + if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY)
> + virBufferAsprintf(&opt, ",sock_fd=%d", qemuSocket);
> +
> virBufferAsprintf(&opt, ",path=%s", fs->src);
>
> if (fs->readonly) {
> @@ -5153,10 +5209,31 @@ qemuBuildCommandLine(virConnectPtr conn,
> if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV)) {
> for (i = 0 ; i < def->nfss ; i++) {
> char *optstr;
> + int sockets[2] = {-1, -1};
> virDomainFSDefPtr fs = def->fss[i];
>
> + /*
> + * If its a proxy FS, we need to create a socket pair
> + * and invoke proxy_helper
> + */
> + if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY) {
> + if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV_PROXY) < 0) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("proxy helper not supported"));
> + goto error;
> + }
> + /* create a socket pair */
> + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
> + virReportSystemError(errno, _("socketpair %s"), "failed");
> + goto error;
> + }
> + virCommandTransferFD(cmd, sockets[1]);
> + if (qemuInvokeProxyHelper(def->emulator, sockets[0],
> + fs->src) < 0)
> + goto error;
> + }
> virCommandAddArg(cmd, "-fsdev");
> - if (!(optstr = qemuBuildFSStr(fs, qemuCaps)))
> + if (!(optstr = qemuBuildFSStr(fs, qemuCaps, sockets[1])))
> goto error;
> virCommandAddArg(cmd, optstr);
> VIR_FREE(optstr);
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index e999bc7..2da5ad0 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -89,7 +89,8 @@ char *qemuBuildDriveStr(virConnectPtr conn,
> bool bootable,
> virBitmapPtr qemuCaps);
> char *qemuBuildFSStr(virDomainFSDefPtr fs,
> - virBitmapPtr qemuCaps);
> + virBitmapPtr qemuCaps,
> + int qemuSocket);
>
> /* Current, best practice */
> char * qemuBuildDriveDevStr(virDomainDefPtr def,
> diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
> index 2d15c94..6af2e68 100644
> --- a/tests/qemuhelptest.c
> +++ b/tests/qemuhelptest.c
> @@ -679,7 +679,9 @@ mymain(void)
> QEMU_CAPS_SCSI_BLOCK,
> QEMU_CAPS_SCSI_CD,
> QEMU_CAPS_IDE_CD,
> - QEMU_CAPS_SCSI_LSI);
> + QEMU_CAPS_SCSI_LSI,
> + QEMU_CAPS_FSDEV_PROXY);
> +
> DO_TEST("qemu-1.1.0", 1001000, 0, 0,
> QEMU_CAPS_VNC_COLON,
> QEMU_CAPS_NO_REBOOT,
> @@ -759,7 +761,8 @@ mymain(void)
> QEMU_CAPS_NEC_USB_XHCI,
> QEMU_CAPS_NETDEV_BRIDGE,
> QEMU_CAPS_SCSI_LSI,
> - QEMU_CAPS_VIRTIO_SCSI_PCI);
> + QEMU_CAPS_VIRTIO_SCSI_PCI,
> + QEMU_CAPS_FSDEV_PROXY);
>
> return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> }
> --
> 1.7.7.6
>
More information about the libvir-list
mailing list