[glib/glib-2-74: 1/2] gtimezone: Reject weird /etc/localtime configurations




commit 1143a8a666037f4baac878418311035c426d26c8
Author: Ray Strode <rstrode redhat com>
Date:   Fri Oct 14 13:18:50 2022 -0400

    gtimezone: Reject weird /etc/localtime configurations
    
    At the moment, glib assumes that if /etc/localtime is a symlink,
    that it's a symlink to zoneinfo file.
    
    Toolbx containers add an extra layer of indirection though, making
    it a symlink to a symlink to a zoneinfo file.
    
    This commit deals with the problem, by performing additional checks
    on /etc/localtime and ignoring it if those check fail, falling back
    instead to reading /etc/timezone.

 glib/gtimezone.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 13 deletions(-)
---
diff --git a/glib/gtimezone.c b/glib/gtimezone.c
index ef0b628904..1e07cf6f0b 100644
--- a/glib/gtimezone.c
+++ b/glib/gtimezone.c
@@ -41,6 +41,10 @@
 #include "gdate.h"
 #include "genviron.h"
 
+#ifdef G_OS_UNIX
+#include "gstdio.h"
+#endif
+
 #ifdef G_OS_WIN32
 
 #define STRICT
@@ -532,16 +536,43 @@ zone_identifier_unix (void)
   gchar *canonical_path = NULL;
   GError *read_link_err = NULL;
   const gchar *tzdir;
+  gboolean not_a_symlink_to_zoneinfo = FALSE;
+  struct stat file_status;
 
   /* Resolve the actual timezone pointed to by /etc/localtime. */
   resolved_identifier = g_file_read_link ("/etc/localtime", &read_link_err);
-  if (resolved_identifier == NULL)
+
+  if (resolved_identifier != NULL)
+    {
+      if (g_lstat (resolved_identifier, &file_status) == 0)
+        {
+          if ((file_status.st_mode & S_IFMT) != S_IFREG)
+            {
+              /* Some systems (e.g. toolbox containers) make /etc/localtime be a symlink
+               * to a symlink.
+               *
+               * Rather than try to cope with that, just ignore /etc/localtime and use
+               * the fallback code to read timezone from /etc/timezone
+               */
+              g_clear_pointer (&resolved_identifier, g_free);
+              not_a_symlink_to_zoneinfo = TRUE;
+            }
+        }
+      else
+        {
+          g_clear_pointer (&resolved_identifier, g_free);
+        }
+    }
+  else
     {
-      gboolean not_a_symlink = g_error_matches (read_link_err,
-                                                G_FILE_ERROR,
-                                                G_FILE_ERROR_INVAL);
+      not_a_symlink_to_zoneinfo = g_error_matches (read_link_err,
+                                                   G_FILE_ERROR,
+                                                   G_FILE_ERROR_INVAL);
       g_clear_error (&read_link_err);
+    }
 
+  if (resolved_identifier == NULL)
+    {
       /* if /etc/localtime is not a symlink, try:
        *  - /var/db/zoneinfo : 'tzsetup' program on FreeBSD and
        *    DragonflyBSD stores the timezone chosen by the user there.
@@ -551,17 +582,17 @@ zone_identifier_unix (void)
        *    as a last-ditch effort to parse the TZ= setting from within
        *    /etc/default/init
        */
-      if (not_a_symlink && (g_file_get_contents ("/var/db/zoneinfo",
-                                                 &resolved_identifier,
-                                                 NULL, NULL) ||
-                            g_file_get_contents ("/etc/timezone",
-                                                 &resolved_identifier,
-                                                 NULL, NULL)
+      if (not_a_symlink_to_zoneinfo && (g_file_get_contents ("/var/db/zoneinfo",
+                                                             &resolved_identifier,
+                                                             NULL, NULL) ||
+                                        g_file_get_contents ("/etc/timezone",
+                                                             &resolved_identifier,
+                                                             NULL, NULL)
 #if defined(__sun) && defined(__SVR4)
-                                                             ||
-                            (resolved_identifier = zone_identifier_illumos ())
+                                        ||
+                                        (resolved_identifier = zone_identifier_illumos ())
 #endif
-                                                             ))
+                                            ))
         g_strchomp (resolved_identifier);
       else
         {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]