git: f5efc804294c - main - tzcode: Reduce diff to upstream

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Thu, 21 Aug 2025 18:59:46 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=f5efc804294c6bb24bd6d14bf2fb883a7320956c

commit f5efc804294c6bb24bd6d14bf2fb883a7320956c
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-08-21 16:34:27 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-08-21 18:59:37 +0000

    tzcode: Reduce diff to upstream
    
    Reviewed by:    imp, jhb, emaste
    Differential Revision:  https://reviews.freebsd.org/D51997
---
 contrib/tzcode/localtime.c | 292 ++++++++++++++++++++++++++-------------------
 1 file changed, 169 insertions(+), 123 deletions(-)

diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index a6ec3d8e4e21..6eabe0afe570 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -13,37 +13,36 @@
 /*LINTLIBRARY*/
 
 #define LOCALTIME_IMPLEMENTATION
+#ifdef __FreeBSD__
 #include "namespace.h"
+#include <pthread.h>
+#endif /* __FreeBSD__ */
 #ifdef DETECT_TZ_CHANGES
-#ifndef DETECT_TZ_CHANGES_INTERVAL
-#define DETECT_TZ_CHANGES_INTERVAL 61
-#endif
+# ifndef DETECT_TZ_CHANGES_INTERVAL
+#  define DETECT_TZ_CHANGES_INTERVAL 61
+# endif
 int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
-#include <sys/stat.h>
-#endif
-#include <fcntl.h>
-#if THREAD_SAFE
-#include <pthread.h>
-#endif
+# include <sys/stat.h>
+#endif /* DETECT_TZ_CHANGES */
 #include "private.h"
-#include "un-namespace.h"
 
 #include "tzdir.h"
 #include "tzfile.h"
-
+#include <fcntl.h>
+#ifdef __FreeBSD__
 #include "libc_private.h"
+#include "un-namespace.h"
+#endif /* __FreeBSD__ */
 
 #if defined THREAD_SAFE && THREAD_SAFE
+# include <pthread.h>
+#ifdef __FreeBSD__
+# define pthread_mutex_lock(l) (__isthreaded ? _pthread_mutex_lock(l) : 0)
+# define pthread_mutex_unlock(l) (__isthreaded ? _pthread_mutex_unlock(l) : 0)
+#endif /* __FreeBSD__ */
 static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
-static int lock(void) {
-	if (__isthreaded)
-		return _pthread_mutex_lock(&locallock);
-	return 0;
-}
-static void unlock(void) {
-	if (__isthreaded)
-		_pthread_mutex_unlock(&locallock);
-}
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
 #else
 static int lock(void) { return 0; }
 static void unlock(void) { }
@@ -166,6 +165,9 @@ struct rule {
 	int_fast32_t	r_time;		/* transition time of rule */
 };
 
+#ifdef __FreeBSD__
+static void tzset_unlocked_name(char const *);
+#endif /* __FreeBSD__ */
 static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
 			 struct tm *);
 static bool increment_overflow(int *, int);
@@ -194,7 +196,7 @@ static struct state *const gmtptr = &gmtmem;
 
 static char		lcl_TZname[TZ_STRLEN_MAX + 1];
 static int		lcl_is_set;
-
+#ifdef __FreeBSD__
 static pthread_once_t	gmt_once = PTHREAD_ONCE_INIT;
 static pthread_once_t	gmtime_once = PTHREAD_ONCE_INIT;
 static pthread_key_t	gmtime_key;
@@ -205,6 +207,7 @@ static int		offtime_key_error;
 static pthread_once_t	localtime_once = PTHREAD_ONCE_INIT;
 static pthread_key_t	localtime_key;
 static int		localtime_key_error;
+#endif /* __FreeBSD__ */
 
 /*
 ** Section 4.12.3 of X3.159-1989 requires that
@@ -398,13 +401,14 @@ scrub_abbrs(struct state *sp)
 
 #ifdef DETECT_TZ_CHANGES
 /*
- * Determine if there's a change in the timezone since the last time we checked.
+ * Check whether either the time zone name or the file it refers to has
+ * changed since the last time we checked.
  * Returns: -1 on error
- * 	     0 if the timezone has not changed
- *	     1 if the timezone has changed
+ * 	     0 if the time zone has not changed
+ *	     1 if the time zone has changed
  */
 static int
