authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-25 19:50:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-25 19:57:02-07:00
log098a07dc45b678af22bb47379e75371767385cbf
tree6e5427e597fc5230b8448ce8a440dc29c4e00fc2
parentcbcef2d806c346b317ca233038ea66fe31dbb3c2

link.Elf: fix UAF in lowerAnonDecl

The main problem being fixed here is there was a getOrPut() that held on to a reference to the value pointer too long, and meanwhile the call to `lowerConst` ended up being recursive and mutating the hash map, invoking undefined behavior. caught via #17719

1 files changed, 40 insertions(+), 35 deletions(-)

src/link/Elf.zig+40-35
...@@ -484,46 +484,51 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link....@@ -484,46 +484,51 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
484 return vaddr;484 return vaddr;
485}485}
486486
487pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result {487pub fn lowerAnonDecl(
488 // This is basically the same as lowerUnnamedConst.488 self: *Elf,
489 // example:489 decl_val: InternPool.Index,
490 // const ty = mod.intern_pool.typeOf(decl_val).toType();490 explicit_alignment: InternPool.Alignment,
491 // const val = decl_val.toValue();491 src_loc: Module.SrcLoc,
492 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.492) !codegen.Result {
493 // It doesn't have an owner decl because it's just an unnamed constant that might
494 // be used by more than one function, however, its address is being used so we need
495 // to put it in some location.
496 // ...
497 const gpa = self.base.allocator;493 const gpa = self.base.allocator;
498 const mod = self.base.options.module.?;494 const mod = self.base.options.module.?;
499 const ty = mod.intern_pool.typeOf(decl_val).toType();495 const ty = mod.intern_pool.typeOf(decl_val).toType();
500 const gop = try self.anon_decls.getOrPut(gpa, decl_val);496 const decl_alignment = switch (explicit_alignment) {
501 const required_alignment = switch (decl_align) {
502 .none => ty.abiAlignment(mod),497 .none => ty.abiAlignment(mod),
503 else => decl_align,498 else => explicit_alignment,
504 };499 };
505 if (!gop.found_existing or500 if (self.anon_decls.get(decl_val)) |sym_index| {
506 required_alignment.order(self.symbol(gop.value_ptr.*).atom(self).?.alignment).compare(.gt))501 const existing_alignment = self.symbol(sym_index).atom(self).?.alignment;
507 {502 if (decl_alignment.order(existing_alignment).compare(.lte))
508 const val = decl_val.toValue();503 return .ok;
509 const tv = TypedValue{ .ty = ty, .val = val };504 }
510 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});505
511 defer gpa.free(name);506 const val = decl_val.toValue();
512 const res = self.lowerConst(name, tv, required_alignment, self.zig_rodata_section_index.?, src_loc) catch |err| switch (err) {507 const tv = TypedValue{ .ty = ty, .val = val };
513 else => {508 var name_buf: [32]u8 = undefined;
514 // TODO improve error message509 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
515 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{510 @intFromEnum(decl_val),
516 @errorName(err),511 }) catch unreachable;
517 });512 const res = self.lowerConst(
518 return .{ .fail = em };513 name,
519 },514 tv,
520 };515 decl_alignment,
521 const sym_index = switch (res) {516 self.zig_rodata_section_index.?,
522 .ok => |sym_index| sym_index,517 src_loc,
523 .fail => |em| return .{ .fail = em },518 ) catch |err| switch (err) {
524 };519 error.OutOfMemory => return error.OutOfMemory,
525 gop.value_ptr.* = sym_index;520 else => |e| return .{ .fail = try Module.ErrorMsg.create(
526 }521 gpa,
522 src_loc,
523 "unable to lower constant value: {s}",
524 .{@errorName(e)},
525 ) },
526 };
527 const sym_index = switch (res) {
528 .ok => |sym_index| sym_index,
529 .fail => |em| return .{ .fail = em },
530 };
531 try self.anon_decls.put(gpa, decl_val, sym_index);
527 return .ok;532 return .ok;
528}533}
529534