Skip to content

Commit fe019a6

Browse files
authored
[Auditor] Add pass to make all binary files executable (#992)
1 parent f22ffe9 commit fe019a6

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

src/Auditor.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ function audit(prefix::Prefix, src_name::AbstractString = "";
8585
all_ok &= check_isa(oh, platform, prefix; verbose=verbose, silent=silent)
8686
# Check that the OS ABI is set correctly (often indicates the wrong linker was used)
8787
all_ok &= check_os_abi(oh, platform, verbose = verbose)
88+
# Make sure all binary files are executables, if libraries aren't
89+
# executables Julia may not be able to dlopen them:
90+
# https://github.com/JuliaLang/julia/issues/38993. In principle this
91+
# should be done when autofix=true, but we have to run this fix on MKL
92+
# for Windows, for which however we have to set autofix=false:
93+
# https://github.com/JuliaPackaging/Yggdrasil/pull/922.
94+
all_ok &= ensure_executability(oh; verbose=verbose, silent=silent)
8895

8996
# If this is a dynamic object, do the dynamic checks
9097
if isdynamic(oh)

src/auditor/filesystems.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,27 @@ function check_absolute_paths(prefix::Prefix, all_files::Vector; silent::Bool =
4343

4444
return true
4545
end
46+
47+
function ensure_executability(oh::ObjectHandle; verbose::Bool=false, silent::Bool=false)
48+
old_mode = filemode(path(oh))
49+
# Execution permissions only for users who can read the file
50+
read_mask = (old_mode & 0o444) >> 2
51+
# Check whether the file has executable permission for all
52+
if old_mode & read_mask != read_mask
53+
if verbose
54+
@info "Making $(path(oh)) executable"
55+
end
56+
try
57+
# Add executable permission for all users that can read the file
58+
chmod(path(oh), old_mode | read_mask)
59+
catch e
60+
if isa(e, InterruptException)
61+
rethrow(e)
62+
end
63+
if !silent
64+
@warn "$(path(oh)) could not be made executable!" exception=(e, catch_backtrace())
65+
end
66+
end
67+
end
68+
return true
69+
end

test/auditing.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,52 @@ end
517517
end
518518
end
519519

520+
@testset "Auditor - execution permission" begin
521+
mktempdir() do build_path
522+
build_output_meta = nothing
523+
product = LibraryProduct("libfoo", :libfoo)
524+
@test_logs (:info, r"Making .*libfoo.* executable") match_mode=:any begin
525+
build_output_meta = autobuild(
526+
build_path,
527+
"exec",
528+
v"1.0.0",
529+
# No sources
530+
FileSource[],
531+
# Build a library without execution permissions
532+
raw"""
533+
mkdir -p "${libdir}"
534+
cc -o "${libdir}/libfoo.${dlext}" -fPIC -shared /usr/share/testsuite/c/dyn_link/libfoo/libfoo.c
535+
chmod 640 "${libdir}/libfoo.${dlext}"
536+
""",
537+
# Build for our platform
538+
[platform],
539+
# Ensure our library product is built
540+
[product],
541+
# No dependencies
542+
Dependency[];
543+
verbose = true,
544+
require_license = false
545+
)
546+
end
547+
548+
# Extract our platform's build
549+
@test haskey(build_output_meta, platform)
550+
tarball_path, tarball_hash = build_output_meta[platform][1:2]
551+
@test isfile(tarball_path)
552+
553+
# Unpack it somewhere else
554+
@test verify(tarball_path, tarball_hash)
555+
testdir = joinpath(build_path, "testdir")
556+
mkdir(testdir)
557+
unpack(tarball_path, testdir)
558+
libfoo_path = joinpath(testdir, build_output_meta[platform][4][product]["path"])
559+
# Tar.jl normalizes permissions of executable files to 0o755, instead of
560+
# recording exact original permissions:
561+
# https://github.com/JuliaIO/Tar.jl/blob/37766a22f5a6ac9f07022d83debd5db7d7a4b896/README.md#permissions
562+
@test_broken filemode(libfoo_path) & 0o777 == 0o750
563+
end
564+
end
565+
520566
@testset "Auditor - other checks" begin
521567
mktempdir() do build_path
522568
@test_logs (:error, r"does not match the hard-float ABI") match_mode=:any begin

0 commit comments

Comments
 (0)