All of lore.kernel.org
 help / color / mirror / Atom feed
From: "M. Mohan Kumar" <mohan@in.ibm.com>
To: qemu-devel@nongnu.org, aneesh.kumar@linux.vnet.ibm.com
Cc: "M. Mohan Kumar" <mohan@in.ibm.com>
Subject: [Qemu-devel] [PATCH 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS
Date: Tue,  1 Nov 2011 02:23:23 +0530	[thread overview]
Message-ID: <1320094412-19091-5-git-send-email-mohan@in.ibm.com> (raw)
In-Reply-To: <1320094412-19091-1-git-send-email-mohan@in.ibm.com>

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
 {{-s|--socket <socketname> -u|--uid -g|--gid}|{-f|--fd <socket descriptor>}}
 -p <path-to-share>   [-r <runasuid> -t <runasgid>]

Where uid:gid gives socket access to uid:gid, -r:t combination drops the
privilege to given uid:gid

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 Makefile                      |    2 +
 configure                     |   25 ++++
 hw/9pfs/proxy.h               |    6 +
 hw/9pfs/virtfs-proxy-helper.c |  262 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 295 insertions(+), 0 deletions(-)
 create mode 100644 hw/9pfs/virtfs-proxy-helper.c

diff --git a/Makefile b/Makefile
index f63fc02..1fd443d 100644
--- a/Makefile
+++ b/Makefile
@@ -153,6 +153,8 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y)
 qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y)
 qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y)
 
+hw/9pfs/virtfs-proxy-helper$(EXESUF): LIBS+=$(LIBS_PROXY)
+
 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 19e8394..8abd17c 100755
--- a/configure
+++ b/configure
@@ -1866,6 +1866,23 @@ 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
+    libs_proxy="-lcap"
+  else
+    cap=no
+  fi
+fi
+
+##########################################
 # pthread probe
 PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
 
@@ -2636,6 +2653,9 @@ confdir=$sysconfdir$confsuffix
 tools=
 if test "$softmmu" = yes ; then
   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
+if test "$cap" = yes; then
+  tools="$tools hw/9pfs/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
@@ -3068,6 +3088,10 @@ if test "$linux_magic_h" = "yes" ; then
   echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
 fi
 
+if test "$cap" = "yes" ; then
+  echo "CONFIG_CAPABILITY=y" >> $config_host_mak
+fi
+
 # USB host support
 case "$usb" in
 linux)
@@ -3143,6 +3167,7 @@ echo "LIBS+=$LIBS" >> $config_host_mak
 echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
 echo "EXESUF=$EXESUF" >> $config_host_mak
 echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
+echo "LIBS_PROXY+=$libs_proxy" >> $config_host_mak
 
 # generate list of library paths for linker script
 
diff --git a/hw/9pfs/proxy.h b/hw/9pfs/proxy.h
index 1a47509..205d7b7 100644
--- a/hw/9pfs/proxy.h
+++ b/hw/9pfs/proxy.h
@@ -2,6 +2,12 @@
 #define __PROXY_HELP_H
 
 #define BUFF_SZ (4 * 1024)
