authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-25 20:23:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-25 20:24:05-07:00
logcf9735a5e06d302a29d70c737aefd505ca34e0fa
tree03ab9b4214484497990249099af9b41b292f350a
parent098a07dc45b678af22bb47379e75371767385cbf

link: Coff, MachO, and Wasm all had the same UAF bug


3 files changed, 95 insertions(+), 78 deletions(-)

src/link/Coff.zig+40-35
...@@ -1737,46 +1737,51 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link...@@ -1737,46 +1737,51 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link
1737 return 0;1737 return 0;
1738}1738}
17391739
1740pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result {1740pub fn lowerAnonDecl(
1741 // This is basically the same as lowerUnnamedConst.1741 self: *Coff,
1742 // example:1742 decl_val: InternPool.Index,
1743 // const ty = mod.intern_pool.typeOf(decl_val).toType();1743 explicit_alignment: InternPool.Alignment,
1744 // const val = decl_val.toValue();1744 src_loc: Module.SrcLoc,
1745 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.1745) !codegen.Result {
1746 // It doesn't have an owner decl because it's just an unnamed constant that might
1747 // be used by more than one function, however, its address is being used so we need
1748 // to put it in some location.
1749 // ...
1750 const gpa = self.base.allocator;1746 const gpa = self.base.allocator;
1751 const mod = self.base.options.module.?;1747 const mod = self.base.options.module.?;
1752 const ty = mod.intern_pool.typeOf(decl_val).toType();1748 const ty = mod.intern_pool.typeOf(decl_val).toType();
1753 const gop = try self.anon_decls.getOrPut(gpa, decl_val);1749 const decl_alignment = switch (explicit_alignment) {
1754 const required_alignment = switch (decl_align) {
1755 .none => ty.abiAlignment(mod),1750 .none => ty.abiAlignment(mod),
1756 else => decl_align,1751 else => explicit_alignment,
1757 };1752 };
1758 if (!gop.found_existing or1753 if (self.anon_decls.get(decl_val)) |atom_index| {
1759 !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).value))1754 const existing_addr = self.getAtom(atom_index).getSymbol(self).value;
1760 {1755 if (decl_alignment.check(existing_addr))
1761 const val = decl_val.toValue();1756 return .ok;
1762 const tv = TypedValue{ .ty = ty, .val = val };1757 }
1763 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});1758
1764 defer gpa.free(name);1759 const val = decl_val.toValue();
1765 const res = self.lowerConst(name, tv, required_alignment, self.rdata_section_index.?, src_loc) catch |err| switch (err) {1760 const tv = TypedValue{ .ty = ty, .val = val };
1766 else => {1761 var name_buf: [32]u8 = undefined;
1767 // TODO improve error message1762 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
1768 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{1763 @intFromEnum(decl_val),
1769 @errorName(err),1764 }) catch unreachable;
1770 });1765 const res = self.lowerConst(
1771 return .{ .fail = em };1766 name,
1772 },1767 tv,
1773 };1768 decl_alignment,
1774 const atom_index = switch (res) {1769 self.rdata_section_index.?,
1775 .ok => |atom_index| atom_index,1770 src_loc,
1776 .fail => |em| return .{ .fail = em },1771 ) catch |err| switch (err) {
1777 };1772 error.OutOfMemory => return error.OutOfMemory,
1778 gop.value_ptr.* = atom_index;1773 else => |e| return .{ .fail = try Module.ErrorMsg.create(
1779 }1774 gpa,
1775 src_loc,
1776 "lowerAnonDecl failed with error: {s}",
1777 .{@errorName(e)},
1778 ) },
1779 };
1780 const atom_index = switch (res) {
1781 .ok => |atom_index| atom_index,
1782 .fail => |em| return .{ .fail = em },
1783 };
1784 try self.anon_decls.put(gpa, decl_val, atom_index);
1780 return .ok;1785 return .ok;
1781}1786}
17821787
src/link/MachO.zig+40-35
...@@ -2866,46 +2866,51 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2866,46 +2866,51 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2866 return 0;2866 return 0;
2867}2867}
28682868
2869pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result {2869pub fn lowerAnonDecl(
2870 // This is basically the same as lowerUnnamedConst.2870 self: *MachO,
2871 // example:2871 decl_val: InternPool.Index,
2872 // const ty = mod.intern_pool.typeOf(decl_val).toType();2872 explicit_alignment: InternPool.Alignment,
2873 // const val = decl_val.toValue();2873 src_loc: Module.SrcLoc,
2874 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.2874) !codegen.Result {
2875 // It doesn't have an owner decl because it's just an unnamed constant that might
2876 // be used by more than one function, however, its address is being used so we need
2877 // to put it in some location.
2878 // ...
2879 const gpa = self.base.allocator;2875 const gpa = self.base.allocator;
2880 const mod = self.base.options.module.?;2876 const mod = self.base.options.module.?;
2881 const ty = mod.intern_pool.typeOf(decl_val).toType();2877 const ty = mod.intern_pool.typeOf(decl_val).toType();
2882 const gop = try self.anon_decls.getOrPut(gpa, decl_val);2878 const decl_alignment = switch (explicit_alignment) {
2883 const required_alignment = switch (decl_align) {
2884 .none => ty.abiAlignment(mod),2879 .none => ty.abiAlignment(mod),
2885 else => decl_align,2880 else => explicit_alignment,
2886 };2881 };
2887 if (!gop.found_existing or2882 if (self.anon_decls.get(decl_val)) |atom_index| {
2888 !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).n_value))2883 const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value;
2889 {2884 if (decl_alignment.check(existing_addr))
2890 const val = decl_val.toValue();2885 return .ok;
2891 const tv = TypedValue{ .ty = ty, .val = val };2886 }
2892 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});2887
2893 defer gpa.free(name);2888 const val = decl_val.toValue();
2894 const res = self.lowerConst(name, tv, required_alignment, self.data_const_section_index.?, src_loc) catch |err| switch (err) {2889 const tv = TypedValue{ .ty = ty, .val = val };
2895 else => {2890 var name_buf: [32]u8 = undefined;
2896 // TODO improve error message2891 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
2897 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{2892 @intFromEnum(decl_val),
2898 @errorName(err),2893 }) catch unreachable;
2899 });2894 const res = self.lowerConst(
2900 return .{ .fail = em };2895 name,
2901 },2896 tv,
2902 };2897 decl_alignment,
2903 const atom_index = switch (res) {2898 self.data_const_section_index.?,
2904 .ok => |atom_index| atom_index,2899 src_loc,
2905 .fail => |em| return .{ .fail = em },2900 ) catch |err| switch (err) {
2906 };2901 error.OutOfMemory => return error.OutOfMemory,
2907 gop.value_ptr.* = atom_index;2902 else => |e| return .{ .fail = try Module.ErrorMsg.create(
2908 }2903 gpa,
2904 src_loc,
2905 "unable to lower constant value: {s}",
2906 .{@errorName(e)},
2907 ) },
2908 };
2909 const atom_index = switch (res) {
2910 .ok => |atom_index| atom_index,
2911 .fail => |em| return .{ .fail = em },
2912 };
2913 try self.anon_decls.put(gpa, decl_val, atom_index);
2909 return .ok;2914 return .ok;
2910}2915}
29112916
src/link/Wasm.zig+15-8
...@@ -1702,27 +1702,34 @@ pub fn getDeclVAddr(...@@ -1702,27 +1702,34 @@ pub fn getDeclVAddr(
1702 return target_symbol_index;1702 return target_symbol_index;
1703}1703}
17041704
1705pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, decl_align: Alignment, src_loc: Module.SrcLoc) !codegen.Result {1705pub fn lowerAnonDecl(
1706 wasm: *Wasm,
1707 decl_val: InternPool.Index,
1708 explicit_alignment: Alignment,
1709 src_loc: Module.SrcLoc,
1710) !codegen.Result {
1706 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);1711 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
1707 if (!gop.found_existing) {1712 if (!gop.found_existing) {
1708 const mod = wasm.base.options.module.?;1713 const mod = wasm.base.options.module.?;
1709 const ty = mod.intern_pool.typeOf(decl_val).toType();1714 const ty = mod.intern_pool.typeOf(decl_val).toType();
1710 const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };1715 const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };
1711 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)});1716 var name_buf: [32]u8 = undefined;
1712 defer wasm.base.allocator.free(name);1717 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
1718 @intFromEnum(decl_val),
1719 }) catch unreachable;
17131720
1714 switch (try wasm.lowerConst(name, tv, src_loc)) {1721 switch (try wasm.lowerConst(name, tv, src_loc)) {
1715 .ok => |atom_index| gop.value_ptr.* = atom_index,1722 .ok => |atom_index| wasm.anon_decls.values()[gop.index] = atom_index,
1716 .fail => |em| return .{ .fail = em },1723 .fail => |em| return .{ .fail = em },
1717 }1724 }
1718 }1725 }
17191726
1720 const atom = wasm.getAtomPtr(gop.value_ptr.*);1727 const atom = wasm.getAtomPtr(wasm.anon_decls.values()[gop.index]);
1721 atom.alignment = switch (atom.alignment) {1728 atom.alignment = switch (atom.alignment) {
1722 .none => decl_align,1729 .none => explicit_alignment,
1723 else => switch (decl_align) {1730 else => switch (explicit_alignment) {
1724 .none => atom.alignment,1731 .none => atom.alignment,
1725 else => atom.alignment.maxStrict(decl_align),1732 else => atom.alignment.maxStrict(explicit_alignment),
1726 },1733 },
1727 };1734 };
1728 return .ok;1735 return .ok;