From patchwork Mon Dec 5 16:18:50 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "M. Mohan Kumar" X-Patchwork-Id: 129362 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 EF5711007D4 for ; Tue, 6 Dec 2011 03:55:55 +1100 (EST) Received: from localhost ([::1]:54300 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RXbJf-0001ex-FU for incoming@patchwork.ozlabs.org; Mon, 05 Dec 2011 11:22:55 -0500 Received: from eggs.gnu.org ([140.186.70.92]:36009) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RXbIt-0008Sb-R8 for qemu-devel@nongnu.org; Mon, 05 Dec 2011 11:22:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RXbIm-0008W3-Kx for qemu-devel@nongnu.org; Mon, 05 Dec 2011 11:22:07 -0500 Received: from mail-iy0-f173.google.com ([209.85.210.173]:51365) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RXbIm-0008QH-3P for qemu-devel@nongnu.org; Mon, 05 Dec 2011 11:22:00 -0500 Received: by mail-iy0-f173.google.com with SMTP id k32so10138078iak.4 for ; Mon, 05 Dec 2011 08:21:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=nnC2PCYmmd7NuS7QNt3o3lLIZWwDuZ+YErvkKVjaJ/k=; b=sQAHFHLjhjYYsMvqcddB0zwga05woqbWd6DNH+MSOEI7nN9gJWhwZImLo2n9ctBiw8 kx94uHg8KA4lJdbQJx8POaWDLibqCsXpI7q6KvGjFYQKI3HvT73WWyuWjbHRkywWidGl 3cv5Kx93SZZSdlT4TgjdXfPqueJvqXsrF+gRA= Received: by 10.42.96.132 with SMTP id j4mr10869298icn.50.1323102119840; Mon, 05 Dec 2011 08:21:59 -0800 (PST) Received: from explorer.in.ibm.com ([117.192.11.142]) by mx.google.com with ESMTPS id el2sm78245721ibb.10.2011.12.05.08.21.56 (version=SSLv3 cipher=OTHER); Mon, 05 Dec 2011 08:21:59 -0800 (PST) From: "M. Mohan Kumar" To: qemu-devel@nongnu.org, aneesh.kumar@linux.vnet.ibm.com, stefanha@gmail.com Date: Mon, 5 Dec 2011 21:48:50 +0530 Message-Id: <1323101930-27163-14-git-send-email-mohan@in.ibm.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1323101930-27163-1-git-send-email-mohan@in.ibm.com> References: <1323101930-27163-1-git-send-email-mohan@in.ibm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.210.173 Cc: "M. Mohan Kumar" Subject: [Qemu-devel] [PATCH V4 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 73de79f..4f76f9d 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 a6bd6dc..d526973 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -57,6 +57,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; @@ -702,11 +705,61 @@ err_out: return ret; } +/* 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)); } @@ -960,16 +1013,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; @@ -984,6 +1041,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: @@ -993,8 +1059,16 @@ int main(int argc, char **argv) } /* Parameter validation */ - if (sock == -1 || rpath == NULL) { - fprintf(stderr, "socket descriptor or path not specified\n"); + if ((sock_name == NULL && sock == -1) || rpath == NULL) { + 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); } @@ -1019,6 +1093,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; #ifdef FS_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 65c17d6..e567b52 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -1115,15 +1115,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; } @@ -1132,10 +1166,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 fe43b4e..60f0d2f 100644 --- a/vl.c +++ b/vl.c @@ -2669,7 +2669,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) { @@ -2709,6 +2709,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);