about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-04-20 18:29:28 -0400
committerJune McEnroe <june@causal.agency>2022-04-20 18:29:28 -0400
commit1b8be724bc5f3cc18da770e01174719ec4890791 (patch)
tree79cbb0ba57f3bf265c587089aca902f786e73639
parentAdd screenshot to README (diff)
downloadcatgirl-1b8be724bc5f3cc18da770e01174719ec4890791.tar.gz
catgirl-1b8be724bc5f3cc18da770e01174719ec4890791.zip
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 <ferivoz@riseup.net>
-rw-r--r--log.c30
1 files 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,