[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 04/13] hw/9pfs: File system helper process for qemu
From: |
M. Mohan Kumar |
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 |
From: "M. Mohan Kumar" <address@hidden>
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 <address@hidden>
---
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
- [Qemu-devel] [PATCH 00/13] Proxy FS driver for VirtFS, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 01/13] hw/9pfs: Move opt validation to FsDriver callback, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 04/13] hw/9pfs: File system helper process for qemu 9p proxy FS,
M. Mohan Kumar <=
- [Qemu-devel] [PATCH 02/13] hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 06/13] hw/9pfs: Open and create files, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 05/13] hw/9pfs: Add support to use named socket for proxy FS, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 07/13] hw/9pfs: Create other filesystem objects, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 08/13] hw/9pfs: Add stat/readlink/statfs for proxy FS, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 10/13] hw/9pfs: xattr interfaces in proxy filesystem driver, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 03/13] hw/9pfs: Add new proxy filesystem driver, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 12/13] hw/9pfs: Documentation changes related to proxy fs, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 09/13] hw/9pfs: File ownership and others, M. Mohan Kumar, 2011/10/31
- [Qemu-devel] [PATCH 13/13] hw/9pfs: man page for proxy helper, M. Mohan Kumar, 2011/10/31