-change_in_tz(const char *name)
+tzfile_changed(const char *name)
 {
 	static char old_name[PATH_MAX];
 	static struct stat old_sb;
@@ -429,9 +433,7 @@ change_in_tz(const char *name)
 
 	return 0;
 }
-#else /* !DETECT_TZ_CHANGES */
-#define	change_in_tz(X)	1
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
 
 /* Input buffer for data read from a compiled tz file.  */
 union input_buffer {
@@ -478,6 +480,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 	register int			fid;
 	register int			stored;
 	register ssize_t		nread;
+	register bool doaccess;
 	register union input_buffer *up = &lsp->u.u;
 	register int tzheadsize = sizeof(struct tzhead);
 
@@ -491,7 +494,17 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 
 	if (name[0] == ':')
 		++name;
-	if (name[0] != '/') {
+#ifdef SUPPRESS_TZDIR
+	/* Do not prepend TZDIR.  This is intended for specialized
+	   applications only, due to its security implications.  */
+	doaccess = true;
+#else
+	doaccess = name[0] == '/';
+#endif
+	if (!doaccess) {
+#ifndef __FreeBSD__
+		char const *dot;
+#endif /* !__FreeBSD__ */
 		if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
 		  return ENAMETOOLONG;
 
@@ -501,15 +514,32 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 		memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
 		strcpy(lsp->fullname + sizeof tzdirslash, name);
 
+#ifndef __FreeBSD__
+		/* Set doaccess if NAME contains a ".." file name
+		   component, as such a name could read a file outside
+		   the TZDIR virtual subtree.  */
+		for (dot = name; (dot = strchr(dot, '.')); dot++)
+		  if ((dot == name || dot[-1] == '/') && dot[1] == '.'
+		      && (dot[2] == '/' || !dot[2])) {
+		    doaccess = true;
+		    break;
+		  }
+#endif /* !__FreeBSD__ */
+
 		name = lsp->fullname;
 	}
+#ifndef __FreeBSD__
+	if (doaccess && access(name, R_OK) != 0)
+	  return errno;
+#endif /* !__FreeBSD__ */
+#ifdef DETECT_TZ_CHANGES
 	if (doextend) {
 		/*
 		 * Detect if the timezone file has changed.  Check
-		 * 'doextend' to ignore TZDEFRULES; the change_in_tz()
+		 * 'doextend' to ignore TZDEFRULES; the tzfile_changed()
 		 * function can only keep state for a single file.
 		 */
-		switch (change_in_tz(name)) {
+		switch (tzfile_changed(name)) {
 		case -1:
 			return errno;
 		case 0:
@@ -518,6 +548,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 			break;
 		}
 	}
+#endif /* DETECT_TZ_CHANGES */
 	fid = _open(name, O_RDONLY | O_BINARY);
 	if (fid < 0)
 	  return errno;
@@ -1370,8 +1401,11 @@ gmtload(struct state *const sp)
 }
 
 #ifdef DETECT_TZ_CHANGES
+/*
+ * Check if the time zone data we have is still fresh.
+ */
 static int
-recheck_tzdata()
+tzdata_is_fresh(void)
 {
 	static time_t last_checked;
 	struct timespec now;
@@ -1387,9 +1421,7 @@ recheck_tzdata()
 
 	return 0;
 }
-#else /* !DETECT_TZ_CHANGES */
-#define	recheck_tzdata()	0
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
 
 /* Initialize *SP to a value appropriate for the TZ setting NAME.
    Return 0 on success, an errno value on failure.  */
@@ -1418,16 +1450,27 @@ zoneinit(struct state *sp, char const *name)
   }
 }
 
