Skip to content
Snippets Groups Projects
Commit a7e7fa13 authored by Simon McVittie's avatar Simon McVittie
Browse files

capture-libs: Never undo our rewriting of the symlink target

Previously, if we were using --remap-link-prefix but not --link-target
(as in pressure-vessel), and if the path at which we found the
library in the provider (`needed_path_in_provider`) was such that
after resolving symlinks, the canonicalized result (`path`) did not
match any of the --remap-link-prefix options, then we would reset
to using the `needed_path_in_provider` as the symlink target.

However, this was wrong, because it did not take into account the
possibility that the original path might have matched one of the
--remap-link-prefix options even though its canonicalized version didn't.

For example, consider the NixOS "FHS environment", a bwrap-based
container that has been populated with symlinks of the form
/lib/libGL.so.1 -> /nix/store/something. Depending on the precise
behaviour of libc and libdl (the exact trigger for the differing
behaviour is unknown), when we open that library, we might find
that the `needed_path_in_provider` is either /lib/libGL.so.1
or a path below /nix/store.

If the `needed_path_in_provider` is /lib/libGL.so.1, we would
canonicalize it to /nix/store/something, then decide that
/nix/store/something didn't match any of the remapping rules such
as `/lib*` → `/run/host/lib*`, and go back to using /lib/libGL.so.1
as the symlink target. But, inside pressure-vessel's container, `/lib`
is from the container runtime and not the provider - which is precisely
why we need to rewrite /lib paths to /run/host/lib in order to be
able to find the library we want.

Instead, we must limit the situation where we keep the
`needed_path_in_provider` as-is to the situation where there is no
symlink target rewriting: no --link-target, and no --remap-link-prefix.
In this situation, we are expecting the meaning of a symlink in the
container environment to be identical to the meaning of a symlink in
the environment from which we are running capsule-capture-libs,
therefore it's slightly preferable to use a non-canonicalized symlink
if we have one: that way, if the target of a symlink changes during
the container's lifetime (perhaps as a result of an OS upgrade),
it will still work.

Conversely, if we are using either --link-target or --remap-link-prefix,
we want to stick to using only the canonicalized paths of libraries,
because that's the only way we can avoid a symlink being interpreted
differently outside and inside the container, for example as a result
of its parent directory being mounted in a different place, or as a
result of something different being mounted at its target.

This means that we have to relax one of our test assertions slightly.

Helps: https://github.com/ValveSoftware/steam-runtime/issues/684


Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent b58a3d40
No related branches found
No related tags found
No related merge requests found
......@@ -218,8 +218,10 @@ run_ok([$CAPSULE_CAPTURE_LIBS_TOOL, '--remap-link-prefix=/opt/=/OPT/',
$target = readlink "$libdir/libc.so.6";
diag("Expecting: $libdir/libc.so.6 -> $LIBDIR/libc.so.6");
diag("Actual: $libdir/libc.so.6 -> $target");
like($target, qr{^$LIBDIR/libc\.so\.6$},
"$libdir/libc.so.6 is a symlink to the real libc.so.6");
like($target, $libc_re,
"$libdir/libc.so.6 is a symlink to the real libc.so.6 in some form");
is(abs_path("$libdir/libc.so.6"), $libc_realpath,
"$libdir/libc.so.6 canonicalizes to $libc_realpath");
run_ok(['rm', '-fr', $libdir]);
mkdir($libdir);
......
......@@ -538,7 +538,6 @@ capture_one( const char *soname, const capture_options *options,
const char *needed_name = provider->needed[i].name;
const char *needed_path_in_provider = provider->needed[i].path;
const char *needed_basename;
bool remapped_prefix = false;
if( !needed_name )
{
......@@ -763,18 +762,14 @@ capture_one( const char *soname, const capture_options *options,
target + strlen( remap_prefix[j].from ) );
free( target );
target = tmp;
remapped_prefix = true;
}
}
}
// If we don't have the link target option and we didn't remap the
// prefix, we just set the target to the needed path in provider
// without following the eventual link chain
if( !remapped_prefix && option_link_target == NULL )
else
{
if( target != NULL )
free( target );
/* No need to remap anything or canonicalize the path,
* because we're going to use it from the same view of the
* filesystem that we're currently in. */
target = xstrdup( needed_path_in_provider );
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment