aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-11-10 22:27:45 -0500
committerGitHub <noreply@github.com>2023-11-10 22:27:45 -0500
commit97e23896a9168132b6d36ca22ae1af10dd53d80d (patch)
treeb7d25c4231838edf980b7de7eec317f0a23371ee
parent138a35df8f434115be04641b1df29514b0ef1cb8 (diff)
parentdfee782d7c30e2ff84060833be375e8cdf92e3be (diff)
downloadzig-97e23896a9168132b6d36ca22ae1af10dd53d80d.tar.gz
zig-97e23896a9168132b6d36ca22ae1af10dd53d80d.zip
Merge pull request #17962 from ziglang/libssp
move libssp into libcompiler_rt
-rw-r--r--lib/compiler_rt.zig1
-rw-r--r--lib/compiler_rt/ssp.zig143
-rw-r--r--lib/ssp.zig135
-rw-r--r--src/Compilation.zig97
-rw-r--r--src/link/Coff/lld.zig6
-rw-r--r--src/link/Elf.zig18
-rw-r--r--src/target.zig15
-rw-r--r--stage1/config.zig.in1
8 files changed, 181 insertions, 235 deletions
diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig
index f0503d2219..173e6af85a 100644
--- a/lib/compiler_rt.zig
+++ b/lib/compiler_rt.zig
@@ -233,5 +233,6 @@ comptime {
_ = @import("compiler_rt/memmove.zig");
_ = @import("compiler_rt/memcmp.zig");
_ = @import("compiler_rt/bcmp.zig");
+ _ = @import("compiler_rt/ssp.zig");
}
}
diff --git a/lib/compiler_rt/ssp.zig b/lib/compiler_rt/ssp.zig
new file mode 100644
index 0000000000..236428e1ca
--- /dev/null
+++ b/lib/compiler_rt/ssp.zig
@@ -0,0 +1,143 @@
+//!
+//! Small Zig reimplementation of gcc's libssp.
+//!
+//! This library implements most of the builtins required by the stack smashing
+//! protection as implemented by gcc&clang.
+//! Missing exports:
+//! - __gets_chk
+//! - __mempcpy_chk
+//! - __snprintf_chk
+//! - __sprintf_chk
+//! - __stpcpy_chk
+//! - __vsnprintf_chk
+//! - __vsprintf_chk
+
+const std = @import("std");
+const common = @import("./common.zig");
+const builtin = @import("builtin");
+
+extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8;
+extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
+extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
+
+comptime {
+ @export(__stack_chk_fail, .{ .name = "__stack_chk_fail", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__chk_fail, .{ .name = "__chk_fail", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__strcpy_chk, .{ .name = "__strcpy_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__strncpy_chk, .{ .name = "__strncpy_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__strcat_chk, .{ .name = "__strcat_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__strncat_chk, .{ .name = "__strncat_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__memcpy_chk, .{ .name = "__memcpy_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__memmove_chk, .{ .name = "__memmove_chk", .linkage = common.linkage, .visibility = common.visibility });
+ @export(__memset_chk, .{ .name = "__memset_chk", .linkage = common.linkage, .visibility = common.visibility });
+}
+
+fn __stack_chk_fail() callconv(.C) noreturn {
+ @panic("stack smashing detected");
+}
+
+fn __chk_fail() callconv(.C) noreturn {
+ @panic("buffer overflow detected");
+}
+
+// TODO: Initialize the canary with random data
+var __stack_chk_guard: usize = blk: {
+ var buf = [1]u8{0} ** @sizeOf(usize);
+ buf[@sizeOf(usize) - 1] = 255;
+ buf[@sizeOf(usize) - 2] = '\n';
+ break :blk @as(usize, @bitCast(buf));
+};
+
+fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
+ @setRuntimeSafety(false);
+
+ var i: usize = 0;
+ while (i < dest_n and src[i] != 0) : (i += 1) {
+ dest[i] = src[i];
+ }
+
+ if (i == dest_n) __chk_fail();
+
+ dest[i] = 0;
+
+ return dest;
+}
+
+fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
+ @setRuntimeSafety(false);
+ if (dest_n < n) __chk_fail();
+ var i: usize = 0;
+ while (i < n and src[i] != 0) : (i += 1) {
+ dest[i] = src[i];
+ }
+ while (i < n) : (i += 1) {
+ dest[i] = 0;
+ }
+ return dest;
+}
+
+fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
+ @setRuntimeSafety(false);
+
+ var avail = dest_n;
+
+ var dest_end: usize = 0;
+ while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
+ avail -= 1;
+ }
+
+ if (avail < 1) __chk_fail();
+
+ var i: usize = 0;
+ while (avail > 0 and src[i] != 0) : (i += 1) {
+ dest[dest_end + i] = src[i];
+ avail -= 1;
+ }
+
+ if (avail < 1) __chk_fail();
+
+ dest[dest_end + i] = 0;
+
+ return dest;
+}
+
+fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
+ @setRuntimeSafety(false);
+
+ var avail = dest_n;
+
+ var dest_end: usize = 0;
+ while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
+ avail -= 1;
+ }
+
+ if (avail < 1) __chk_fail();
+
+ var i: usize = 0;
+ while (avail > 0 and i < n and src[i] != 0) : (i += 1) {
+ dest[dest_end + i] = src[i];
+ avail -= 1;
+ }
+
+ if (avail < 1) __chk_fail();
+
+ dest[dest_end + i] = 0;
+
+ return dest;
+}
+
+fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
+ if (dest_n < n) __chk_fail();
+ return memcpy(dest, src, n);
+}
+
+fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
+ if (dest_n < n) __chk_fail();
+ return memmove(dest, src, n);
+}
+
+fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
+ if (dest_n < n) __chk_fail();
+ return memset(dest, c, n);
+}
diff --git a/lib/ssp.zig b/lib/ssp.zig
deleted file mode 100644
index 4f8eba567f..0000000000
--- a/lib/ssp.zig
+++ /dev/null
@@ -1,135 +0,0 @@
-//!
-//! Small Zig reimplementation of gcc's libssp.
-//!
-//! This library implements most of the builtins required by the stack smashing
-//! protection as implemented by gcc&clang.
-//! Missing exports:
-//! - __gets_chk
-//! - __mempcpy_chk
-//! - __snprintf_chk
-//! - __sprintf_chk
-//! - __stpcpy_chk
-//! - __vsnprintf_chk
-//! - __vsprintf_chk
-
-const std = @import("std");
-
-extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8;
-extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8;
-extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
-extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
-
-// Avoid dragging in the runtime safety mechanisms into this .o file.
-pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
- _ = msg;
- _ = error_return_trace;
- @setCold(true);
- std.os.abort();
-}
-
-export fn __stack_chk_fail() callconv(.C) noreturn {
- @panic("stack smashing detected");
-}
-
-export fn __chk_fail() callconv(.C) noreturn {
- @panic("buffer overflow detected");
-}
-
-// Emitted when targeting some architectures (eg. x86)
-// XXX: This symbol should be hidden
-export fn __stack_chk_fail_local() callconv(.C) noreturn {
- __stack_chk_fail();
-}
-
-// XXX: Initialize the canary with random data
-export var __stack_chk_guard: usize = blk: {
- var buf = [1]u8{0} ** @sizeOf(usize);
- buf[@sizeOf(usize) - 1] = 255;
- buf[@sizeOf(usize) - 2] = '\n';
- break :blk @as(usize, @bitCast(buf));
-};
-
-export fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
- @setRuntimeSafety(false);
-
- var i: usize = 0;
- while (i < dest_n and src[i] != 0) : (i += 1) {
- dest[i] = src[i];
- }
-
- if (i == dest_n) __chk_fail();
-
- dest[i] = 0;
-
- return dest;
-}
-
-export fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
- if (dest_n < n) __chk_fail();
- return strncpy(dest, src, n);
-}
-
-export fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
- @setRuntimeSafety(false);
-
- var avail = dest_n;
-
- var dest_end: usize = 0;
- while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
- avail -= 1;
- }
-
- if (avail < 1) __chk_fail();
-
- var i: usize = 0;
- while (avail > 0 and src[i] != 0) : (i += 1) {
- dest[dest_end + i] = src[i];
- avail -= 1;
- }
-
- if (avail < 1) __chk_fail();
-
- dest[dest_end + i] = 0;
-
- return dest;
-}
-
-export fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
- @setRuntimeSafety(false);
-
- var avail = dest_n;
-
- var dest_end: usize = 0;
- while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
- avail -= 1;
- }
-
- if (avail < 1) __chk_fail();
-
- var i: usize = 0;
- while (avail > 0 and i < n and src[i] != 0) : (i += 1) {
- dest[dest_end + i] = src[i];
- avail -= 1;
- }
-
- if (avail < 1) __chk_fail();
-
- dest[dest_end + i] = 0;
-
- return dest;
-}
-
-export fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
- if (dest_n < n) __chk_fail();
- return memcpy(dest, src, n);
-}
-
-export fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
- if (dest_n < n) __chk_fail();
- return memmove(dest, src, n);
-}
-
-export fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
- if (dest_n < n) __chk_fail();
- return memset(dest, c, n);
-}
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 3bd7d1506c..00b7c50357 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -152,9 +152,6 @@ libunwind_static_lib: ?CRTFile = null,
/// Populated when we build the TSAN static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
tsan_static_lib: ?CRTFile = null,
-/// Populated when we build the libssp static library. A Job to build this is placed in the queue
-/// and resolved before calling linker.flush().
-libssp_static_lib: ?CRTFile = null,
/// Populated when we build the libc static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libc_static_lib: ?CRTFile = null,
@@ -286,7 +283,6 @@ const Job = union(enum) {
libcxx: void,
libcxxabi: void,
libtsan: void,
- libssp: void,
/// needed when not linking libc and using LLVM for code generation because it generates
/// calls to, for example, memcpy and memset.
zig_libc: void,
@@ -683,7 +679,6 @@ pub const MiscTask = enum {
libtsan,
wasi_libc_crt_file,
compiler_rt,
- libssp,
zig_libc,
analyze_mod,
@@ -1072,8 +1067,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.Exe => true,
};
- const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib;
-
// WASI-only. Resolve the optional exec-model option, defaults to command.
const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command;
@@ -1355,10 +1348,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
if (stack_check and !target_util.supportsStackProbing(options.target))
return error.StackCheckUnsupportedByTarget;
- const capable_of_building_ssp = canBuildLibSsp(options.target, use_llvm);
-
- const stack_protector: u32 = options.want_stack_protector orelse b: {
- if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0);
+ const stack_protector: u32 = sp: {
+ const zig_backend = zigBackend(options.target, use_llvm);
+ if (!target_util.supportsStackProtector(options.target, zig_backend)) {
+ if (options.want_stack_protector) |x| {
+ if (x > 0) return error.StackProtectorUnsupportedByTarget;
+ }
+ break :sp 0;
+ }
// This logic is checking for linking libc because otherwise our start code
// which is trying to set up TLS (i.e. the fs/gs registers) but the stack
@@ -1367,21 +1364,20 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
// as being exempt from stack protection checks, we could change this logic
// to supporting stack protection even when not linking libc.
// TODO file issue about this
- if (!link_libc) break :b 0;
- if (!capable_of_building_ssp) break :b 0;
- if (is_safe_mode) break :b default_stack_protector_buffer_size;
- break :b 0;
+ if (!link_libc) {
+ if (options.want_stack_protector) |x| {
+ if (x > 0) return error.StackProtectorUnavailableWithoutLibC;
+ }
+ break :sp 0;
+ }
+
+ if (options.want_stack_protector) |x| break :sp x;
+ if (is_safe_mode) break :sp default_stack_protector_buffer_size;
+ break :sp 0;
};
- if (stack_protector != 0) {
- if (!target_util.supportsStackProtector(options.target))
- return error.StackProtectorUnsupportedByTarget;
- if (!capable_of_building_ssp)
- return error.StackProtectorUnsupportedByBackend;
- if (!link_libc)
- return error.StackProtectorUnavailableWithoutLibC;
- }
- const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;
+ const include_compiler_rt = options.want_compiler_rt orelse
+ (!options.skip_linker_dependencies and is_exe_or_dyn_lib);
const single_threaded = st: {
if (target_util.isSingleThreaded(options.target)) {
@@ -2196,18 +2192,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
comp.job_queued_compiler_rt_obj = true;
}
}
- if (needs_c_symbols) {
- // Related: https://github.com/ziglang/zig/issues/7265.
- if (comp.bin_file.options.stack_protector != 0 and
- (!comp.bin_file.options.link_libc or
- !target_util.libcProvidesStackProtector(target)))
- {
- try comp.work_queue.writeItem(.{ .libssp = {} });
- }
- if (!comp.bin_file.options.link_libc and capable_of_building_zig_libc) {
- try comp.work_queue.writeItem(.{ .zig_libc = {} });
- }
+ if (!comp.bin_file.options.skip_linker_dependencies and is_exe_or_dyn_lib and
+ !comp.bin_file.options.link_libc and capable_of_building_zig_libc)
+ {
+ try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
@@ -2253,9 +2242,6 @@ pub fn destroy(self: *Compilation) void {
if (self.compiler_rt_obj) |*crt_file| {
crt_file.deinit(gpa);
}
- if (self.libssp_static_lib) |*crt_file| {
- crt_file.deinit(gpa);
- }
if (self.libc_static_lib) |*crt_file| {
crt_file.deinit(gpa);
}
@@ -4022,26 +4008,6 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
);
};
},
- .libssp => {
- const named_frame = tracy.namedFrame("libssp");
- defer named_frame.end();
-
- comp.buildOutputFromZig(
- "ssp.zig",
- .Lib,
- &comp.libssp_static_lib,
- .libssp,
- prog_node,
- ) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.SubCompilationFailed => return, // error reported already
- else => comp.lockAndSetMiscFailure(
- .libssp,
- "unable to build libssp: {s}",
- .{@errorName(err)},
- ),
- };
- },
.zig_libc => {
const named_frame = tracy.namedFrame("zig_libc");
defer named_frame.end();
@@ -6526,21 +6492,6 @@ fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {
};
}
-fn canBuildLibSsp(target: std.Target, use_llvm: bool) bool {
- switch (target.os.tag) {
- .plan9 => return false,
- else => {},
- }
- switch (target.cpu.arch) {
- .spirv32, .spirv64 => return false,
- else => {},
- }
- return switch (zigBackend(target, use_llvm)) {
- .stage2_llvm => true,
- else => build_options.have_llvm,
- };
-}
-
/// Not to be confused with canBuildLibC, which builds musl, glibc, and similar.
/// This one builds lib/c.zig.
fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig
index cbefcbd91e..573a85e167 100644
--- a/src/link/Coff/lld.zig
+++ b/src/link/Coff/lld.zig
@@ -483,12 +483,6 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append(lib.full_object_path);
}
}
- // MinGW doesn't provide libssp symbols
- if (target.abi.isGnu()) {
- if (comp.libssp_static_lib) |lib| {
- try argv.append(lib.full_object_path);
- }
- }
// MSVC compiler_rt is missing some stuff, so we build it unconditionally but
// and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index d210292bf9..b21a7254ff 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1040,12 +1040,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
}
- // stack-protector.
- // Related: https://github.com/ziglang/zig/issues/7265
- if (comp.libssp_static_lib) |ssp| {
- try positionals.append(.{ .path = ssp.full_object_path });
- }
-
for (positionals.items) |obj| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
@@ -1689,12 +1683,6 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
}
- // stack-protector.
- // Related: https://github.com/ziglang/zig/issues/7265
- if (comp.libssp_static_lib) |ssp| {
- try argv.append(ssp.full_object_path);
- }
-
// Shared libraries.
// Worst-case, we need an --as-needed argument for every lib, as well
// as one before and one after.
@@ -2729,12 +2717,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
}
- // stack-protector.
- // Related: https://github.com/ziglang/zig/issues/7265
- if (comp.libssp_static_lib) |ssp| {
- try argv.append(ssp.full_object_path);
- }
-
// Shared libraries.
if (is_exe_or_dyn_lib) {
const system_libs = self.base.options.system_libs.keys();
diff --git a/src/target.zig b/src/target.zig
index 7f85113040..59528ed139 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -328,8 +328,19 @@ pub fn supportsStackProbing(target: std.Target) bool {
(target.cpu.arch == .x86 or target.cpu.arch == .x86_64);
}
-pub fn supportsStackProtector(target: std.Target) bool {
- return !target.isSpirV();
+pub fn supportsStackProtector(target: std.Target, backend: std.builtin.CompilerBackend) bool {
+ switch (target.os.tag) {
+ .plan9 => return false,
+ else => {},
+ }
+ switch (target.cpu.arch) {
+ .spirv32, .spirv64 => return false,
+ else => {},
+ }
+ return switch (backend) {
+ .stage2_llvm => true,
+ else => false,
+ };
}
pub fn libcProvidesStackProtector(target: std.Target) bool {
diff --git a/stage1/config.zig.in b/stage1/config.zig.in
index 4db7babbd5..96215bb362 100644
--- a/stage1/config.zig.in
+++ b/stage1/config.zig.in
@@ -9,7 +9,6 @@ pub const enable_logging: bool = false;
pub const enable_link_snapshots: bool = false;
pub const enable_tracy = false;
pub const value_tracing = false;
-pub const have_stage1 = false;
pub const skip_non_native = false;
pub const only_c = false;
pub const force_gpa = false;