+static void
+tzset_unlocked(void)
+{
+#ifdef __FreeBSD__
+  tzset_unlocked_name(getenv("TZ"));
+}
 static void
 tzset_unlocked_name(char const *name)
 {
+#else
+  char const *name = getenv("TZ");
+#endif
   struct state *sp = lclptr;
   int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
   if (lcl < 0
       ? lcl_is_set < 0
       : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
-    if (recheck_tzdata() == 0)
-      return;
+#ifdef DETECT_TZ_CHANGES
+    if (tzdata_is_fresh() == 0)
+#endif /* DETECT_TZ_CHANGES */
+    return;
 #ifdef ALL_STATE
   if (! sp)
     lclptr = sp = malloc(sizeof *lclptr);
@@ -1442,12 +1485,6 @@ tzset_unlocked_name(char const *name)
   lcl_is_set = lcl;
 }
 
-static void
-tzset_unlocked(void)
-{
-  tzset_unlocked_name(getenv("TZ"));
-}
-
 void
 tzset(void)
 {
@@ -1457,6 +1494,7 @@ tzset(void)
   unlock();
 }
 
+#ifdef __FreeBSD__
 void
 freebsd13_tzsetwall(void)
 {
@@ -1468,7 +1506,7 @@ freebsd13_tzsetwall(void)
 __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
 __warn_references(tzsetwall,
     "warning: tzsetwall() is deprecated, use tzset() instead.");
-
+#endif /* __FreeBSD__ */
 static void
 gmtcheck(void)
 {
@@ -1485,6 +1523,9 @@ gmtcheck(void)
   }
   unlock();
 }
+#ifdef __FreeBSD__
+#define gmtcheck() _once(&gmt_once, gmtcheck)
+#endif
 
 #if NETBSD_INSPIRED
 
@@ -1652,45 +1693,47 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
   }
 #ifndef DETECT_TZ_CHANGES
   if (setname || !lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
     tzset_unlocked();
   tmp = localsub(lclptr, timep, setname, tmp);
   unlock();
   return tmp;
 }
 
+#ifdef __FreeBSD__
 static void
 localtime_key_init(void)
 {
-
-	localtime_key_error = _pthread_key_create(&localtime_key, free);
+  localtime_key_error = _pthread_key_create(&localtime_key, free);
 }
-
+#endif /* __FreeBSD__ */
 struct tm *
 localtime(const time_t *timep)
 {
 #if !SUPPORT_C89
-	static struct tm tm;
+  static struct tm tm;
 #endif
-	struct tm *p_tm = &tm;
-
-	if (__isthreaded != 0) {
-		_pthread_once(&localtime_once, localtime_key_init);
-		if (localtime_key_error != 0) {
-			errno = localtime_key_error;
-			return (NULL);
-		}
-		if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
-			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
-				return (NULL);
-			}
-			if (_pthread_setspecific(localtime_key, p_tm) != 0) {
-				free(p_tm);
-				return (NULL);
-			}
-		}
-	}
-	return localtime_tzset(timep, p_tm, true);
+#ifdef __FreeBSD__
+  struct tm *p_tm = &tm;
+
+  if (__isthreaded != 0) {
+    _pthread_once(&localtime_once, localtime_key_init);
+    if (localtime_key_error != 0) {
+      errno = localtime_key_error;
+      return (NULL);
+    }
+    if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
+      if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+	return (NULL);
+      }
+      if (_pthread_setspecific(localtime_key, p_tm) != 0) {
+	free(p_tm);
+	return (NULL);
+      }
+    }
+  }
+#endif /* __FreeBSD__ */
+  return localtime_tzset(timep, p_tm, true);
 }
 
 struct tm *
@@ -1729,42 +1772,44 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
 struct tm *
 gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
 {
-	_once(&gmt_once, gmtcheck);
-	return gmtsub(gmtptr, timep, 0, tmp);
+  gmtcheck();
+  return gmtsub(gmtptr, timep, 0, tmp);
 }
 
+#ifdef __FreeBSD__
 static void
 gmtime_key_init(void)
 {
-
-	gmtime_key_error = _pthread_key_create(&gmtime_key, free);
+  gmtime_key_error = _pthread_key_create(&gmtime_key, free);
 }
