Skip to content

Commit 25b3c0c

Browse files
author
git-bruh
committed
std.zig.NativeTargetInfo.abiAndDynamicLinkerFromFile: return an error when the file is not actually dynamic
1 parent 402468b commit 25b3c0c

File tree

1 file changed

+67
-51
lines changed

1 file changed

+67
-51
lines changed

lib/std/zig/system/NativeTargetInfo.zig

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ fn detectAbiAndDynamicLinker(
388388
error.Unexpected,
389389
error.UnexpectedEndOfFile,
390390
error.NameTooLong,
391+
error.StaticElfFile,
391392
// Finally, we fall back on the standard path.
392393
=> |e| {
393394
std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)});
@@ -607,6 +608,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
607608
Unexpected,
608609
UnexpectedEndOfFile,
609610
NameTooLong,
611+
StaticElfFile,
610612
};
611613

612614
pub fn abiAndDynamicLinkerFromFile(
@@ -654,6 +656,8 @@ pub fn abiAndDynamicLinkerFromFile(
654656
if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
655657

656658
var ph_i: u16 = 0;
659+
var got_dyn_section: bool = false;
660+
657661
while (ph_i < phnum) {
658662
// Reserve some bytes so that we can deref the 64-bit struct fields
659663
// even when the ELF file is 32-bits.
@@ -669,61 +673,69 @@ pub fn abiAndDynamicLinkerFromFile(
669673
const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i]));
670674
const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
671675
switch (p_type) {
672-
elf.PT_INTERP => if (look_for_ld) {
673-
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
674-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
675-
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
676-
const filesz = @as(usize, @intCast(p_filesz));
677-
_ = try preadMin(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
678-
// PT_INTERP includes a null byte in filesz.
679-
const len = filesz - 1;
680-
// dynamic_linker.max_byte is "max", not "len".
681-
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
682-
result.dynamic_linker.max_byte = @as(u8, @intCast(len - 1));
683-
684-
// Use it to determine ABI.
685-
const full_ld_path = result.dynamic_linker.buffer[0..len];
686-
for (ld_info_list) |ld_info| {
687-
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
688-
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
689-
result.target.abi = ld_info.abi;
690-
break;
676+
elf.PT_INTERP => {
677+
got_dyn_section = true;
678+
679+
if (look_for_ld) {
680+
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
681+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
682+
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
683+
const filesz = @as(usize, @intCast(p_filesz));
684+
_ = try preadMin(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
685+
// PT_INTERP includes a null byte in filesz.
686+
const len = filesz - 1;
687+
// dynamic_linker.max_byte is "max", not "len".
688+
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
689+
result.dynamic_linker.max_byte = @as(u8, @intCast(len - 1));
690+
691+
// Use it to determine ABI.
692+
const full_ld_path = result.dynamic_linker.buffer[0..len];
693+
for (ld_info_list) |ld_info| {
694+
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
695+
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
696+
result.target.abi = ld_info.abi;
697+
break;
698+
}
691699
}
692700
}
693701
},
694702
// We only need this for detecting glibc version.
695-
elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.target.isGnuLibC() and
696-
cross_target.glibc_version == null)
697-
{
698-
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
699-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
700-
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
701-
const dyn_num = p_filesz / dyn_size;
702-
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
703-
var dyn_i: usize = 0;
704-
dyn: while (dyn_i < dyn_num) {
705-
// Reserve some bytes so that we can deref the 64-bit struct fields
706-
// even when the ELF file is 32-bits.
707-
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
708-
const dyn_read_byte_len = try preadMin(
709-
file,
710-
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
711-
dyn_off,
712-
dyn_size,
713-
);
714-
var dyn_buf_i: usize = 0;
715-
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
716-
dyn_i += 1;
717-
dyn_off += dyn_size;
718-
dyn_buf_i += dyn_size;
719-
}) {
720-
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
721-
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
722-
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
723-
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
724-
if (tag == elf.DT_RUNPATH) {
725-
rpath_offset = val;
726-
break :dyn;
703+
elf.PT_DYNAMIC => {
704+
got_dyn_section = true;
705+
706+
if (builtin.target.os.tag == .linux and result.target.isGnuLibC() and
707+
cross_target.glibc_version == null)
708+
{
709+
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
710+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
711+
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
712+
const dyn_num = p_filesz / dyn_size;
713+
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
714+
var dyn_i: usize = 0;
715+
dyn: while (dyn_i < dyn_num) {
716+
// Reserve some bytes so that we can deref the 64-bit struct fields
717+
// even when the ELF file is 32-bits.
718+
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
719+
const dyn_read_byte_len = try preadMin(
720+
file,
721+
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
722+
dyn_off,
723+
dyn_size,
724+
);
725+
var dyn_buf_i: usize = 0;
726+
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
727+
dyn_i += 1;
728+
dyn_off += dyn_size;
729+
dyn_buf_i += dyn_size;
730+
}) {
731+
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
732+
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
733+
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
734+
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
735+
if (tag == elf.DT_RUNPATH) {
736+
rpath_offset = val;
737+
break :dyn;
738+
}
727739
}
728740
}
729741
}
@@ -733,6 +745,10 @@ pub fn abiAndDynamicLinkerFromFile(
733745
}
734746
}
735747

748+
if (!got_dyn_section) {
749+
return error.StaticElfFile;
750+
}
751+
736752
if (builtin.target.os.tag == .linux and result.target.isGnuLibC() and
737753
cross_target.glibc_version == null)
738754
{

0 commit comments

Comments
 (0)