libvirt/tests/commandhelper.c

238 lines
6.0 KiB
C
Raw Normal View History

/*
* commandhelper.c: Auxiliary program for commandtest
*
* Copyright (C) 2010-2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <poll.h>
#include "internal.h"
#define NO_LIBVIRT
#include "testutils.h"
#ifndef WIN32
# define VIR_FROM_THIS VIR_FROM_NONE
static int envsort(const void *a, const void *b)
{
const char *const*astrptr = a;
const char *const*bstrptr = b;
const char *astr = *astrptr;
const char *bstr = *bstrptr;
char *aeq = strchr(astr, '=');
char *beq = strchr(bstr, '=');
char *akey;
char *bkey;
int ret;
Stop linking tests/commandhelper to libvirt code The commandhelper binary is a helper for commandtest that validates what file handles were inherited. For this to work reliably we must not have any libraries that leak file descriptors into commandhelper. Unfortunately some versions of gnutls will intentionally open file handles at library load time via a constructor function. We previously hacked around this in commit 4cbc15d037e1cd8abf5c4aa6acc30d83ae13e34d Author: Martin Kletzander <mkletzan@redhat.com> Date: Fri May 2 09:55:52 2014 +0200 tests: don't fail with newer gnutls gnutls-3.3.0 and newer leaves 2 FDs open in order to be backwards compatible when it comes to chrooted binaries [1]. Linking commandhelper with gnutls then leaves these two FDs open and commandtest fails thanks to that. This patch does not link commandhelper with libvirt.la, but rather only the utilities making the test pass. Based on suggestion from Daniel [2]. [1] http://lists.gnutls.org/pipermail/gnutls-help/2014-April/003429.html [2] https://www.redhat.com/archives/libvir-list/2014-April/msg01119.html That fix relied on fact that while libvirt.so linked with gnutls, libvirt_util.la did not link to it. With the introduction of the util/vircrypto.c file that assumption is no longer valid. We must not link to libvirt_util.la at all - only gnulib and libc can (hopefully) be relied on not to open random file descriptors in constructors. Reviewed-by: Martin Kletzander <mkletzan@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-09-20 11:03:47 +00:00
if (!(akey = strndup(astr, aeq - astr)))
abort();
if (!(bkey = strndup(bstr, beq - bstr)))
abort();
ret = strcmp(akey, bkey);
Stop linking tests/commandhelper to libvirt code The commandhelper binary is a helper for commandtest that validates what file handles were inherited. For this to work reliably we must not have any libraries that leak file descriptors into commandhelper. Unfortunately some versions of gnutls will intentionally open file handles at library load time via a constructor function. We previously hacked around this in commit 4cbc15d037e1cd8abf5c4aa6acc30d83ae13e34d Author: Martin Kletzander <mkletzan@redhat.com> Date: Fri May 2 09:55:52 2014 +0200 tests: don't fail with newer gnutls gnutls-3.3.0 and newer leaves 2 FDs open in order to be backwards compatible when it comes to chrooted binaries [1]. Linking commandhelper with gnutls then leaves these two FDs open and commandtest fails thanks to that. This patch does not link commandhelper with libvirt.la, but rather only the utilities making the test pass. Based on suggestion from Daniel [2]. [1] http://lists.gnutls.org/pipermail/gnutls-help/2014-April/003429.html [2] https://www.redhat.com/archives/libvir-list/2014-April/msg01119.html That fix relied on fact that while libvirt.so linked with gnutls, libvirt_util.la did not link to it. With the introduction of the util/vircrypto.c file that assumption is no longer valid. We must not link to libvirt_util.la at all - only gnulib and libc can (hopefully) be relied on not to open random file descriptors in constructors. Reviewed-by: Martin Kletzander <mkletzan@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-09-20 11:03:47 +00:00
free(akey);
free(bkey);
return ret;
}
int main(int argc, char **argv) {
size_t i, n;
int open_max;
char **origenv;
char **newenv = NULL;
char *cwd;
FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
int ret = EXIT_FAILURE;
int readfds[3] = { STDIN_FILENO, };
int numreadfds = 1;
struct pollfd fds[3];
int numpollfds = 0;
char *buffers[3] = {NULL, NULL, NULL};
size_t buflen[3] = {0, 0, 0};
char c;
if (!log)
return ret;
for (i = 1; i < argc; i++) {
fprintf(log, "ARG:%s\n", argv[i]);
if (STREQ(argv[i - 1], "--readfd") &&
sscanf(argv[i], "%u%c", &readfds[numreadfds++], &c) != 1) {
printf("Could not parse fd %s\n", argv[i]);
goto cleanup;
}
}
origenv = environ;
n = 0;
while (*origenv != NULL) {
n++;
origenv++;
}
Stop linking tests/commandhelper to libvirt code The commandhelper binary is a helper for commandtest that validates what file handles were inherited. For this to work reliably we must not have any libraries that leak file descriptors into commandhelper. Unfortunately some versions of gnutls will intentionally open file handles at library load time via a constructor function. We previously hacked around this in commit 4cbc15d037e1cd8abf5c4aa6acc30d83ae13e34d Author: Martin Kletzander <mkletzan@redhat.com> Date: Fri May 2 09:55:52 2014 +0200 tests: don't fail with newer gnutls gnutls-3.3.0 and newer leaves 2 FDs open in order to be backwards compatible when it comes to chrooted binaries [1]. Linking commandhelper with gnutls then leaves these two FDs open and commandtest fails thanks to that. This patch does not link commandhelper with libvirt.la, but rather only the utilities making the test pass. Based on suggestion from Daniel [2]. [1] http://lists.gnutls.org/pipermail/gnutls-help/2014-April/003429.html [2] https://www.redhat.com/archives/libvir-list/2014-April/msg01119.html That fix relied on fact that while libvirt.so linked with gnutls, libvirt_util.la did not link to it. With the introduction of the util/vircrypto.c file that assumption is no longer valid. We must not link to libvirt_util.la at all - only gnulib and libc can (hopefully) be relied on not to open random file descriptors in constructors. Reviewed-by: Martin Kletzander <mkletzan@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-09-20 11:03:47 +00:00
if (!(newenv = malloc(sizeof(*newenv) * n)))
abort();
origenv = environ;
n = i = 0;
while (*origenv != NULL) {
newenv[i++] = *origenv;
n++;
origenv++;
}
qsort(newenv, n, sizeof(newenv[0]), envsort);
for (i = 0; i < n; i++) {
/* Ignore the variables used to instruct the loader into
* behaving differently, as they could throw the tests off. */
if (!STRPREFIX(newenv[i], "LD_"))
fprintf(log, "ENV:%s\n", newenv[i]);
}
open_max = sysconf(_SC_OPEN_MAX);
if (open_max < 0)
goto cleanup;
for (i = 0; i < open_max; i++) {
int f;
int closed;
if (i == fileno(log))
continue;
closed = fcntl(i, F_GETFD, &f) == -1 &&
errno == EBADF;
if (!closed)
fprintf(log, "FD:%zu\n", i);
}
fprintf(log, "DAEMON:%s\n", getpgrp() == getsid(0) ? "yes" : "no");
if (!(cwd = getcwd(NULL, 0)))
goto cleanup;
if (strlen(cwd) > strlen(".../commanddata") &&
STREQ(cwd + strlen(cwd) - strlen("/commanddata"), "/commanddata"))
strcpy(cwd, ".../commanddata");
# ifdef __APPLE__
char *noprivateprefix = NULL;
if (strstr(cwd, "/private"))
noprivateprefix = cwd + strlen("/private");
else
noprivateprefix = cwd;
fprintf(log, "CWD:%s\n", noprivateprefix);
# else
fprintf(log, "CWD:%s\n", cwd);
# endif
Stop linking tests/commandhelper to libvirt code The commandhelper binary is a helper for commandtest that validates what file handles were inherited. For this to work reliably we must not have any libraries that leak file descriptors into commandhelper. Unfortunately some versions of gnutls will intentionally open file handles at library load time via a constructor function. We previously hacked around this in commit 4cbc15d037e1cd8abf5c4aa6acc30d83ae13e34d Author: Martin Kletzander <mkletzan@redhat.com> Date: Fri May 2 09:55:52 2014 +0200 tests: don't fail with newer gnutls gnutls-3.3.0 and newer leaves 2 FDs open in order to be backwards compatible when it comes to chrooted binaries [1]. Linking commandhelper with gnutls then leaves these two FDs open and commandtest fails thanks to that. This patch does not link commandhelper with libvirt.la, but rather only the utilities making the test pass. Based on suggestion from Daniel [2]. [1] http://lists.gnutls.org/pipermail/gnutls-help/2014-April/003429.html [2] https://www.redhat.com/archives/libvir-list/2014-April/msg01119.html That fix relied on fact that while libvirt.so linked with gnutls, libvirt_util.la did not link to it. With the introduction of the util/vircrypto.c file that assumption is no longer valid. We must not link to libvirt_util.la at all - only gnulib and libc can (hopefully) be relied on not to open random file descriptors in constructors. Reviewed-by: Martin Kletzander <mkletzan@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-09-20 11:03:47 +00:00
free(cwd);
fprintf(log, "UMASK:%04o\n", umask(0));
if (argc > 1 && STREQ(argv[1], "--close-stdin")) {
if (freopen("/dev/null", "r", stdin) != stdin)
goto cleanup;
usleep(100*1000);
}
char buf[1024];
ssize_t got;
fprintf(stdout, "BEGIN STDOUT\n");
fflush(stdout);
fprintf(stderr, "BEGIN STDERR\n");
fflush(stderr);
for (i = 0; i < numreadfds; i++) {
fds[numpollfds].fd = readfds[i];
fds[numpollfds].events = POLLIN;
fds[numpollfds].revents = 0;
numpollfds++;
}
for (;;) {
unsigned ctr = 0;
if (poll(fds, numpollfds, -1) < 0) {
printf("poll failed: %s\n", strerror(errno));
goto cleanup;
}
for (i = 0; i < numpollfds; i++) {
if (fds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
fds[i].revents = 0;
got = read(fds[i].fd, buf, sizeof(buf));
if (got < 0)
goto cleanup;
if (got == 0) {
/* do not want to hear from this fd anymore */
fds[i].events = 0;
} else {
buffers[i] = realloc(buffers[i], buflen[i] + got);
if (!buf[i]) {
fprintf(stdout, "Out of memory!\n");
goto cleanup;
}
memcpy(buffers[i] + buflen[i], buf, got);
buflen[i] += got;
}
}
}
for (i = 0; i < numpollfds; i++) {
if (fds[i].events) {
ctr++;
break;
}
}
if (ctr == 0)
break;
}
for (i = 0; i < numpollfds; i++) {
if (write(STDOUT_FILENO, buffers[i], buflen[i]) != buflen[i])
goto cleanup;
if (write(STDERR_FILENO, buffers[i], buflen[i]) != buflen[i])
goto cleanup;
}
fprintf(stdout, "END STDOUT\n");
fflush(stdout);
fprintf(stderr, "END STDERR\n");
fflush(stderr);
ret = EXIT_SUCCESS;
cleanup:
for (i = 0; i < ARRAY_CARDINALITY(buffers); i++)
free(buffers[i]);
Stop linking tests/commandhelper to libvirt code The commandhelper binary is a helper for commandtest that validates what file handles were inherited. For this to work reliably we must not have any libraries that leak file descriptors into commandhelper. Unfortunately some versions of gnutls will intentionally open file handles at library load time via a constructor function. We previously hacked around this in commit 4cbc15d037e1cd8abf5c4aa6acc30d83ae13e34d Author: Martin Kletzander <mkletzan@redhat.com> Date: Fri May 2 09:55:52 2014 +0200 tests: don't fail with newer gnutls gnutls-3.3.0 and newer leaves 2 FDs open in order to be backwards compatible when it comes to chrooted binaries [1]. Linking commandhelper with gnutls then leaves these two FDs open and commandtest fails thanks to that. This patch does not link commandhelper with libvirt.la, but rather only the utilities making the test pass. Based on suggestion from Daniel [2]. [1] http://lists.gnutls.org/pipermail/gnutls-help/2014-April/003429.html [2] https://www.redhat.com/archives/libvir-list/2014-April/msg01119.html That fix relied on fact that while libvirt.so linked with gnutls, libvirt_util.la did not link to it. With the introduction of the util/vircrypto.c file that assumption is no longer valid. We must not link to libvirt_util.la at all - only gnulib and libc can (hopefully) be relied on not to open random file descriptors in constructors. Reviewed-by: Martin Kletzander <mkletzan@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-09-20 11:03:47 +00:00
fclose(log);
free(newenv);
return ret;
}
#else
int
main(void)
{
return EXIT_AM_SKIP;
}
#endif