From fd46fea69707d535da268fa02277b64117819fa7 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 26 Sep 2025 16:22:47 -0700
Subject: [PROPOSED 2/3] Use O_RESOLVE_BENEATH (if available) for TZif

* localtime.c (O_RESOLVE_BENEATH): Default to 0.
(tzloadbody): If O_RESOLVE_BENEATH is available, use it
instead of manually checking for "..".
This mimics what bleeding-edge FreeBSD does.
---
 localtime.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/localtime.c b/localtime.c
index 27b0455f..c103909a 100644
--- a/localtime.c
+++ b/localtime.c
@@ -138,6 +138,9 @@ static int openat(int dd, char const *path, int oflag) { unreachable (); }
 #ifndef O_PATH
 # define O_PATH 0
 #endif
+#ifndef O_RESOLVE_BENEATH
+# define O_RESOLVE_BENEATH 0
+#endif
 #ifndef O_SEARCH
 # define O_SEARCH 0
 #endif
@@ -652,14 +655,17 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
 	}
 
 	if (relname[0] != '/') {
-	  /* Fail if a relative name contains a ".." component,
-	     as such a name could read a file outside TZDIR.  */
-	  char const *component;
-	  for (component = relname; component[0]; component++)
-	    if (component[0] == '.' && component[1] == '.'
-		&& ((component[2] == '/') | !component[2])
-		&& (component == relname || component[-1] == '/'))
-	      return ENOTCAPABLE;
+	  if (!OPENAT_TZDIR || !O_RESOLVE_BENEATH) {
+	    /* Fail if a relative name contains a ".." component,
+	       as such a name could read a file outside TZDIR
+	       when AT_FDCWD and O_RESOLVE_BENEATH are not available.  */
+	    char const *component;
+	    for (component = relname; component[0]; component++)
+	      if (component[0] == '.' && component[1] == '.'
+		  && ((component[2] == '/') | !component[2])
+		  && (component == relname || component[-1] == '/'))
+		return ENOTCAPABLE;
+	  }
 
 	  if (OPENAT_TZDIR) {
 	    /* Prefer O_SEARCH or O_PATH if available;
@@ -671,6 +677,7 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
 		       | O_BINARY | O_CLOEXEC | O_CLOFORK | O_DIRECTORY));
 	    if (dd < 0)
 	      return errno;
+	    oflags |= O_RESOLVE_BENEATH;
 	  }
 	}
 
-- 
2.48.1

