authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-22 12:13:14+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-22 12:14:26+01:00
log215b8ba6fdfa31699be3a1cf76ab406694dcac72
tree5ad1cc6b745214d01f284108f08240b748cf375c
parent128fd31918c36b6a4d2a1f5fe19802303bc9f9c8
signature Commit is signed but in an unrecognized format.

Elf2: fix ehdr ident osabi check


1 files changed, 22 insertions(+), 12 deletions(-)

src/link/Elf2.zig+22-12
......@@ -3730,7 +3730,7 @@ fn create(
37303730 .big => .@"2MSB",
37313731 };
37323732 const osabi: std.elf.OSABI = switch (target.os.tag) {
3733 else => if (target.abi.isGnu()) .GNU else .NONE,
3733 else => .NONE, // might be changed to `.GNU` by `checkInputIdent`
37343734 .freestanding, .other => .STANDALONE,
37353735 .netbsd => .NETBSD,
37363736 .illumos => .SOLARIS,
......@@ -7089,9 +7089,11 @@ fn loadDso(
70897089/// `error.AlreadyReported`, but if the magic number is missing or incorrect, returns
70907090/// `error.BadMagic` instead.
70917091///
7092/// If necessary, modifies our own ident to use `ELF_OSABI_GNU` instead of `ELF_OSABI_NONE`.
7093///
70927094/// Does not advance the position of `r`. Requires `r` to have a 16-byte buffer.
70937095fn checkInputIdent(
7094 elf: *const Elf,
7096 elf: *Elf,
70957097 path: std.Build.Cache.Path,
70967098 r: *Io.Reader,
70977099) error{ BadMagic, EndOfStream, AlreadyReported, ReadFailed }!void {
......@@ -7106,8 +7108,9 @@ fn checkInputIdent(
71067108 }
71077109
71087110 const ident = try r.peekStructPointer(std.elf.Ident);
7109 const target: *const std.elf.Ident =
7110 @ptrCast(elf.ni.elf.sliceConst(&elf.mf)[0..@sizeOf(std.elf.Ident)]);
7111 const target: *std.elf.Ident = @ptrCast(
7112 elf.ni.elf.slice(&elf.mf)[0..@sizeOf(std.elf.Ident)],
7113 );
71117114
71127115 if (ident.class != target.class) return diags.failParse(
71137116 path,
......@@ -7124,17 +7127,24 @@ fn checkInputIdent(
71247127 "bad ELF version ({d})",
71257128 .{ident.version},
71267129 );
7127
7128 // OSABI is a bit more complex. On Linux, `.NONE` and `.GNU` are both valid and both common.
7129 // It sounds reasonable to allow the value we chose *and* allow `.NONE`.
7130 const expect_abiversion: u8 = abiver: {
7131 if (ident.osabi == .NONE) break :abiver 0;
7132 if (ident.osabi == target.osabi) break :abiver target.abiversion;
7133 return diags.failParse(
7130 // OSABI is a bit more complex.
7131 const expect_abiversion: u8 = switch (ident.osabi) {
7132 .NONE => 0,
7133 .GNU => abiversion: {
7134 // If we're currently emitting `ELF_OSABI_NONE` then prefer `ELF_OSABI_GNU` to signify
7135 // the GNU-specific features, but if we're already emitting a target-specific osabi then
7136 // just leave it alone.
7137 if (target.osabi == .NONE) target.osabi = .GNU;
7138 // Either way, allow the `ELF_OSABI_GNU` input through.
7139 break :abiversion 0;
7140 },
7141 else => if (ident.osabi == target.osabi) abiversion: {
7142 break :abiversion target.abiversion;
7143 } else return diags.failParse(
71347144 path,
71357145 "bad ELF OS/ABI ({?s})",
71367146 .{std.enums.tagName(std.elf.OSABI, ident.osabi)},
7137 );
7147 ),
71387148 };
71397149 if (ident.abiversion != expect_abiversion) return diags.failParse(
71407150 path,