The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=f5efc804294c6bb24bd6d14bf2fb883a7320956c
commit f5efc804294c6bb24bd6d14bf2fb883a7320956c Author: Dag-Erling Smørgrav <d...@freebsd.org> AuthorDate: 2025-08-21 16:34:27 +0000 Commit: Dag-Erling Smørgrav <d...@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);