+#define V9FS_FD_VALID INT_MAX
+
+union MsgControl {
+    struct cmsghdr cmsg;
+    char control[CMSG_SPACE(sizeof(int))];
+};
 
 typedef struct {
     int type;
diff --git a/hw/9pfs/virtfs-proxy-helper.c b/hw/9pfs/virtfs-proxy-helper.c
new file mode 100644
index 0000000..8e82ca7
--- /dev/null
+++ b/hw/9pfs/virtfs-proxy-helper.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <sys/fsuid.h>
+#include <stdarg.h>
+#include "bswap.h"
+#include <sys/socket.h>
+#include "qemu-common.h"
+#include "hw/9pfs/proxy.h"
+
+#define PROGNAME "virtfs-proxy-helper"
+
+static struct option helper_opts[] = {
+    {"fd", required_argument, NULL, 'f'},
+    {"path", required_argument, NULL, 'p'},
+    {"nodaemon", no_argument, NULL, 'n'},
+};
+
+int is_daemon;
+
+static void do_perror(const char *string)
+{
+    if (is_daemon) {
+        syslog(LOG_CRIT, "%s:%s", string, strerror(errno));
+    } else {
+        fprintf(stderr, "%s:%s\n", string, strerror(errno));
+    }
+}
+
+static void do_log(int level, const char *string)
+{
+    if (is_daemon) {
+        syslog(level, "%s", string);
+    } else {
+        fprintf(stderr, "%s\n", string);
+    }
+}
+
+static int cap_set(void)
+{
+    int retval;
+    cap_t caps;
+    cap_value_t cap_list[10];
+
+    /* helper needs following capbabilities only */
+    cap_list[0] = CAP_CHOWN;
+    cap_list[1] = CAP_DAC_OVERRIDE;
+    cap_list[2] = CAP_DAC_READ_SEARCH;
+    cap_list[3] = CAP_FOWNER;
+    cap_list[4] = CAP_FSETID;
+    cap_list[5] = CAP_SETGID;
+    cap_list[6] = CAP_MKNOD;
+    cap_list[7] = CAP_SETUID;
+
+    caps = cap_init();
+    if (caps == NULL) {
+        do_perror("cap_init");
+        return -1;
+    }
+    retval = cap_set_flag(caps, CAP_PERMITTED, 8, cap_list, CAP_SET);
+    if (retval < 0) {
+        do_perror("cap_set_flag");
+        goto error;
+    }
+    retval = cap_set_proc(caps);
+    if (retval < 0) {
+        do_perror("cap_set_proc");
+    }
+    retval = cap_set_flag(caps, CAP_EFFECTIVE, 8, cap_list, CAP_SET);
+    if (retval < 0) {
+        do_perror("cap_set_flag");
+        goto error;
+    }
+    retval = cap_set_proc(caps);
+    if (retval < 0) {
+        do_perror("cap_set_proc");
+    }
+
+error:
+    cap_free(caps);
+    return retval;
+}
+
+static int init_capabilities(void)
+{
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        do_perror("prctl");
+        return -1;
+    }
+    if (cap_set() < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static int socket_read(int sockfd, void *buff, ssize_t size)
+{
+    int retval;
+
+    do {
+        retval = read(sockfd, buff, size);
+    } while (retval < 0 && errno == EINTR);
+    if (retval != size) {
+        if (errno != ENOENT) {
+            do_perror("socket read");
+        }
+        return -EIO;
+    }
+    return retval;
+}
+
+static int socket_write(int sockfd, void *buff, ssize_t size)
+{
+    int retval;
+
+    do {
+        retval = write(sockfd, buff, size);
+    } while (retval < 0 && errno == EINTR);
+    if (retval != size) {
+        do_perror("socket_write");
+        return -EIO;
+    }
+    return retval;
+}
+
+static int read_request(int sockfd, struct iovec *iovec)
+{
+    int retval;
+    ProxyHeader header;
+
+    do {
+        retval = socket_read(sockfd, &header, sizeof(header));
+        if (retval != sizeof(header)) {
+            return -EIO;
+        }
+        retval = socket_read(sockfd, iovec->iov_base, header.size);
+        if (retval != header.size) {
+            return -EIO;
+        }
+        return header.type;
+    } while (1);
+}
+
+static void usage(char *prog)
+{
+    fprintf(stderr, "usage: %s\n"
+        " -p|--path <path> 9p path to export\n"
+        " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
+        " [-n|--nodaemon] Run as a normal program\n",
+        basename(prog));
+}
+
+static int process_requests(int sock)
+{
+    int type;
+    struct iovec iovec;
+
+    iovec.iov_base = g_malloc(BUFF_SZ);
+    iovec.iov_len = BUFF_SZ;
+    while (1) {
+        type = read_request(sock, &iovec);
+        if (type <= 0) {
+            goto error;
+        }
+    }
+    (void)socket_write;
+error:
+    g_free(iovec.iov_base);
+    return -1;
+}
+
+int main(int argc, char **argv)
+{
+    int sock;
+    char rpath[PATH_MAX];
+    struct stat stbuf;
+    int c, option_index;
+
+    is_daemon = 1;
+    rpath[0] = '\0';
+    sock = -1;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
+                        &option_index);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case 'p':
+            strcpy(rpath, optarg);
+            break;
+        case 'n':
+            is_daemon = 0;
+            break;
+	case 'f':
+            sock = atoi(optarg);
+            break;
+        case '?':
+        case 'h':
+        default:
+            usage(argv[0]);
+            return -1;
+            break;
+        }
+    }
+
+    /* Parameter validation */
+    if (sock == -1 || rpath[0] == '\0') {
+        fprintf(stderr, "socket descriptor or path not specified\n");
+        usage(argv[0]);
+        return -1;
+    }
+
+    if (lstat(rpath, &stbuf) < 0) {
+        fprintf(stderr, "invalid path \"%s\" specified?\n", rpath);
+        return -1;
+    }
+
+    if (!S_ISDIR(stbuf.st_mode)) {
+        fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
+        return -1;
+    }
+
+    if (is_daemon) {
+        if (daemon(1, 0) < 0) {
+            fprintf(stderr, "deamon error\n");
+            return -1;
+        }
+        openlog(PROGNAME, LOG_PID, LOG_DAEMON);
+    }
+
+    do_log(LOG_INFO, "Started");
+
+    if (chroot(rpath) < 0) {
+        do_perror("chroot");
+        goto error;
+    }
+    umask(0);
+
+    if (init_capabilities() < 0) {
+        goto error;
+    }
+
+    process_requests(sock);
+error:
+    do_log(LOG_INFO, "Done");
+    closelog();
+    return 0;
+}
-- 
1.7.6

  parent reply	other threads:[~2011-10-31 20:54 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-10-31 20:53 [Qemu-devel] [PATCH 00/13] Proxy FS driver for VirtFS M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 01/13] hw/9pfs: Move opt validation to FsDriver callback M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 02/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 03/13] hw/9pfs: Add new proxy filesystem driver M. Mohan Kumar
2011-10-31 20:53 ` M. Mohan Kumar [this message]
2011-10-31 20:53 ` [Qemu-devel] [PATCH 05/13] hw/9pfs: Add support to use named socket for proxy FS M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 06/13] hw/9pfs: Open and create files M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 07/13] hw/9pfs: Create other filesystem objects M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 08/13] hw/9pfs: Add stat/readlink/statfs for proxy FS M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 09/13] hw/9pfs: File ownership and others M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 10/13] hw/9pfs: xattr interfaces in proxy filesystem driver M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 12/13] hw/9pfs: Documentation changes related to proxy fs M. Mohan Kumar
2011-10-31 20:53 ` [Qemu-devel] [PATCH 13/13] hw/9pfs: man page for proxy helper M. Mohan Kumar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1320094412-19091-5-git-send-email-mohan@in.ibm.com \
    --to=mohan@in.ibm.com \
    --cc=aneesh.kumar@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.