CVE-2018-19045 (C, published 2018-11-08T20:29Z)
Description: value: keepalived 2.0.8 used mode 0666 when creating new temporary files upon a call to PrintData or PrintStats, potentially leaking sensitive information.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-200 \u2014 Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Repository: https://github.com/acassen/keepalived
Files changed:
doc/keepalived.conf.SYNOPSIS
doc/man/man5/keepalived.conf.5
doc/man/man8/keepalived.8
keepalived/core/global_data.c
keepalived/core/global_parser.c
keepalived/core/main.c
keepalived/include/global_data.h
keepalived/include/main.h
Commit message: Add command line and configuration option to set umask

Issue #1048 identified that files created by keepalived are created
with mode 0666. This commit changes the default to 0644, and also
allows the umask to be specified in the configuration or as a command
line option.

Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>


Vulnerable code:
	while (longindex = -1, (c = getopt_long(argc, argv, ":vhlndDRS:f:p:i:mM::g::Gt::"
	/* Set file creation mask */
	umask(0);


Fixed code:
    umask [NUMBER|BITS]                       # The umask to use for creating files. The number can be specified in hex, octal
                                              #   or decimal. BITS are I{R|W|X}{USR|GRP|OTH}, e.g. IRGRP, separated by '|'s.
                                              #   The default umask is IWGRP | IWOTH. This option cannot override the
                                              #   command-line option.

    # The umask to use for creating files. The number can be specified in hex, octal
    #   or decimal. BITS are I{R|W|X}{USR|GRP|OTH}, e.g. IRGRP, separated by '|'s.
    #   The default umask is IWGRP | IWOTH. This option cannot override the
    #   command-line option.
    \fBumask \fR[NUMBER|BITS]
[\fB\-u\fP|\fB\-\-umask\fP=NUMBER]
\fB -u, --umask\fP=NUMBER
The umask specified in the usual numeric way - see man umask(2)
.TP
	conf_write(fp, " umask = 0%o", global_data->umask);
#include <sys/types.h>
#include <sys/stat.h>
static void
umask_handler(vector_t *strvec)
{
	long umask_long;
	mode_t umask_val = 0;
	char *mask = strvec_slot(strvec, 1);
	char *endptr;
	unsigned i;
	char *p;

	if (umask_cmdline) {
		log_message(LOG_INFO, "umask command line option specified, ignoring config option");
		return;
	}

	if (isdigit(mask[0])) {
		if (vector_size(strvec) != 2) {
			report_config_error(CONFIG_GENERAL_ERROR, "%s parameter(s) to umask option", vector_size(strvec) == 1 ? "Missing" : "Extra");
			return;
		}
		umask_long = strtol(mask, &endptr, 0);
		if (*endptr || umask_long < 0 || umask_long & ~0777L) {
			report_config_error(CONFIG_GENERAL_ERROR, "invalid umask value %s", mask);
			return;
		}
		umask_val = umask_long & 0777;
	}
	else {
		bool need_or = false;
		for (i = 1; i < vector_size(strvec); i++) {
			for (p = strvec_slot(strvec, i); *p; ) {
				if (need_or) {
					if (*p == '|') {
						need_or = false;
						p++;
						continue;
					}

					report_config_error(CONFIG_GENERAL_ERROR, "Invalid umask syntax %s", FMT_STR_VSLOT(strvec, i));
					return;
				}

				if      (!strncmp(p, "IRUSR", 5)) umask_val |= S_IRUSR;
				else if (!strncmp(p, "IWUSR", 5)) umask_val |= S_IWUSR;
				else if (!strncmp(p, "IXUSR", 5)) umask_val |= S_IXUSR;
				else if (!strncmp(p, "IRGRP", 5)) umask_val |= S_IRGRP;
				else if (!strncmp(p, "IWGRP", 5)) umask_val |= S_IWGRP;
				else if (!strncmp(p, "IXGRP", 5)) umask_val |= S_IXGRP;
				else if (!strncmp(p, "IROTH", 5)) umask_val |= S_IROTH;
				else if (!strncmp(p, "IWOTH", 5)) umask_val |= S_IWOTH;
				else if (!strncmp(p, "IXOTH", 5)) umask_val |= S_IXOTH;
				else {
					report_config_error(CONFIG_GENERAL_ERROR, "Unknown umask bit %s", p);
					return;
				}

				p += 5;
				need_or = true;
			}
		}
		if (!need_or) {
			report_config_error(CONFIG_GENERAL_ERROR, "umask missing bit value");
			return;
		}
	}

	global_data->umask = umask_val;
	umask(umask_val);
}

	install_keyword("umask", &umask_handler);
#include <sys/types.h>
/* umask settings */
bool umask_cmdline;
static mode_t umask_val = S_IXUSR | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH;

static mode_t
set_umask(const char *optarg)
{
	long umask_long;
	mode_t umask_val;
	char *endptr;

	umask_long = strtoll(optarg, &endptr, 0);

	if (*endptr || umask_long < 0 || umask_long & ~0777L) {
		fprintf(stderr, "Invalid --umask option %s", optarg);
		return;
	}

	umask_val = umask_long & 0777;
	umask(umask_val);

	umask_cmdline = true;

	return umask_val;
}

	fprintf(stderr, "  -u, --umask=MASK             umask for file creation (in numeric form)\n");
	mode_t new_umask_val;
		{"umask",		required_argument,	NULL, 'u'},
	while (longindex = -1, (c = getopt_long(argc, argv, ":vhlndu:DRS:f:p:i:mM::g::Gt::"
		case 'u':
			new_umask_val = set_umask(optarg);
			if (umask_cmdline)
				umask_val = new_umask_val;
			break;
	/* Set default file creation mask */
	umask(022);

	global_data->umask = umask_val;
	mode_t				umask;			/* mask for file creation */
extern bool umask_cmdline;