Skip to content

Commit 5bb9963

Browse files
authored
abiAndDynamicLinkerFromFile: return an error when the file is not actually dynamic (#19928)
1 parent 263ba34 commit 5bb9963

File tree

1 file changed

+67
-51
lines changed

1 file changed

+67
-51
lines changed

lib/std/zig/system.zig

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
505505
UnexpectedEndOfFile,
506506
NameTooLong,
507507
ProcessNotFound,
508+
StaticElfFile,
508509
};
509510

510511
pub fn abiAndDynamicLinkerFromFile(
@@ -550,6 +551,8 @@ pub fn abiAndDynamicLinkerFromFile(
550551
if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
551552

552553
var ph_i: u16 = 0;
554+
var got_dyn_section: bool = false;
555+
553556
while (ph_i < phnum) {
554557
// Reserve some bytes so that we can deref the 64-bit struct fields
555558
// even when the ELF file is 32-bits.
@@ -565,61 +568,69 @@ pub fn abiAndDynamicLinkerFromFile(
565568
const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i]));
566569
const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
567570
switch (p_type) {
568-
elf.PT_INTERP => if (look_for_ld) {
569-
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
570-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
571-
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
572-
const filesz: usize = @intCast(p_filesz);
573-
_ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
574-
// PT_INTERP includes a null byte in filesz.
575-
const len = filesz - 1;
576-
// dynamic_linker.max_byte is "max", not "len".
577-
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
578-
result.dynamic_linker.len = @intCast(len);
579-
580-
// Use it to determine ABI.
581-
const full_ld_path = result.dynamic_linker.buffer[0..len];
582-
for (ld_info_list) |ld_info| {
583-
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
584-
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
585-
result.abi = ld_info.abi;
586-
break;
571+
elf.PT_INTERP => {
572+
got_dyn_section = true;
573+
574+
if (look_for_ld) {
575+
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
576+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
577+
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
578+
const filesz: usize = @intCast(p_filesz);
579+
_ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
580+
// PT_INTERP includes a null byte in filesz.
581+
const len = filesz - 1;
582+
// dynamic_linker.max_byte is "max", not "len".
583+
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
584+
result.dynamic_linker.len = @intCast(len);
585+
586+
// Use it to determine ABI.
587+
const full_ld_path = result.dynamic_linker.buffer[0..len];
588+
for (ld_info_list) |ld_info| {
589+
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
590+
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
591+
result.abi = ld_info.abi;
592+
break;
593+
}
587594
}
588595
}
589596
},
590597
// We only need this for detecting glibc version.
591-
elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.isGnuLibC() and
592-
query.glibc_version == null)
593-
{
594-
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
595-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
596-
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
597-
const dyn_num = p_filesz / dyn_size;
598-
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
599-
var dyn_i: usize = 0;
600-
dyn: while (dyn_i < dyn_num) {
601-
// Reserve some bytes so that we can deref the 64-bit struct fields
602-
// even when the ELF file is 32-bits.
603-
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
604-
const dyn_read_byte_len = try preadAtLeast(
605-
file,
606-
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
607-
dyn_off,
608-
dyn_size,
609-
);
610-
var dyn_buf_i: usize = 0;
611-
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
612-
dyn_i += 1;
613-
dyn_off += dyn_size;
614-
dyn_buf_i += dyn_size;
615-
}) {
616-
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
617-
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
618-
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
619-
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
620-
if (tag == elf.DT_RUNPATH) {
621-
rpath_offset = val;
622-
break :dyn;
598+
elf.PT_DYNAMIC => {
599+
got_dyn_section = true;
600+
601+
if (builtin.target.os.tag == .linux and result.isGnuLibC() and
602+
query.glibc_version == null)
603+
{
604+
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
605+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
606+
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
607+
const dyn_num = p_filesz / dyn_size;
608+
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
609+
var dyn_i: usize = 0;
610+
dyn: while (dyn_i < dyn_num) {
611+
// Reserve some bytes so that we can deref the 64-bit struct fields
612+
// even when the ELF file is 32-bits.
613+
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
614+
const dyn_read_byte_len = try preadAtLeast(
615+
file,
616+
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
617+
dyn_off,
618+
dyn_size,
619+
);
620+
var dyn_buf_i: usize = 0;
621+
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
622+
dyn_i += 1;
623+
dyn_off += dyn_size;
624+
dyn_buf_i += dyn_size;
625+
}) {
626+
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
627+
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
628+
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
629+
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
630+
if (tag == elf.DT_RUNPATH) {
631+
rpath_offset = val;
632+
break :dyn;
633+
}
623634
}
624635
}
625636
}
@@ -629,6 +640,10 @@ pub fn abiAndDynamicLinkerFromFile(
629640
}
630641
}
631642

643+
if (!got_dyn_section) {
644+
return error.StaticElfFile;
645+
}
646+
632647
if (builtin.target.os.tag == .linux and result.isGnuLibC() and
633648
query.glibc_version == null)
634649
{
@@ -1208,6 +1223,7 @@ fn detectAbiAndDynamicLinker(
12081223
error.Unexpected,
12091224
error.UnexpectedEndOfFile,
12101225
error.NameTooLong,
1226+
error.StaticElfFile,
12111227
// Finally, we fall back on the standard path.
12121228
=> |e| {
12131229
std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)});

0 commit comments

Comments
 (0)