commit 96233476c269f24ce76cecadc2f5144632157d7b from: Omar Polo date: Thu Jun 09 17:17:35 2022 UTC use canonpath (from kern_pledge.c) instead of home grow "equivalent" commit - ebdc0a24f14a77c01c20f3c8f7d106dc2f0ee410 commit + 96233476c269f24ce76cecadc2f5144632157d7b blob - a12e1cf15b7ee48352b18f7cc21fe0b4e9deda6b blob + 78e1afcd78a8d22217e61b225af34e82aa2556fa --- ctl.c +++ ctl.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 Omar Polo + * Copyright (c) 2015 Theo de Raadt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,7 +38,8 @@ #include "playlist.h" #include "xmalloc.h" -static struct imsgbuf *ibuf; +static struct imsgbuf *ibuf; +char cwd[PATH_MAX]; int ctl_noarg(struct parse_result *, int, char **); int ctl_add(struct parse_result *, int, char **); @@ -81,7 +83,53 @@ ctl_usage(struct ctl_command *ctl) exit(1); } +/* based on canonpath from kern_pledge.c */ static int +canonpath(const char *input, char *buf, size_t bufsize) +{ + const char *p; + char *q, path[PATH_MAX]; + + if (input[0] != '/') { + if (snprintf(path, sizeof(path), "%s/%s", cwd, input) + >= sizeof(path)) { + errno = ENAMETOOLONG; + return -1; + } + input = path; + } + + p = input; + q = buf; + while (*p && (q - buf < bufsize)) { + if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) { + p += 1; + + } else if (p[0] == '/' && p[1] == '.' && + (p[2] == '/' || p[2] == '\0')) { + p += 2; + + } else if (p[0] == '/' && p[1] == '.' && p[2] == '.' && + (p[3] == '/' || p[3] == '\0')) { + p += 3; + if (q != buf) /* "/../" at start of buf */ + while (*--q != '/') + continue; + + } else { + *q++ = *p++; + } + } + if ((*p == '\0') && (q - buf < bufsize)) { + *q = 0; + return 0; + } else { + errno = ENAMETOOLONG; + return -1; + } +} + +static int parse(int argc, char **argv) { struct ctl_command *ctl = NULL; @@ -132,8 +180,8 @@ load_files(struct parse_result *res, int *ret) FILE *f; const char *file; char *line = NULL; - char path[PATH_MAX], cwd[PATH_MAX]; - size_t linesize = 0, i = 0, n; + char path[PATH_MAX]; + size_t linesize = 0, i = 0; ssize_t linelen, curr = -1; if (res->file == NULL) @@ -143,9 +191,6 @@ load_files(struct parse_result *res, int *ret) *ret = 1; return 1; } - - if (getcwd(cwd, sizeof(cwd)) == NULL) - fatal("getcwd"); while ((linelen = getline(&line, &linesize, f)) != -1) { if (linelen == 0) @@ -158,17 +203,8 @@ load_files(struct parse_result *res, int *ret) } else if (!strncmp(file, " ", 2)) file += 2; - if (!strncmp(file, "./", 2)) - file += 2; - - memset(path, 0, sizeof(path)); - if (*file == '/') - n = strlcpy(path, file, sizeof(path)); - else - n = snprintf(path, sizeof(path), "%s/%s", cwd, file); - - if (n >= sizeof(path)) { - log_warnx("path too long: %s", file); + if (canonpath(file, path, sizeof(path)) == -1) { + log_warnx("canonpath %s", file); continue; } @@ -777,6 +813,9 @@ ctl(int argc, char **argv) log_init(1, LOG_DAEMON); log_setverbose(verbose); + if (getcwd(cwd, sizeof(cwd)) == NULL) + fatal("getcwd"); + if ((ctl_sock = ctl_connect()) == -1) fatal("can't connect");