-
+#endif /* __FreeBSD__ */
 struct tm *
 gmtime(const time_t *timep)
 {
 #if !SUPPORT_C89
-	static struct tm tm;
+  static struct tm tm;
 #endif
-	struct tm *p_tm = &tm;
-
-	if (__isthreaded != 0) {
-		_pthread_once(&gmtime_once, gmtime_key_init);
-		if (gmtime_key_error != 0) {
-			errno = gmtime_key_error;
-			return (NULL);
-		}
-		if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
-			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
-				return (NULL);
-			}
-			if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
-				free(p_tm);
-				return (NULL);
-			}
-		}
-	}
-	return gmtime_r(timep, p_tm);
+#ifdef __FreeBSD__
+  struct tm *p_tm = &tm;
+
+  if (__isthreaded != 0) {
+    _pthread_once(&gmtime_once, gmtime_key_init);
+    if (gmtime_key_error != 0) {
+      errno = gmtime_key_error;
+      return (NULL);
+    }
+    if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
+      if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+	return (NULL);
+      }
+      if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
+	free(p_tm);
+	return (NULL);
+      }
+    }
+  }
+#endif /* __FreeBSD__ */
+  return gmtime_r(timep, p_tm);
 }
 
 #if STD_INSPIRED
@@ -1775,42 +1820,44 @@ gmtime(const time_t *timep)
 struct tm *
 offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
 {
-	_once(&gmt_once, gmtcheck);
-	return gmtsub(gmtptr, timep, offset, tmp);
+  gmtcheck();
+  return gmtsub(gmtptr, timep, offset, tmp);
 }
 
+#ifdef __FreeBSD__
 static void
 offtime_key_init(void)
 {
-
-	offtime_key_error = _pthread_key_create(&offtime_key, free);
+  offtime_key_error = _pthread_key_create(&offtime_key, free);
 }
-
+#endif /* __FreeBSD__ */
 struct tm *
 offtime(const time_t *timep, long offset)
 {
 #if !SUPPORT_C89
-	static struct tm tm;
+  static struct tm tm;
 #endif
-	struct tm *p_tm = &tm;
-
-	if (__isthreaded != 0) {
-		_pthread_once(&offtime_once, offtime_key_init);
-		if (offtime_key_error != 0) {
-			errno = offtime_key_error;
-			return (NULL);
-		}
-		if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
-			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
-				return (NULL);
-			}
-			if (_pthread_setspecific(offtime_key, p_tm) != 0) {
-				free(p_tm);
-				return (NULL);
-			}
-		}
-	}
-	return offtime_r(timep, offset, p_tm);
+#ifdef __FreeBSD__
+  struct tm *p_tm = &tm;
+
+  if (__isthreaded != 0) {
+    _pthread_once(&offtime_once, offtime_key_init);
+    if (offtime_key_error != 0) {
+      errno = offtime_key_error;
+      return (NULL);
+    }
+    if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
+      if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+	return (NULL);
+      }
+      if (_pthread_setspecific(offtime_key, p_tm) != 0) {
+	free(p_tm);
+	return (NULL);
+      }
+    }
+  }
+#endif
+  return offtime_r(timep, offset, p_tm);
 }
 
 #endif
@@ -2323,7 +2370,6 @@ time1(struct tm *const tmp,
 		errno = EINVAL;
 		return WRONG;
 	}
-
 	if (tmp->tm_isdst > 1)
 		tmp->tm_isdst = 1;
 	t = time2(tmp, funcp, sp, offset, &okay);
@@ -2382,7 +2428,7 @@ mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
   if (sp)
     return time1(tmp, localsub, sp, setname);
   else {
-    _once(&gmt_once, gmtcheck);
+    gmtcheck();
     return time1(tmp, gmtsub, gmtptr, 0);
   }
 }
@@ -2438,7 +2484,7 @@ timeoff(struct tm *tmp, long offset)
 {
   if (tmp)
     tmp->tm_isdst = 0;
-  _once(&gmt_once, gmtcheck);
+  gmtcheck();
   return time1(tmp, gmtsub, gmtptr, offset);
 }
 
@@ -2508,7 +2554,7 @@ time2posix(time_t t)
   }
 #ifndef DETECT_TZ_CHANGES
   if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
     tzset_unlocked();
   if (lclptr)
     t = time2posix_z(lclptr, t);
@@ -2555,7 +2601,7 @@ posix2time(time_t t)
   }
 #ifndef DETECT_TZ_CHANGES
   if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
     tzset_unlocked();
   if (lclptr)
     t = posix2time_z(lclptr, t);