From d3d10ea62c7b6ad1454565cc21776592e08351a1 Mon Sep 17 00:00:00 2001 From: millert Date: Mon, 3 Oct 2022 15:34:39 +0000 Subject: [PATCH] Allow TZ to contain absolutes paths starting with /usr/share/zoneinfo/ Other absolutes paths are still rejected. --- lib/libc/time/localtime.c | 77 +++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/lib/libc/time/localtime.c b/lib/libc/time/localtime.c index 6f1c207047b..2e1641183a8 100644 --- a/lib/libc/time/localtime.c +++ b/lib/libc/time/localtime.c @@ -1,4 +1,4 @@ -/* $OpenBSD: localtime.c,v 1.64 2022/09/23 17:29:22 millert Exp $ */ +/* $OpenBSD: localtime.c,v 1.65 2022/10/03 15:34:39 millert Exp $ */ /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson. @@ -296,27 +296,25 @@ differ_by_repeat(time_t t1, time_t t0) } static int -tzload(const char *name, struct state *sp, int doextend) +tzpath_ok(const char *name) { - const char * p; - int i; - int fid; - int stored; - int nread; - typedef union { - struct tzhead tzhead; - char buf[2 * sizeof(struct tzhead) + - 2 * sizeof *sp + - 4 * TZ_MAX_TIMES]; - } u_t; - u_t * up; - char fullname[PATH_MAX]; + /* Reject absolute paths that don't start with TZDIR. */ + if (name[0] == '/' && (strncmp(name, TZDIR, sizeof(TZDIR) - 1) != 0 || + name[sizeof(TZDIR) - 1] != '/')) + return 0; - up = calloc(1, sizeof *up); - if (up == NULL) - return -1; + /* Reject paths that contain "../". */ + if (strstr(name, "../") != NULL) + return 0; - sp->goback = sp->goahead = FALSE; + return 1; +} + +static int +open_tzfile(const char *name) +{ + char fullname[PATH_MAX]; + int i; if (name != NULL) { /* @@ -325,22 +323,53 @@ tzload(const char *name, struct state *sp, int doextend) */ if (name[0] == ':') name++; - /* Ignore absolute paths or names that contain "../". */ - if (name[0] == '/' || strstr(name, "../") != NULL) + + /* + * Ignore absolute paths that don't start with TZDIR + * or that contain "../". + */ + if (!tzpath_ok(name)) name = NULL; } + if (name == NULL) { name = TZDEFAULT; - } else { + } else if (name[0] != '/') { /* Time zone data path is relative to TZDIR. */ i = snprintf(fullname, sizeof(fullname), "%s/%s", TZDIR, name); if (i < 0 || i >= sizeof(fullname)) { errno = ENAMETOOLONG; - goto oops; + return -1; } name = fullname; } - if ((fid = open(name, O_RDONLY)) == -1) { + + return open(name, O_RDONLY); +} + +static int +tzload(const char *name, struct state *sp, int doextend) +{ + const char * p; + int i; + int fid; + int stored; + int nread; + typedef union { + struct tzhead tzhead; + char buf[2 * sizeof(struct tzhead) + + 2 * sizeof *sp + + 4 * TZ_MAX_TIMES]; + } u_t; + u_t * up; + + up = calloc(1, sizeof *up); + if (up == NULL) + return -1; + + sp->goback = sp->goahead = FALSE; + + if ((fid = open_tzfile(name)) == -1) { /* Could be a POSIX section 8-style TZ string. */ goto oops; } -- 2.20.1