summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2022-10-03 15:34:40 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2022-10-03 15:34:40 +0000
commit9ada79011110198e0b48f901fda0f53caae40a5b (patch)
tree3352d187f67a04988cfcb5c011a7ea9d4f7c1666
parentad4e74d1c6d32010ef15b3547a3925eb64d9edc5 (diff)
Allow TZ to contain absolutes paths starting with /usr/share/zoneinfo/
Other absolutes paths are still rejected.
-rw-r--r--lib/libc/time/localtime.c77
1 files 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;
}