dir: Fix spurious permission denied errors

Currently this error is happening on the eos3.9 dev branch of Endless
OS:

Nov 19 12:05:55 endless eos-updater-flatpak-installer[464]:
eos-updater-flatpak-installer: Couldn’t apply some flatpak update
actions for this boot: Error opening directory
'/root/.local/share/flatpak/app': Permission denied

The reason is that we have a check in flatpak_dir_list_unused_refs() to
check if the per-user installation exists and only try to list the refs
there if so, but the existence check falsely succeeds due to the systemd
sandboxing on eos-updater-flatpak-installer.service, and
flatpak_dir_list_refs() then fails in find_used_refs(). Specifically the
ProtectHome=yes systemd service option makes /root inaccessible, and due
to a bug in GLib[1] this makes g_file_query_exists() falsely return TRUE
for any paths under /root.

So, check for not found and permission denied errors rather than doing
an existence check, as we should be doing anyway to avoid a
time-of-check/time-of-use race, as explained in the
g_file_query_exists() documentation.

[1] https://gitlab.gnome.org/GNOME/glib/-/issues/1237
This commit is contained in:
Phaedrus Leeds
2020-11-19 22:19:50 -08:00
committed by Alexander Larsson
parent 09b470c0fd
commit 1f53e73bf3

View File

@@ -15846,14 +15846,21 @@ flatpak_dir_list_unused_refs (FlatpakDir *self,
*/
if (!flatpak_dir_is_user (self))
{
g_autoptr(GFile) user_base_dir = flatpak_get_user_base_dir_location ();
if (g_file_query_exists (user_base_dir, cancellable))
{
g_autoptr(FlatpakDir) user_dir = flatpak_dir_get_user ();
g_autoptr(FlatpakDir) user_dir = flatpak_dir_get_user ();
g_autoptr(GError) local_error = NULL;
if (!find_used_refs (self, user_dir, arch, metadata_injection, excluded_refs_ht,
used_refs, cancellable, error))
return NULL;
if (!find_used_refs (self, user_dir, arch, metadata_injection, excluded_refs_ht,
used_refs, cancellable, &local_error))
{
/* We may get permission denied if the process is sandboxed with
* systemd's ProtectHome=
*/
if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
{
g_propagate_error (error, g_steal_pointer (&local_error));
return NULL;
}
}
}