From patchwork Mon Nov 21 13:36:18 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mohan Kumar M X-Patchwork-Id: 126815 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A5C76B720B for ; Tue, 22 Nov 2011 02:14:25 +1100 (EST) Received: from localhost ([::1]:46302 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU3h-0000HA-M8 for incoming@patchwork.ozlabs.org; Mon, 21 Nov 2011 08:37:17 -0500 Received: from eggs.gnu.org ([140.186.70.92]:46598) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU3H-0008O0-CI for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RSU3A-0008Sd-34 for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:51 -0500 Received: from e23smtp07.au.ibm.com ([202.81.31.140]:44728) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RSU39-0008Ry-3r for qemu-devel@nongnu.org; Mon, 21 Nov 2011 08:36:44 -0500 Received: from /spool/local by e23smtp07.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 21 Nov 2011 13:34:49 +1000 Received: from d23relay04.au.ibm.com ([202.81.31.246]) by e23smtp07.au.ibm.com ([202.81.31.204]) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 21 Nov 2011 13:34:47 +1000 Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay04.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id pALDXOYn3178582 for ; Tue, 22 Nov 2011 00:33:24 +1100 Received: from d23av03.au.ibm.com (loopback [127.0.0.1]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id pALDacqo006100 for ; Tue, 22 Nov 2011 00:36:38 +1100 Received: from explorer.in.ibm.com (explorer.in.ibm.com [9.122.21.115]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id pALDaGuH004347; Tue, 22 Nov 2011 00:36:36 +1100 From: "M. Mohan Kumar" To: qemu-devel@nongnu.org, aneesh.kumar@linux.vnet.ibm.com, stefanha@gmail.com, berrange@redhat.com Date: Mon, 21 Nov 2011 19:06:18 +0530 Message-Id: <1321882578-7498-14-git-send-email-mohan@in.ibm.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1321882578-7498-1-git-send-email-mohan@in.ibm.com> References: <1321882578-7498-1-git-send-email-mohan@in.ibm.com> x-cbid: 11112103-0260-0000-0000-000000141D82 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.81.31.140 Cc: "M. Mohan Kumar" Subject: [Qemu-devel] [PATCH V3 13/13] hw/9pfs: Add support to use named socket for proxy FS X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "M. Mohan Kumar" 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<>, 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 Signed-off-by: Aneesh Kumar K.V --- 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 9p path to export\n" " {-f|--fd } socket file descriptor to be used\n" + " {-s|--socket socket file used for communication\n" + " \t-u|--uid -g|--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);