Skip to content

Commit 0e34bfa

Browse files
git-bruhandrewrk
authored andcommitted
abiAndDynamicLinkerFromFile: return an error when the file is not actually dynamic
1 parent 9374725 commit 0e34bfa

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
@@ -436,6 +436,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
436436
Unexpected,
437437
UnexpectedEndOfFile,
438438
NameTooLong,
439+
StaticElfFile,
439440
};
440441

441442
pub fn abiAndDynamicLinkerFromFile(
@@ -481,6 +482,8 @@ pub fn abiAndDynamicLinkerFromFile(
481482
if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
482483

483484
var ph_i: u16 = 0;
485+
var got_dyn_section: bool = false;
486+
484487
while (ph_i < phnum) {
485488
// Reserve some bytes so that we can deref the 64-bit struct fields
486489
// even when the ELF file is 32-bits.
@@ -496,61 +499,69 @@ pub fn abiAndDynamicLinkerFromFile(
496499
const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i]));
497500
const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
498501
switch (p_type) {
499-
elf.PT_INTERP => if (look_for_ld) {
500-
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
501-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
502-
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
503-
const filesz: usize = @intCast(p_filesz);
504-
_ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
505-
// PT_INTERP includes a null byte in filesz.
506-
const len = filesz - 1;
507-
// dynamic_linker.max_byte is "max", not "len".
508-
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
509-
result.dynamic_linker.len = @intCast(len);
510-
511-
// Use it to determine ABI.
512-
const full_ld_path = result.dynamic_linker.buffer[0..len];
513-
for (ld_info_list) |ld_info| {
514-
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
515-
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
516-
result.abi = ld_info.abi;
517-
break;
502+
elf.PT_INTERP => {
503+
got_dyn_section = true;
504+
505+
if (look_for_ld) {
506+
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
507+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
508+
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
509+
const filesz: usize = @intCast(p_filesz);
510+
_ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
511+
// PT_INTERP includes a null byte in filesz.
512+
const len = filesz - 1;
513+
// dynamic_linker.max_byte is "max", not "len".
514+
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
515+
result.dynamic_linker.len = @intCast(len);
516+
517+
// Use it to determine ABI.
518+
const full_ld_path = result.dynamic_linker.buffer[0..len];
519+
for (ld_info_list) |ld_info| {
520+
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
521+
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
522+
result.abi = ld_info.abi;
523+
break;
524+
}
518525
}
519526
}
520527
},
521528
// We only need this for detecting glibc version.
522-
elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.isGnuLibC() and
523-
query.glibc_version == null)
524-
{
525-
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
526-
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
527-
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
528-
const dyn_num = p_filesz / dyn_size;
529-
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
530-
var dyn_i: usize = 0;
531-
dyn: while (dyn_i < dyn_num) {
532-
// Reserve some bytes so that we can deref the 64-bit struct fields
533-
// even when the ELF file is 32-bits.
534-
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
535-
const dyn_read_byte_len = try preadAtLeast(
536-
file,
537-
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
538-
dyn_off,
539-
dyn_size,
540-
);
541-
var dyn_buf_i: usize = 0;
542-
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
543-
dyn_i += 1;
544-
dyn_off += dyn_size;
545-
dyn_buf_i += dyn_size;
546-
}) {
547-
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
548-
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
549-
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
550-
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
551-
if (tag == elf.DT_RUNPATH) {
552-
rpath_offset = val;
553-
break :dyn;
529+
elf.PT_DYNAMIC => {
530+
got_dyn_section = true;
531+
532+
if (builtin.target.os.tag == .linux and result.isGnuLibC() and
533+
query.glibc_version == null)
534+
{
535+
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
536+
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
537+
const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
538+
const dyn_num = p_filesz / dyn_size;
539+
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
540+
var dyn_i: usize = 0;
541+
dyn: while (dyn_i < dyn_num) {
542+
// Reserve some bytes so that we can deref the 64-bit struct fields
543+
// even when the ELF file is 32-bits.
544+
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
545+
const dyn_read_byte_len = try preadAtLeast(
546+
file,
547+
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
548+
dyn_off,
549+
dyn_size,
550+
);
551+
var dyn_buf_i: usize = 0;
552+
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
553+
dyn_i += 1;
554+
dyn_off += dyn_size;
555+
dyn_buf_i += dyn_size;
556+
}) {
557+
const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
558+
const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i]));
559+
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
560+
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
561+
if (tag == elf.DT_RUNPATH) {
562+
rpath_offset = val;
563+
break :dyn;
564+
}
554565
}
555566
}
556567
}
@@ -560,6 +571,10 @@ pub fn abiAndDynamicLinkerFromFile(
560571
}
561572
}
562573

574+
if (!got_dyn_section) {
575+
return error.StaticElfFile;
576+
}
577+
563578
if (builtin.target.os.tag == .linux and result.isGnuLibC() and
564579
query.glibc_version == null)
565580
{
@@ -1124,6 +1139,7 @@ fn detectAbiAndDynamicLinker(
11241139
error.Unexpected,
11251140
error.UnexpectedEndOfFile,
11261141
error.NameTooLong,
1142+
error.StaticElfFile,
11271143
// Finally, we fall back on the standard path.
11281144
=> |e| {
11291145
std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)});

0 commit comments

Comments
 (0)