mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
`xl devd` has been observed leaking /var/log/xldevd.log into children. Note this is specifically safe; dup2() leaves O_CLOEXEC disabled on newfd, so after setting up stdout/stderr, it's only the logfile fd which will close on exec(). Link: https://github.com/QubesOS/qubes-issues/issues/8292 Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Reviewed-by: Demi Marie Obenour <demi@invisiblethingslab.com> Acked-by: Anthony PERARD <anthony.perard@vates.tech> Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
330 lines
7.5 KiB
C
330 lines
7.5 KiB
C
/*
|
|
* Copyright 2009-2017 Citrix Ltd and other contributors
|
|
*
|
|
* This program 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; version 2.1 only. with the special
|
|
* exception on linking described in file LICENSE.
|
|
*
|
|
* This program 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.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <libxl.h>
|
|
#include <libxl_utils.h>
|
|
|
|
#include "xl.h"
|
|
#include "xl_utils.h"
|
|
|
|
#ifndef O_CLOEXEC
|
|
#define O_CLOEXEC 0
|
|
#endif
|
|
|
|
void dolog(const char *file, int line, const char *func, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char *s = NULL;
|
|
int rc;
|
|
|
|
va_start(ap, fmt);
|
|
rc = vasprintf(&s, fmt, ap);
|
|
va_end(ap);
|
|
if (rc >= 0)
|
|
/* we ignore write errors since we have no way to report them;
|
|
* the alternative would be to abort the whole program */
|
|
libxl_write_exactly(NULL, logfile, s, rc, NULL, NULL);
|
|
free(s);
|
|
}
|
|
|
|
void xvasprintf(char **strp, const char *fmt, va_list ap)
|
|
{
|
|
int r = vasprintf(strp, fmt, ap);
|
|
if (r == -1) {
|
|
perror("asprintf failed");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void xasprintf(char **strp, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
xvasprintf(strp, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void *xmalloc(size_t sz)
|
|
{
|
|
void *r;
|
|
r = malloc(sz);
|
|
if (!r) {
|
|
fprintf(stderr,"xl: Unable to malloc %lu bytes.\n",
|
|
(unsigned long)sz);
|
|
exit(-ERROR_FAIL);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void *xcalloc(size_t n, size_t sz)
|
|
{
|
|
void *r = calloc(n, sz);
|
|
if (!r) {
|
|
fprintf(stderr,"xl: Unable to calloc %zu bytes.\n", sz*n);
|
|
exit(-ERROR_FAIL);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void *xrealloc(void *ptr, size_t sz)
|
|
{
|
|
void *r;
|
|
if (!sz) {
|
|
free(ptr);
|
|
return 0;
|
|
}
|
|
/* realloc(non-0, 0) has a useless return value;
|
|
* but xrealloc(anything, 0) is like free
|
|
*/
|
|
r = realloc(ptr, sz);
|
|
if (!r) {
|
|
fprintf(stderr,"xl: Unable to realloc to %lu bytes.\n",
|
|
(unsigned long)sz);
|
|
exit(-ERROR_FAIL);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
char *xstrdup(const char *x)
|
|
{
|
|
char *r;
|
|
r = strdup(x);
|
|
if (!r) {
|
|
fprintf(stderr, "xl: Unable to strdup a string of length %zu.\n",
|
|
strlen(x));
|
|
exit(-ERROR_FAIL);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void flush_stream(FILE *fh)
|
|
{
|
|
const char *fh_name =
|
|
fh == stdout ? "stdout" :
|
|
fh == stderr ? "stderr" :
|
|
(abort(), (const char*)0);
|
|
|
|
if (ferror(fh) || fflush(fh)) {
|
|
perror(fh_name);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
uint32_t find_domain(const char *p)
|
|
{
|
|
uint32_t domid;
|
|
int rc;
|
|
|
|
rc = libxl_domain_qualifier_to_domid(ctx, p, &domid);
|
|
if (rc) {
|
|
fprintf(stderr, "%s is an invalid domain identifier (rc=%d)\n", p, rc);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
common_domname = libxl_domid_to_name(ctx, domid);
|
|
return domid;
|
|
}
|
|
|
|
/*
|
|
* Callers should use SWITCH_FOREACH_OPT in preference to calling this
|
|
* directly.
|
|
*/
|
|
int def_getopt(int argc, char * const argv[],
|
|
const char *optstring,
|
|
const struct option *longopts,
|
|
const char* helpstr, int reqargs)
|
|
{
|
|
int opt;
|
|
const struct option def_options[] = {
|
|
COMMON_LONG_OPTS
|
|
};
|
|
|
|
if (!longopts)
|
|
longopts = def_options;
|
|
|
|
opterr = 0;
|
|
while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) == '?') {
|
|
if (optopt == 'h') {
|
|
help(helpstr);
|
|
exit(0);
|
|
}
|
|
fprintf(stderr, "option `%c' not supported.\n", optopt);
|
|
exit(2);
|
|
}
|
|
if (opt == 'h') {
|
|
help(helpstr);
|
|
exit(0);
|
|
}
|
|
if (opt != -1)
|
|
return opt;
|
|
|
|
if (argc - optind <= reqargs - 1) {
|
|
fprintf(stderr, "'xl %s' requires at least %d argument%s.\n\n",
|
|
helpstr, reqargs, reqargs > 1 ? "s" : "");
|
|
help(helpstr);
|
|
exit(2);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void string_realloc_append(char **accumulate, const char *more)
|
|
{
|
|
/* Appends more to accumulate. Accumulate is either NULL, or
|
|
* points (always) to a malloc'd nul-terminated string. */
|
|
|
|
size_t oldlen = *accumulate ? strlen(*accumulate) : 0;
|
|
size_t morelen = strlen(more) + 1/*nul*/;
|
|
if (oldlen > SSIZE_MAX || morelen > SSIZE_MAX - oldlen) {
|
|
fprintf(stderr,"Additional config data far too large\n");
|
|
exit(-ERROR_FAIL);
|
|
}
|
|
|
|
*accumulate = xrealloc(*accumulate, oldlen + morelen);
|
|
memcpy(*accumulate + oldlen, more, morelen);
|
|
}
|
|
|
|
void print_bitmap(uint8_t *map, int maplen, FILE *stream)
|
|
{
|
|
int i;
|
|
uint8_t pmap = 0, bitmask = 0;
|
|
int firstset = 0, state = 0;
|
|
|
|
for (i = 0; i < maplen; i++) {
|
|
if (i % 8 == 0) {
|
|
pmap = *map++;
|
|
bitmask = 1;
|
|
} else bitmask <<= 1;
|
|
|
|
switch (state) {
|
|
case 0:
|
|
case 2:
|
|
if ((pmap & bitmask) != 0) {
|
|
firstset = i;
|
|
state++;
|
|
}
|
|
continue;
|
|
case 1:
|
|
case 3:
|
|
if ((pmap & bitmask) == 0) {
|
|
fprintf(stream, "%s%d", state > 1 ? "," : "", firstset);
|
|
if (i - 1 > firstset)
|
|
fprintf(stream, "-%d", i - 1);
|
|
state = 2;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
switch (state) {
|
|
case 0:
|
|
fprintf(stream, "none");
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 1:
|
|
if (firstset == 0) {
|
|
fprintf(stream, "all");
|
|
break;
|
|
}
|
|
case 3:
|
|
fprintf(stream, "%s%d", state > 1 ? "," : "", firstset);
|
|
if (i - 1 > firstset)
|
|
fprintf(stream, "-%d", i - 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int do_daemonize(const char *name, const char *pidfile)
|
|
{
|
|
char *fullname;
|
|
pid_t child1;
|
|
int nullfd, ret = 0;
|
|
|
|
child1 = xl_fork(child_waitdaemon, "domain monitoring daemonizing child");
|
|
if (child1) {
|
|
ret = child_report(child_waitdaemon);
|
|
if (ret) goto out;
|
|
ret = 1;
|
|
goto out;
|
|
}
|
|
|
|
postfork();
|
|
|
|
ret = libxl_create_logfile(ctx, name, &fullname);
|
|
if (ret) {
|
|
LOG("failed to open logfile %s: %s",fullname,strerror(errno));
|
|
exit(-1);
|
|
}
|
|
|
|
CHK_SYSCALL(logfile = open(fullname, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0644));
|
|
free(fullname);
|
|
assert(logfile >= 3);
|
|
|
|
CHK_SYSCALL(nullfd = open("/dev/null", O_RDONLY));
|
|
assert(nullfd >= 3);
|
|
|
|
dup2(nullfd, 0);
|
|
dup2(logfile, 1);
|
|
dup2(logfile, 2);
|
|
|
|
close(nullfd);
|
|
|
|
CHK_SYSCALL(daemon(0, 1));
|
|
|
|
if (pidfile) {
|
|
int fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
|
|
char *pid = NULL;
|
|
|
|
if (fd == -1) {
|
|
perror("Unable to open pidfile");
|
|
exit(1);
|
|
}
|
|
|
|
if (asprintf(&pid, "%ld\n", (long)getpid()) == -1) {
|
|
perror("Formatting pid");
|
|
exit(1);
|
|
}
|
|
|
|
if (write(fd, pid, strlen(pid)) < 0) {
|
|
perror("Writing pid");
|
|
exit(1);
|
|
}
|
|
|
|
if (close(fd) < 0) {
|
|
perror("Closing pidfile");
|
|
exit(1);
|
|
}
|
|
|
|
free(pid);
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|