From: "M. Mohan Kumar" <mo...@in.ibm.com> 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.
Signed-off-by: M. Mohan Kumar <mo...@in.ibm.com> --- hw/9pfs/virtfs-proxy-helper.c | 89 ++++++++++++++++++++++++++++++++++++++-- hw/9pfs/virtio-9p-proxy.c | 56 ++++++++++++++++++++++--- qemu-config.c | 6 +++ vl.c | 6 ++- 4 files changed, 144 insertions(+), 13 deletions(-) diff --git a/hw/9pfs/virtfs-proxy-helper.c b/hw/9pfs/virtfs-proxy-helper.c index 8e82ca7..9d925e0 100644 --- a/hw/9pfs/virtfs-proxy-helper.c +++ b/hw/9pfs/virtfs-proxy-helper.c @@ -26,6 +26,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'}, }; int is_daemon; @@ -153,11 +156,61 @@ static int read_request(int sockfd, struct iovec *iovec) } while (1); } +/* 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 <path> 9p path to export\n" " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n" + " {-s|--socket <socketname> socket file used for communication\n" + " \t-u|--uid <uid> -g|--gid <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)); } @@ -184,16 +237,20 @@ error: int main(int argc, char **argv) { int sock; + char sock_name[PATH_MAX]; char rpath[PATH_MAX]; struct stat stbuf; int c, option_index; + uid_t own_u; + gid_t own_g; is_daemon = 1; - rpath[0] = '\0'; + sock_name[0] = rpath[0] = '\0'; 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; @@ -205,9 +262,18 @@ int main(int argc, char **argv) case 'n': is_daemon = 0; break; - case 'f': + case 'f': sock = atoi(optarg); break; + case 's': + strcpy(sock_name, optarg); + break; + case 'u': + own_u = atoi(optarg); + break; + case 'g': + own_g = atoi(optarg); + break; case '?': case 'h': default: @@ -218,8 +284,15 @@ 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 specifies who can access the socket file\n"); usage(argv[0]); return -1; } @@ -243,6 +316,12 @@ int main(int argc, char **argv) } do_log(LOG_INFO, "Started"); + if (*sock_name) { + sock = proxy_socket(sock_name, own_u, own_g); + if (sock < 0) { + goto error; + } + } if (chroot(rpath) < 0) { do_perror("chroot"); diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index c682e36..0ec686c 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -16,6 +16,10 @@ #include "fsdev/qemu-fsdev.h" #include "proxy.h" +/* FS specific flags */ +#define V9FS_PROXY_SOCK_FD (1 << 9) +#define V9FS_PROXY_SOCK_NAME (1 << 10) + typedef struct V9fsProxy { int sockfd; QemuMutex mutex; @@ -301,15 +305,49 @@ static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, return ret; } +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; } @@ -318,10 +356,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 5e63c14..6203e7b 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -187,6 +187,9 @@ QemuOptsList qemu_fsdev_opts = { }, { .name = "sock_fd", .type = QEMU_OPT_NUMBER, + }, { + .name = "socket", + .type = QEMU_OPT_STRING, }, { /*End of list */ } @@ -219,6 +222,9 @@ QemuOptsList qemu_virtfs_opts = { }, { .name = "sock_fd", .type = QEMU_OPT_NUMBER, + }, { + .name = "socket", + .type = QEMU_OPT_STRING, }, { /*End of list */ } diff --git a/vl.c b/vl.c index 5a5ab7f..8fbf481 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); -- 1.7.6