From 1b8be724bc5f3cc18da770e01174719ec4890791 Mon Sep 17 00:00:00 2001 From: June McEnroe Date: Wed, 20 Apr 2022 18:29:28 -0400 Subject: Sanitize leading dots from log path components Prevent directory traversal by sanitizing leading dots as well as slashes from log path components, which can be controlled by the server. Side effect of preventing hidden dotfiles is a bonus, I think. Also check that the full path actually fits in the buffer. Reported-by: Samanta Navarro --- log.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/log.c b/log.c index 32d771f..d2f937f 100644 --- a/log.c +++ b/log.c @@ -73,6 +73,15 @@ static void logMkdir(const char *path) { if (error && errno != EEXIST) err(EX_CANTCREAT, "log/%s", path); } +static void sanitize(char *ptr, char *end) { + for (char *ch = ptr; ch < end && *ch == '.'; ++ch) { + *ch = '_'; + } + for (char *ch = ptr; ch < end; ++ch) { + if (*ch == '/') *ch = '_'; + } +} + static struct { int year; int month; @@ -97,22 +106,21 @@ static FILE *logFile(uint id, const struct tm *tm) { logs[id].month = tm->tm_mon; logs[id].day = tm->tm_mday; - size_t len = 0; char path[PATH_MAX]; - for (const char *ch = network.name; *ch; ++ch) { - path[len++] = (*ch == '/' ? '_' : *ch); - } - path[len] = '\0'; + char *ptr = path, *end = &path[sizeof(path)]; + + ptr = seprintf(ptr, end, "%s", network.name); + sanitize(path, ptr); logMkdir(path); - path[len++] = '/'; - for (const char *ch = idNames[id]; *ch; ++ch) { - path[len++] = (*ch == '/' ? '_' : *ch); - } - path[len] = '\0'; + char *name = ptr; + ptr = seprintf(ptr, end, "/%s", idNames[id]); + sanitize(&name[1], ptr); logMkdir(path); - strftime(&path[len], sizeof(path) - len, "/%F.log", tm); + size_t len = strftime(ptr, end - ptr, "/%F.log", tm); + if (!len) errx(EX_CANTCREAT, "log path too long"); + int fd = openat( logDir, path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, -- cgit 1.4.1