Note that 'virsh lxc-enter-namespace' must double-fork, for two reasons: some namespaces can only be done from a single thread, while virsh is multithreaded; and because virsh can be run in batch mode where we must not corrupt the namespace of that execution upon return from the subsidiary command. When virt-login-shell was first written, it blindly copied from 'virsh lxc-enter-namespace', including the double-fork. But neither of the reasons for double forking apply to virt-login-shell (we are single-threaded, and we have nothing to do after the child completes that would require us to preserve a namespace), so we can simplify life by using a single fork. In turn, this will make it easier for a future patch to pass the child's exit status on to the invoking shell. In flattening to a single fork, note that closing the fds must be done after fork, because the parent process still needs to use fds to control the virConnectPtr; meanwhile, chdir can be done prior to forking (in fact, it's easier to report errors on anything attempted before forking). * tools/virt-login-shell.c (main): Single rather than double fork. (virLoginShellFini): Delete, by inlining actions instead. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- tools/virt-login-shell.c | 116 ++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 73 deletions(-) diff --git a/tools/virt-login-shell.c b/tools/virt-login-shell.c index 666facf..75a5223 100644 --- a/tools/virt-login-shell.c +++ b/tools/virt-login-shell.c @@ -41,24 +41,8 @@ #include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_NONE -static ssize_t nfdlist; -static int *fdlist; static const char *conf_file = SYSCONFDIR "/libvirt/virt-login-shell.conf"; -static void virLoginShellFini(virConnectPtr conn, virDomainPtr dom) -{ - size_t i; - - for (i = 0; i < nfdlist; i++) - VIR_FORCE_CLOSE(fdlist[i]); - VIR_FREE(fdlist); - nfdlist = 0; - if (dom) - virDomainFree(dom); - if (conn) - virConnectClose(conn); -} - static int virLoginShellAllowedUser(virConfPtr conf, const char *name, gid_t *groups) @@ -187,7 +171,6 @@ main(int argc, char **argv) pid_t cpid; int ret = EXIT_FAILURE; int status; - int status2; uid_t uid = getuid(); gid_t gid = getgid(); char *name = NULL; @@ -201,6 +184,10 @@ main(int argc, char **argv) int longindex = -1; int ngroups; gid_t *groups = NULL; + ssize_t nfdlist = 0; + int *fdlist = NULL; + int openmax; + size_t i; struct option opt[] = { {"help", no_argument, NULL, 'h'}, @@ -298,6 +285,13 @@ main(int argc, char **argv) } } + openmax = sysconf(_SC_OPEN_MAX); + if (openmax < 0) { + virReportSystemError(errno, "%s", + _("sysconf(_SC_OPEN_MAX) failed")); + goto cleanup; + } + if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) goto cleanup; if (VIR_ALLOC(secmodel) < 0) @@ -308,76 +302,52 @@ main(int argc, char **argv) goto cleanup; if (virDomainGetSecurityLabel(dom, seclabel) < 0) goto cleanup; + if (virSetUIDGID(0, 0, NULL, 0) < 0) + goto cleanup; + if (virDomainLxcEnterSecurityLabel(secmodel, seclabel, NULL, 0) < 0) + goto cleanup; + if (nfdlist > 0 && + virDomainLxcEnterNamespace(dom, nfdlist, fdlist, NULL, NULL, 0) < 0) + goto cleanup; + if (virSetUIDGID(uid, gid, groups, ngroups) < 0) + goto cleanup; + if (chdir(homedir) < 0) { + virReportSystemError(errno, _("Unable to chdir(%s)"), homedir); + goto cleanup; + } - /* Fork once because we don't want to affect virt-login-shell's - * namespace itself. FIXME: is this necessary? - */ + /* A fork is required to create new process in correct pid namespace. */ if ((cpid = virFork()) < 0) goto cleanup; if (cpid == 0) { - pid_t ccpid; - - int openmax = sysconf(_SC_OPEN_MAX); - int fd; + int tmpfd; - if (virSetUIDGID(0, 0, NULL, 0) < 0) - return EXIT_FAILURE; - - if (virDomainLxcEnterSecurityLabel(secmodel, - seclabel, - NULL, - 0) < 0) - return EXIT_FAILURE; - - if (nfdlist > 0) { - if (virDomainLxcEnterNamespace(dom, - nfdlist, - fdlist, - NULL, - NULL, - 0) < 0) - return EXIT_FAILURE; - } - - ret = virSetUIDGID(uid, gid, groups, ngroups); - VIR_FREE(groups); - if (ret < 0) - return EXIT_FAILURE; - - if (openmax < 0) { - virReportSystemError(errno, "%s", - _("sysconf(_SC_OPEN_MAX) failed")); - return EXIT_FAILURE; - } - for (fd = 3; fd < openmax; fd++) { - int tmpfd = fd; + for (i = 3; i < openmax; i++) { + tmpfd = i; VIR_MASS_CLOSE(tmpfd); } - - /* A fork is required to create new process in correct pid - * namespace. */ - if ((ccpid = virFork()) < 0) + if (execv(shargv[0], (char *const*) shargv) < 0) { + virReportSystemError(errno, _("Unable to exec shell %s"), + shargv[0]); return EXIT_FAILURE; - - if (ccpid == 0) { - if (chdir(homedir) < 0) { - virReportSystemError(errno, _("Unable to chdir(%s)"), homedir); - return EXIT_FAILURE; - } - if (execv(shargv[0], (char *const*) shargv) < 0) { - virReportSystemError(errno, _("Unable to exec shell %s"), - shargv[0]); - return EXIT_FAILURE; - } } - return virProcessWait(ccpid, &status2, true); + return EXIT_SUCCESS; } - ret = virProcessWait(cpid, &status, true); + + if (virProcessWait(cpid, &status, true) < 0) + goto cleanup; + ret = EXIT_SUCCESS; cleanup: + for (i = 0; i < nfdlist; i++) + VIR_FORCE_CLOSE(fdlist[i]); + VIR_FREE(fdlist); virConfFree(conf); - virLoginShellFini(conn, dom); + if (dom) + virDomainFree(dom); + if (conn) + virConnectClose(conn); virStringFreeList(shargv); VIR_FREE(name); VIR_FREE(homedir); -- 1.8.5.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list