From 82c6e4680f407c8ada9346db1ed1077775ea897f Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sun, 5 Feb 2023 18:08:14 +0100 Subject: [PATCH] Fix issue with pid://../run/foo..pid parser Unfortunately we cannot use realpath(3) here since the the PID files usually do not yet exist at this point. Add and modify my ugly de_dotdot() from Merecat httpd. Signed-off-by: Joachim Wiberg --- TODO.org | 2 +- src/pid.c | 6 +++++- src/pid.h | 8 ++++---- src/util.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/util.h | 1 + 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/TODO.org b/TODO.org index 1c661aad..ec4b5f8f 100644 --- a/TODO.org +++ b/TODO.org @@ -1,4 +1,4 @@ -* TODO fix pid parser, //run/foo.pid -> /var/run///run/foo.pid +* DONE fix pid parser, //run/foo.pid -> /var/run///run/foo.pid ** DONE test framework refactor 'texec sh -c ...' -> 'run ...' * TODO Clean up tests a bit * TODO Drop tenv or common and rename tenv-root diff --git a/src/pid.c b/src/pid.c index 48d77988..13ce57d3 100644 --- a/src/pid.c +++ b/src/pid.c @@ -149,6 +149,8 @@ int pid_file_create(svc_t *svc) int pid_file_set(svc_t *svc, char *file, int not) { + char buf[sizeof(svc->pidfile)]; + if (!file) { file = pid_file(svc); if (!file) @@ -165,7 +167,9 @@ int pid_file_set(svc_t *svc, char *file, int not) not = 1; } - pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not); + de_dotdot(file); + pid_runpath(file, buf, sizeof(buf)); + strlcpy(&svc->pidfile[not], buf, sizeof(svc->pidfile) - not); if (not) svc->pidfile[0] = '!'; diff --git a/src/pid.h b/src/pid.h index 3a1bb32f..533d0258 100644 --- a/src/pid.h +++ b/src/pid.h @@ -51,6 +51,7 @@ static inline char *pid_runpath(const char *file, char *path, size_t len) { static char *prefix = "/var/run"; static int unknown = 1; + char *ptr; int rc; if (unknown) { @@ -59,10 +60,9 @@ static inline char *pid_runpath(const char *file, char *path, size_t len) unknown = 0; } - if (!strncmp(file, "/var/run/", 9)) - file += 9; - else if (!strncmp(file, "/run/", 5)) - file += 5; + ptr = strstr(file, "/run/"); + if (ptr) + file = ptr + 5; rc = paste(path, len, prefix, file); if (rc < 0 || (size_t)rc >= len) diff --git a/src/util.c b/src/util.c index e90d1999..a557412b 100644 --- a/src/util.c +++ b/src/util.c @@ -467,6 +467,47 @@ char *sanitize(char *arg, size_t len) return arg; } +void de_dotdot(char *file) +{ + char *cp, *cp2; + int l; + + /* Remove leading ./ and any /./ sequences. */ + while (strncmp(file, "./", 2) == 0) + memmove(file, file + 2, strlen(file) - 1); + while ((cp = strstr(file, "/./"))) + memmove(cp, cp + 2, strlen(cp) - 1); + + /* Alternate between removing leading ../ and removing xxx/../ */ + for (;;) { + while (strncmp(file, "../", 3) == 0) + memmove(file, file + 3, strlen(file) - 2); + cp = strstr(file, "/../"); + if (!cp) + break; + + for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) + continue; + + memmove(cp2 + 1, cp + 4, strlen(cp + 3)); + } + + /* Also elide any xxx/.. at the end. */ + while ((l = strlen(file)) > 3 && strcmp((cp = file + l - 3), "/..") == 0) { + for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) + continue; + if (cp2 < file) + break; + *cp2 = '\0'; + } + + /* Collapse any multiple / sequences. */ + while ((cp = strstr(file, "//"))) { + cp2 = cp + 1; + memmove(cp, cp2, strlen(cp2) + 1); + } +} + static int hasopt(char *opts, char *opt) { char buf[strlen(opts) + 1]; diff --git a/src/util.h b/src/util.h index 7eb894be..18a01c4e 100644 --- a/src/util.h +++ b/src/util.h @@ -72,6 +72,7 @@ char *uptime (long secs, char *buf, size_t len); char *memsz (uint64_t sz, char *buf, size_t len); char *sanitize (char *arg, size_t len); +void de_dotdot (char *file); int ismnt (char *file, char *dir, char *mode); int fismnt (char *dir);