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{...@@ -505,6 +505,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
505 UnexpectedEndOfFile,505 UnexpectedEndOfFile,
506 NameTooLong,506 NameTooLong,
507 ProcessNotFound,507 ProcessNotFound,
508 StaticElfFile,
508};509};
509510
510pub fn abiAndDynamicLinkerFromFile(511pub fn abiAndDynamicLinkerFromFile(
...@@ -550,6 +551,8 @@ pub fn abiAndDynamicLinkerFromFile(...@@ -550,6 +551,8 @@ pub fn abiAndDynamicLinkerFromFile(
550 if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;551 if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
551552
552 var ph_i: u16 = 0;553 var ph_i: u16 = 0;
554 var got_dyn_section: bool = false;
555
553 while (ph_i < phnum) {556 while (ph_i < phnum) {
554 // Reserve some bytes so that we can deref the 64-bit struct fields557 // Reserve some bytes so that we can deref the 64-bit struct fields
555 // even when the ELF file is 32-bits.558 // even when the ELF file is 32-bits.
...@@ -565,61 +568,69 @@ pub fn abiAndDynamicLinkerFromFile(...@@ -565,61 +568,69 @@ pub fn abiAndDynamicLinkerFromFile(
565 const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i]));568 const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i]));
566 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);569 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
567 switch (p_type) {570 switch (p_type) {
568 elf.PT_INTERP => if (look_for_ld) {571 elf.PT_INTERP => {
569 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);572 got_dyn_section = true;
570 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);573
571 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;574 if (look_for_ld) {
572 const filesz: usize = @intCast(p_filesz);575 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
573 _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);576 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
574 // PT_INTERP includes a null byte in filesz.577 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
575 const len = filesz - 1;578 const filesz: usize = @intCast(p_filesz);
576 // dynamic_linker.max_byte is "max", not "len".579 _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
577 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.580 // PT_INTERP includes a null byte in filesz.
578 result.dynamic_linker.len = @intCast(len);581 const len = filesz - 1;
579582 // dynamic_linker.max_byte is "max", not "len".
580 // Use it to determine ABI.583 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
581 const full_ld_path = result.dynamic_linker.buffer[0..len];584 result.dynamic_linker.len = @intCast(len);
582 for (ld_info_list) |ld_info| {585
583 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);586 // Use it to determine ABI.
584 if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {587 const full_ld_path = result.dynamic_linker.buffer[0..len];
585 result.abi = ld_info.abi;588 for (ld_info_list) |ld_info| {
586 break;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 }
587 }594 }
588 }595 }
589 },596 },
590 // We only need this for detecting glibc version.597 // We only need this for detecting glibc version.
591 elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.isGnuLibC() and598 elf.PT_DYNAMIC => {
592 query.glibc_version == null)599 got_dyn_section = true;
593 {600
594 var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);601 if (builtin.target.os.tag == .linux and result.isGnuLibC() and
595 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);602 query.glibc_version == null)
596 const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);603 {
597 const dyn_num = p_filesz / dyn_size;604 var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
598 var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;605 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
599 var dyn_i: usize = 0;606 const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
600 dyn: while (dyn_i < dyn_num) {607 const dyn_num = p_filesz / dyn_size;
601 // Reserve some bytes so that we can deref the 64-bit struct fields608 var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
602 // even when the ELF file is 32-bits.609 var dyn_i: usize = 0;
603 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);610 dyn: while (dyn_i < dyn_num) {
604 const dyn_read_byte_len = try preadAtLeast(611 // Reserve some bytes so that we can deref the 64-bit struct fields
605 file,612 // even when the ELF file is 32-bits.
606 dyn_buf[0 .. dyn_buf.len - dyn_reserve],613 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
607 dyn_off,614 const dyn_read_byte_len = try preadAtLeast(
608 dyn_size,615 file,
609 );616 dyn_buf[0 .. dyn_buf.len - dyn_reserve],
610 var dyn_buf_i: usize = 0;617 dyn_off,
611 while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({618 dyn_size,
612 dyn_i += 1;619 );
613 dyn_off += dyn_size;620 var dyn_buf_i: usize = 0;
614 dyn_buf_i += dyn_size;621 while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
615 }) {622 dyn_i += 1;
616 const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));623 dyn_off += dyn_size;
617 const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));624 dyn_buf_i += dyn_size;
618 const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);625 }) {
619 const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);626 const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
620 if (tag == elf.DT_RUNPATH) {627 const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
621 rpath_offset = val;628 const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
622 break :dyn;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 }
623 }634 }
624 }635 }
625 }636 }
...@@ -629,6 +640,10 @@ pub fn abiAndDynamicLinkerFromFile(...@@ -629,6 +640,10 @@ pub fn abiAndDynamicLinkerFromFile(
629 }640 }
630 }641 }
631642
643 if (!got_dyn_section) {
644 return error.StaticElfFile;
645 }
646
632 if (builtin.target.os.tag == .linux and result.isGnuLibC() and647 if (builtin.target.os.tag == .linux and result.isGnuLibC() and
633 query.glibc_version == null)648 query.glibc_version == null)
634 {649 {
...@@ -1208,6 +1223,7 @@ fn detectAbiAndDynamicLinker(...@@ -1208,6 +1223,7 @@ fn detectAbiAndDynamicLinker(
1208 error.Unexpected,1223 error.Unexpected,
1209 error.UnexpectedEndOfFile,1224 error.UnexpectedEndOfFile,
1210 error.NameTooLong,1225 error.NameTooLong,
1226 error.StaticElfFile,
1211 // Finally, we fall back on the standard path.1227 // Finally, we fall back on the standard path.
1212 => |e| {1228 => |e| {
1213 std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)});1229 std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)});