Skip to content

Commit ad586f5

Browse files
authored
[Auditor] Fix path normalisation for rpaths (#1186)
* [Auditor] Fix relative path normalisation for new runpaths * [Audit] Remove type piracy * [Audit] Strip out absolute rpaths * [Audit] Add test for rpaths
1 parent f20e6d0 commit ad586f5

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

src/auditor/dynamic_linkage.jl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using ObjectFile.ELF
2-
import ObjectFile: rpaths, canonical_rpaths
32

43
"""
54
platform_for_object(oh::ObjectHandle)
@@ -68,13 +67,13 @@ function platform_for_object(oh::ObjectHandle)
6867
end
6968
end
7069

71-
function rpaths(file::AbstractString)
70+
function _rpaths(file::AbstractString)
7271
readmeta(file) do oh
7372
rpaths(RPath(oh))
7473
end
7574
end
7675

77-
function canonical_rpaths(file::AbstractString)
76+
function _canonical_rpaths(file::AbstractString)
7877
readmeta(file) do oh
7978
canonical_rpaths(RPath(oh))
8079
end
@@ -406,12 +405,14 @@ function update_linkage(prefix::Prefix, platform::AbstractPlatform, path::Abstra
406405
if rp == "."
407406
return "\$ORIGIN"
408407
end
409-
if startswith(rp, ".")
408+
if startswith(rp, ".") || !startswith(rp, "/")
409+
# Relative paths starting with `.`, or anything which isn't an absolute
410+
# path. It may also be a relative path without the leading `./`
410411
return "\$ORIGIN/$(rp)"
411412
end
412413
return rp
413414
end
414-
current_rpaths = [r for r in rpaths(path) if !isempty(r)]
415+
current_rpaths = [r for r in _rpaths(path) if !isempty(r)]
415416
add_rpath = rp -> begin
416417
# Join together RPaths to set new one
417418
rpaths = unique(vcat(current_rpaths, rp))
@@ -425,6 +426,9 @@ function update_linkage(prefix::Prefix, platform::AbstractPlatform, path::Abstra
425426
return path
426427
end
427428
rpaths = chomp_slashdot.(rpaths)
429+
# Remove paths starting with `/workspace`: they will not work outisde of the
430+
# build environment and only create noise when debugging.
431+
filter!(rp -> !startswith(rp, "/workspace"), rpaths)
428432

429433
rpath_str = join(rpaths, ':')
430434
return `$patchelf $(patchelf_flags(platform)) --set-rpath $(rpath_str) $(rel_path)`
@@ -435,7 +439,7 @@ function update_linkage(prefix::Prefix, platform::AbstractPlatform, path::Abstra
435439
# If the relative directory doesn't already exist within the RPATH of this
436440
# binary, then add it in.
437441
new_libdir = abspath(dirname(new_libpath) * "/")
438-
if !(new_libdir in canonical_rpaths(path))
442+
if !(new_libdir in _canonical_rpaths(path))
439443
libname = basename(old_libpath)
440444
cmd = add_rpath(normalize_rpath(relpath(new_libdir, dirname(path))))
441445
with_logfile(prefix, "update_rpath_$(basename(path))_$(libname).log"; subdir) do io

test/auditing.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,55 @@ end
571571
end
572572
end
573573

574+
@testset "Auditor - rpaths" begin
575+
@testset "$platform" for platform in (Platform("x86_64", "linux"; libc="glibc"), Platform("x86_64", "macos"))
576+
mktempdir() do build_path
577+
build_output_meta = nothing
578+
@test_logs (:info, "Building for $(triplet(platform))") match_mode=:any begin
579+
build_output_meta = autobuild(
580+
build_path,
581+
"rpaths",
582+
v"1.0.0",
583+
# No sources
584+
FileSource[],
585+
# Build two libraries, `libbar` in `${libdir}/qux/` and `libfoo` in
586+
# `${libdir}`, with the latter linking to the former.
587+
raw"""
588+
mkdir -p ${libdir}/qux
589+
echo "int bar(){return 38;}" | gcc -x c -shared -fPIC - -o ${libdir}/qux/libbar.${dlext}
590+
echo "extern int bar(); int foo(){return bar() + 4;}" | gcc -x c -shared -fPIC - -o ${libdir}/libfoo.${dlext} -L${libdir}/qux -lbar -Wl,-rpath,${libdir}/qux
591+
""",
592+
[platform],
593+
# Ensure our library products are built
594+
[LibraryProduct("libbar", :libbar, "\$libdir/qux"), LibraryProduct("libfoo", :libfoo)],
595+
# No dependencies
596+
Dependency[];
597+
require_license = false
598+
)
599+
end
600+
# Extract our platform's build
601+
@test haskey(build_output_meta, platform)
602+
tarball_path, tarball_hash = build_output_meta[platform][1:2]
603+
# Ensure the build products were created
604+
@test isfile(tarball_path)
605+
606+
# Unpack it somewhere else
607+
@test verify(tarball_path, tarball_hash)
608+
testdir = joinpath(build_path, "testdir")
609+
mkdir(testdir)
610+
unpack(tarball_path, testdir)
611+
# Make sure rpath of libbar is empty
612+
@test Auditor._rpaths(joinpath(testdir, "lib", "qux", "libbar.$(platform_dlext(platform))")) == []
613+
# Make sure the rpath of libfoo contains only `$ORIGIN/qux`, with the relative
614+
# path handled correctly.
615+
libfoo_rpaths = Auditor._rpaths(joinpath(testdir, "lib", "libfoo.$(platform_dlext(platform))"))
616+
@test (Sys.isapple(platform) ? "@loader_path" : "\$ORIGIN") * "/qux" in libfoo_rpaths
617+
# Currently we don't filter out absolute rpaths for macOS libraries, no good.
618+
@test length(libfoo_rpaths) == 1 broken=Sys.isapple(platform)
619+
end
620+
end
621+
end
622+
574623
@testset "Auditor - execution permission" begin
575624
mktempdir() do build_path
576625
build_output_meta = nothing

0 commit comments

Comments
 (0)