utils: Only remove cached files in the cache directory

The function flatpak_switch_symlink_and_remove is used to implement a
cache for ld.so (regenerate_ld_cache). If the active symlink changes to
a new cache file, the old cache file is supposed to get removed.

The symlink still points to the old cache file, so we would remove the
file that it points to and then point at the new file.

Because the symlink is under the app's control, the symlink can point
anywhere, and the removal happens in the host context, which allows an
app to remove arbitrary files on the host.

The filename of the cache files are checksums, which means that we can
ensure that the link is a file in the same directory of the link by
checking that it only contains the chars a-zA-Z0-9.

(cherry picked from commit FIXME)
This commit is contained in:
Sebastian Wick
2026-01-09 19:24:44 +01:00
committed by Sebastian Wick
parent c82a3d7716
commit c97905c818

View File

@@ -922,6 +922,22 @@ out:
return ret;
}
static gboolean
flatpak_str_is_alphanumeric (const char *arg)
{
while (*arg != '\0')
{
char c = *arg;
if (!g_ascii_isalnum (c))
return FALSE;
arg++;
}
return TRUE;
}
/* This atomically replaces a symlink with a new value, removing the
* existing symlink target, if it exstis and is different from
* @target. This is atomic in the sense that we're guaranteed to
@@ -931,6 +947,9 @@ out:
* symlink for some reason, ending up with neither the old or the new
* target. That is fine if the reason for the symlink is keeping a
* cache though.
* The target shall only be a file in the same directory as the symlink, and
* shall only contain the characters a-zA-Z0-9. This is so that the target of
* the symlink that gets removed is in the same directory as the link.
*/
gboolean
flatpak_switch_symlink_and_remove (const char *symlink_path,
@@ -974,10 +993,21 @@ flatpak_switch_symlink_and_remove (const char *symlink_path,
g_autofree char *old_target = flatpak_readlink (tmp_path, error);
if (old_target == NULL)
return FALSE;
if (strcmp (old_target, target) != 0) /* Don't remove old file if its the same as the new one */
/* Don't remove old file if its the same as the new one */
if (strcmp (old_target, target) != 0)
{
g_autofree char *old_target_path = g_build_filename (symlink_dir, old_target, NULL);
unlink (old_target_path);
if (flatpak_str_is_alphanumeric (old_target))
{
g_autofree char *old_target_path = NULL;
old_target_path = g_build_filename (symlink_dir, old_target, NULL);
unlink (old_target_path);
}
else
{
g_warning ("Refusing to delete old link target %s", old_target);
}
}
}
else if (errno != ENOENT)