Skip to content

Commit

Permalink
Check for a branded ELF note when OS/ABI is NONE
Browse files Browse the repository at this point in the history
Currently the auditor is only checking for the correct OS/ABI and
producing a warning on FreeBSD when it doesn't match. This warning is
incorrect on AArch64 though, as FreeBSD instead uses an ELF note to
declare the OS/ABI. The change implemented here looks for such a note
when the OS/ABI in the ELF header is NONE.
  • Loading branch information
ararslan committed Sep 12, 2024
1 parent 49f57bf commit 01b8996
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 3 deletions.
36 changes: 35 additions & 1 deletion src/auditor/dynamic_linkage.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
using ObjectFile.ELF

function os_from_elf_note(oh::ELFHandle)
for section in Sections(oh)
section_handle(section) == ELF.SHT_NOTE || continue
seek(oh, section_offset(section))
name_length = read(oh, UInt32)
iszero(name_length) && continue
descriptor_length = read(oh, UInt32)
note_type = read(oh, UInt32)
name = String(read(oh, name_length - 1)) # skip trailing NUL
if note_type == 1
# Technically it's part of the Linux specification that any executable should
# have an ELF note with type 1, name GNU, and descriptor length ≥4, but in
# practice I haven't observed that consistently, especially on musl. So for
# now, only bother checking FreeBSD, which uses an ELF note rather than OS/ABI
# to identify itself on AArch64 and RISC-V.
if name == "FreeBSD" && descriptor_length == 4
return name
end
end
end
return nothing
end

os_from_elf_note(::ObjectHandle) = nothing

"""
platform_for_object(oh::ObjectHandle)
Expand Down Expand Up @@ -39,7 +64,9 @@ function platform_for_object(oh::ObjectHandle)
end
end

if oh.ei.osabi == ELF.ELFOSABI_LINUX || oh.ei.osabi == ELF.ELFOSABI_NONE
if oh.ei.osabi == ELF.ELFOSABI_NONE
return Platform(arch, os_from_elf_note(oh) == "FreeBSD" ? "freebsd" : "linux")
elseif oh.ei.osabi == ELF.ELFOSABI_LINUX
return Platform(arch, "linux")
elseif oh.ei.osabi == ELF.ELFOSABI_FREEBSD
return Platform(arch, "freebsd")
Expand Down Expand Up @@ -108,6 +135,13 @@ function is_for_platform(h::ObjectHandle, platform::AbstractPlatform)
else
error("Unknown OS ABI type $(typeof(platform))")
end
else
# If no OSABI, check whether it has a matching ELF note
if Sys.isfreebsd(platform)
if os_from_elf_note(h) != "FreeBSD"
return false
end
end
end
# Check that the ELF arch matches our own
m = h.header.e_machine
Expand Down
17 changes: 15 additions & 2 deletions src/auditor/extra_checks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ using Dates: DateTime, datetime2unix

function check_os_abi(oh::ObjectHandle, p::AbstractPlatform, rest...; verbose::Bool = false, kwargs...)
if Sys.isfreebsd(p)
if oh.ei.osabi != ELF.ELFOSABI_FREEBSD
# On AArch64 and RISC-V, FreeBSD uses an ELF note section to identify itself rather
# than OS/ABI in the ELF header. In that case, the OS/ABI will be generic Unix (NONE).
# See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=252490 and
# https://github.com/freebsd/freebsd-src/blob/main/lib/csu/common/crtbrand.S
if oh.ei.osabi == ELF.ELFOSABI_NONE
if os_from_elf_note(oh) != "FreeBSD"
if verbose
@warn("$(basename(path(oh))) does not have a FreeBSD-branded ELF note " *
"and may be unrecognized or unusable on $p")
end
return false
end
elseif oh.ei.osabi != ELF.ELFOSABI_FREEBSD
# The dynamic loader should not have problems in this case, but the
# linker may not appreciate. Let the user know about this.
if verbose
Expand All @@ -17,7 +29,8 @@ function check_os_abi(oh::ObjectHandle, p::AbstractPlatform, rest...; verbose::B
end
return false
end
elseif call_abi(p) == "eabihf"
end
if call_abi(p) == "eabihf"
# Make sure the object file has the hard-float ABI. See Table 4-2 of
# "ELF for the ARM Architecture" document
# (https://developer.arm.com/documentation/ihi0044/e/). Note: `0x000`
Expand Down

0 comments on commit 01b8996

Please sign in to comment.