Skip to content

Commit

Permalink
run: Always expose host /usr/share/zoneinfo (if possible)
Browse files Browse the repository at this point in the history
Instead of relying on the runtime tzdate we now always expose the host
/usr/share/zoneinfo in that location and make /etc/localtime a regular
symlink to it. This means applications that parse the content of the
localtime symlink will work, and additionally it means that we're
guaranteed that the host configure timezone exists (and works with)
the tzdata in the app.

This unfortunately means we no longer make the localtime an indirect
file via the session helper, and thus that localtime configurations
are static over the lifetime of an app sandbox. However, I don't
think there is a workable solution to this.

This fixes #3338
  • Loading branch information
alexlarsson committed Jun 23, 2020
1 parent 5a64611 commit dc4e198
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 51 deletions.
89 changes: 43 additions & 46 deletions common/flatpak-run.c
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,47 @@ flatpak_run_add_app_info_args (FlatpakBwrap *bwrap,
return TRUE;
}

static void
add_tzdata_args (FlatpakBwrap *bwrap,
GFile *runtime_files)
{
g_autofree char *timezone = flatpak_get_timezone ();
g_autofree char *timezone_content = g_strdup_printf ("%s\n", timezone);
g_autofree char *localtime_content = g_strconcat ("../usr/share/zoneinfo/", timezone, NULL);
g_autoptr(GFile) runtime_zoneinfo = NULL;

if (runtime_files)
runtime_zoneinfo = g_file_resolve_relative_path (runtime_files, "share/zoneinfo");

/* Check for runtime /usr/share/zoneinfo */
if (runtime_zoneinfo != NULL && g_file_query_exists (runtime_zoneinfo, NULL))
{
/* Check for host /usr/share/zoneinfo */
if (g_file_test ("/usr/share/zoneinfo", G_FILE_TEST_IS_DIR))
{
/* Here we assume the host timezone file exist in the host data */
flatpak_bwrap_add_args (bwrap,
"--ro-bind", "/usr/share/zoneinfo", "/usr/share/zoneinfo",
"--symlink", localtime_content, "/etc/localtime",
NULL);
}
else
{
g_autoptr(GFile) runtime_tzfile = g_file_resolve_relative_path (runtime_zoneinfo, timezone);

/* Check if host timezone file exist in the runtime tzdata */
if (g_file_query_exists (runtime_tzfile, NULL))
flatpak_bwrap_add_args (bwrap,
"--symlink", localtime_content, "/etc/localtime",
NULL);
}
}

flatpak_bwrap_add_args_data (bwrap, "timezone",
timezone_content, -1, "/etc/timezone",
NULL);
}

static void
add_monitor_path_args (gboolean use_session_helper,
FlatpakBwrap *bwrap)
Expand Down Expand Up @@ -2443,11 +2484,9 @@ add_monitor_path_args (gboolean use_session_helper,
if (g_variant_lookup (session_data, "path", "s", &monitor_path))
flatpak_bwrap_add_args (bwrap,
"--ro-bind", monitor_path, "/run/host/monitor",
"--symlink", "/run/host/monitor/localtime", "/etc/localtime",
"--symlink", "/run/host/monitor/resolv.conf", "/etc/resolv.conf",
"--symlink", "/run/host/monitor/host.conf", "/etc/host.conf",
"--symlink", "/run/host/monitor/hosts", "/etc/hosts",
"--symlink", "/run/host/monitor/timezone", "/etc/timezone",
NULL);

if (g_variant_lookup (session_data, "pkcs11-socket", "s", &pkcs11_socket_path))
Expand All @@ -2470,50 +2509,6 @@ add_monitor_path_args (gboolean use_session_helper,
}
else
{
/* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
* non-existing targets), in which case we don't want to attempt to create
* bogus symlinks or bind mounts, as that will cause flatpak run to fail.
*/
if (g_file_test ("/etc/localtime", G_FILE_TEST_EXISTS))
{
g_autofree char *localtime = NULL;
gboolean is_reachable = FALSE;
g_autofree char *timezone = flatpak_get_timezone ();
g_autofree char *timezone_content = g_strdup_printf ("%s\n", timezone);

localtime = glnx_readlinkat_malloc (-1, "/etc/localtime", NULL, NULL);

if (localtime != NULL)
{
g_autoptr(GFile) base_file = NULL;
g_autoptr(GFile) target_file = NULL;
g_autofree char *target_canonical = NULL;

base_file = g_file_new_for_path ("/etc");
target_file = g_file_resolve_relative_path (base_file, localtime);
target_canonical = g_file_get_path (target_file);

is_reachable = g_str_has_prefix (target_canonical, "/usr/");
}

if (is_reachable)
{
flatpak_bwrap_add_args (bwrap,
"--symlink", localtime, "/etc/localtime",
NULL);
}
else
{
flatpak_bwrap_add_args (bwrap,
"--ro-bind", "/etc/localtime", "/etc/localtime",
NULL);
}

flatpak_bwrap_add_args_data (bwrap, "timezone",
timezone_content, -1, "/etc/timezone",
NULL);
}

if (g_file_test ("/etc/resolv.conf", G_FILE_TEST_EXISTS))
flatpak_bwrap_add_args (bwrap,
"--ro-bind", "/etc/resolv.conf", "/etc/resolv.conf",
Expand Down Expand Up @@ -3020,6 +3015,8 @@ flatpak_run_setup_base_argv (FlatpakBwrap *bwrap,

flatpak_run_setup_usr_links (bwrap, runtime_files);

add_tzdata_args (bwrap, runtime_files);

pers = PER_LINUX;

if ((flags & FLATPAK_RUN_FLAG_SET_PERSONALITY) &&
Expand Down
18 changes: 13 additions & 5 deletions common/flatpak-utils-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ flatpak_get_timezone (void)
g_autofree gchar *symlink = NULL;
gchar *etc_timezone = NULL;
const gchar *tzdir;

tzdir = getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
const gchar *default_tzdir = "/usr/share/zoneinfo";

symlink = flatpak_resolve_link ("/etc/localtime", NULL);
if (symlink != NULL)
Expand All @@ -47,14 +44,25 @@ flatpak_get_timezone (void)
char *canonical_suffix;

/* Strip the prefix and slashes if possible. */
if (g_str_has_prefix (canonical, tzdir))

tzdir = getenv ("TZDIR");
if (tzdir != NULL && g_str_has_prefix (canonical, tzdir))
{
canonical_suffix = canonical + strlen (tzdir);
while (*canonical_suffix == '/')
canonical_suffix++;

return g_strdup (canonical_suffix);
}

if (g_str_has_prefix (canonical, default_tzdir))
{
canonical_suffix = canonical + strlen (default_tzdir);
while (*canonical_suffix == '/')
canonical_suffix++;

return g_strdup (canonical_suffix);
}
}

if (g_file_get_contents ("/etc/timezone", &etc_timezone,
Expand Down

0 comments on commit dc4e198

Please sign in to comment.