authorgravatar for 67585967+git-bruh@users.noreply.github.comPratham <67585967+git-bruh@users.noreply.github.com> 2025-03-27 01:24:10+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-03-26 19:54:10+00:00
log5bb9963bbbfeed105542f52d022a80a7dd5e13a0
treeb66d1c4e26ea25e9494b2612240b3e7b858c425f
parent263ba346198c921cf80e63db0c45405dba029933
signaturebadge-check Signed by PGP key B5690EEEBB952194

abiAndDynamicLinkerFromFile: return an error when the file is not actually dynamic (#19928)


1 files changed, 67 insertions(+), 51 deletions(-)

lib/std/zig/system.zig+67-51
......@@ -505,6 +505,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
505505 UnexpectedEndOfFile,
506506 NameTooLong,
507507 ProcessNotFound,
508 StaticElfFile,
508509};
509510
510511pub 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)});