From 5bb9963bbbfeed105542f52d022a80a7dd5e13a0 Mon Sep 17 00:00:00 2001 From: Pratham <67585967+git-bruh@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:24:10 +0530 Subject: abiAndDynamicLinkerFromFile: return an error when the file is not actually dynamic (#19928) --- lib/std/zig/system.zig | 118 ++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 51 deletions(-) (limited to 'lib') diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 3bc815eb87..427b260de0 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -505,6 +505,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{ UnexpectedEndOfFile, NameTooLong, ProcessNotFound, + StaticElfFile, }; pub fn abiAndDynamicLinkerFromFile( @@ -550,6 +551,8 @@ pub fn abiAndDynamicLinkerFromFile( if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile; var ph_i: u16 = 0; + var got_dyn_section: bool = false; + while (ph_i < phnum) { // Reserve some bytes so that we can deref the 64-bit struct fields // even when the ELF file is 32-bits. @@ -565,61 +568,69 @@ pub fn abiAndDynamicLinkerFromFile( const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); switch (p_type) { - elf.PT_INTERP => if (look_for_ld) { - const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); - const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); - if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; - const filesz: usize = @intCast(p_filesz); - _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); - // PT_INTERP includes a null byte in filesz. - const len = filesz - 1; - // dynamic_linker.max_byte is "max", not "len". - // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. - result.dynamic_linker.len = @intCast(len); - - // Use it to determine ABI. - const full_ld_path = result.dynamic_linker.buffer[0..len]; - for (ld_info_list) |ld_info| { - const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); - if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { - result.abi = ld_info.abi; - break; + elf.PT_INTERP => { + got_dyn_section = true; + + if (look_for_ld) { + const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); + const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); + if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; + const filesz: usize = @intCast(p_filesz); + _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); + // PT_INTERP includes a null byte in filesz. + const len = filesz - 1; + // dynamic_linker.max_byte is "max", not "len". + // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. + result.dynamic_linker.len = @intCast(len); + + // Use it to determine ABI. + const full_ld_path = result.dynamic_linker.buffer[0..len]; + for (ld_info_list) |ld_info| { + const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); + if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { + result.abi = ld_info.abi; + break; + } } } }, // We only need this for detecting glibc version. - elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.isGnuLibC() and - query.glibc_version == null) - { - var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); - const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); - const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); - const dyn_num = p_filesz / dyn_size; - var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; - var dyn_i: usize = 0; - dyn: while (dyn_i < dyn_num) { - // Reserve some bytes so that we can deref the 64-bit struct fields - // even when the ELF file is 32-bits. - const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); - const dyn_read_byte_len = try preadAtLeast( - file, - dyn_buf[0 .. dyn_buf.len - dyn_reserve], - dyn_off, - dyn_size, - ); - var dyn_buf_i: usize = 0; - while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ - dyn_i += 1; - dyn_off += dyn_size; - dyn_buf_i += dyn_size; - }) { - const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); - const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); - const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); - const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); - if (tag == elf.DT_RUNPATH) { - rpath_offset = val; - break :dyn; + elf.PT_DYNAMIC => { + got_dyn_section = true; + + if (builtin.target.os.tag == .linux and result.isGnuLibC() and + query.glibc_version == null) + { + var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); + const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); + const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); + const dyn_num = p_filesz / dyn_size; + var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; + var dyn_i: usize = 0; + dyn: while (dyn_i < dyn_num) { + // Reserve some bytes so that we can deref the 64-bit struct fields + // even when the ELF file is 32-bits. + const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); + const dyn_read_byte_len = try preadAtLeast( + file, + dyn_buf[0 .. dyn_buf.len - dyn_reserve], + dyn_off, + dyn_size, + ); + var dyn_buf_i: usize = 0; + while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ + dyn_i += 1; + dyn_off += dyn_size; + dyn_buf_i += dyn_size; + }) { + const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); + const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); + const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); + const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); + if (tag == elf.DT_RUNPATH) { + rpath_offset = val; + break :dyn; + } } } } @@ -629,6 +640,10 @@ pub fn abiAndDynamicLinkerFromFile( } } + if (!got_dyn_section) { + return error.StaticElfFile; + } + if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { @@ -1208,6 +1223,7 @@ fn detectAbiAndDynamicLinker( error.Unexpected, error.UnexpectedEndOfFile, error.NameTooLong, + error.StaticElfFile, // Finally, we fall back on the standard path. => |e| { std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)}); -- cgit v1.2.3