| author | |
| committer | |
| log | be2bd5848a880765f4bc7e2363ef201a0930a04b |
| tree | 868694d734e82cb93b52b6c0c155d932f5f65f8f |
| parent | 2ccaa5414b904edb2f4af293291f5401d106f277 |
| parent | fdb934a157230ae6d3f11dee8d0d62013d5b919e |
| signature |
stage2: implement stack protectors15 files changed, 193 insertions(+), 61 deletions(-)
src/Compilation.zig+76-45| ... | ... | @@ -173,6 +173,7 @@ astgen_wait_group: WaitGroup = .{}, |
| 173 | 173 | /// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information. |
| 174 | 174 | export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{}, |
| 175 | 175 | |
| 176 | pub const default_stack_protector_buffer_size = 4; | |
| 176 | 177 | pub const SemaError = Module.SemaError; |
| 177 | 178 | |
| 178 | 179 | pub const CRTFile = struct { |
| ... | ... | @@ -837,6 +838,10 @@ pub const InitOptions = struct { |
| 837 | 838 | want_pie: ?bool = null, |
| 838 | 839 | want_sanitize_c: ?bool = null, |
| 839 | 840 | want_stack_check: ?bool = null, |
| 841 | /// null means default. | |
| 842 | /// 0 means no stack protector. | |
| 843 | /// other number means stack protection with that buffer size. | |
| 844 | want_stack_protector: ?u32 = null, | |
| 840 | 845 | want_red_zone: ?bool = null, |
| 841 | 846 | omit_frame_pointer: ?bool = null, |
| 842 | 847 | want_valgrind: ?bool = null, |
| ... | ... | @@ -1014,6 +1019,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1014 | 1019 | return error.ExportTableAndImportTableConflict; |
| 1015 | 1020 | } |
| 1016 | 1021 | |
| 1022 | // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt. | |
| 1023 | // Once they are capable this condition could be removed. When removing this condition, | |
| 1024 | // also test the use case of `build-obj -fcompiler-rt` with the native backends | |
| 1025 | // and make sure the compiler-rt symbols are emitted. | |
| 1026 | const capable_of_building_compiler_rt = build_options.have_llvm; | |
| 1027 | ||
| 1028 | const capable_of_building_zig_libc = build_options.have_llvm; | |
| 1029 | const capable_of_building_ssp = build_options.have_llvm; | |
| 1030 | ||
| 1017 | 1031 | const comp: *Compilation = comp: { |
| 1018 | 1032 | // For allocations that have the same lifetime as Compilation. This arena is used only during this |
| 1019 | 1033 | // initialization and then is freed in deinit(). |
| ... | ... | @@ -1289,11 +1303,36 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1289 | 1303 | |
| 1290 | 1304 | const sanitize_c = options.want_sanitize_c orelse is_safe_mode; |
| 1291 | 1305 | |
| 1292 | const stack_check: bool = b: { | |
| 1293 | if (!target_util.supportsStackProbing(options.target)) | |
| 1294 | break :b false; | |
| 1295 | break :b options.want_stack_check orelse is_safe_mode; | |
| 1306 | const stack_check: bool = options.want_stack_check orelse b: { | |
| 1307 | if (!target_util.supportsStackProbing(options.target)) break :b false; | |
| 1308 | break :b is_safe_mode; | |
| 1296 | 1309 | }; |
| 1310 | if (stack_check and !target_util.supportsStackProbing(options.target)) | |
| 1311 | return error.StackCheckUnsupportedByTarget; | |
| 1312 | ||
| 1313 | const stack_protector: u32 = options.want_stack_protector orelse b: { | |
| 1314 | if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0); | |
| 1315 | ||
| 1316 | // This logic is checking for linking libc because otherwise our start code | |
| 1317 | // which is trying to set up TLS (i.e. the fs/gs registers) but the stack | |
| 1318 | // protection code depends on fs/gs registers being already set up. | |
| 1319 | // If we were able to annotate start code, or perhaps the entire std lib, | |
| 1320 | // as being exempt from stack protection checks, we could change this logic | |
| 1321 | // to supporting stack protection even when not linking libc. | |
| 1322 | // TODO file issue about this | |
| 1323 | if (!link_libc) break :b 0; | |
| 1324 | if (!capable_of_building_ssp) break :b 0; | |
| 1325 | if (is_safe_mode) break :b default_stack_protector_buffer_size; | |
| 1326 | break :b 0; | |
| 1327 | }; | |
| 1328 | if (stack_protector != 0) { | |
| 1329 | if (!target_util.supportsStackProtector(options.target)) | |
| 1330 | return error.StackProtectorUnsupportedByTarget; | |
| 1331 | if (!capable_of_building_ssp) | |
| 1332 | return error.StackProtectorUnsupportedByBackend; | |
| 1333 | if (!link_libc) | |
| 1334 | return error.StackProtectorUnavailableWithoutLibC; | |
| 1335 | } | |
| 1297 | 1336 | |
| 1298 | 1337 | const valgrind: bool = b: { |
| 1299 | 1338 | if (!target_util.hasValgrindSupport(options.target)) |
| ... | ... | @@ -1378,6 +1417,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1378 | 1417 | cache.hash.add(unwind_tables); |
| 1379 | 1418 | cache.hash.add(tsan); |
| 1380 | 1419 | cache.hash.add(stack_check); |
| 1420 | cache.hash.add(stack_protector); | |
| 1381 | 1421 | cache.hash.add(red_zone); |
| 1382 | 1422 | cache.hash.add(omit_frame_pointer); |
| 1383 | 1423 | cache.hash.add(link_mode); |
| ... | ... | @@ -1741,6 +1781,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1741 | 1781 | .valgrind = valgrind, |
| 1742 | 1782 | .tsan = tsan, |
| 1743 | 1783 | .stack_check = stack_check, |
| 1784 | .stack_protector = stack_protector, | |
| 1744 | 1785 | .red_zone = red_zone, |
| 1745 | 1786 | .omit_frame_pointer = omit_frame_pointer, |
| 1746 | 1787 | .single_threaded = single_threaded, |
| ... | ... | @@ -1822,6 +1863,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1822 | 1863 | }; |
| 1823 | 1864 | errdefer comp.destroy(); |
| 1824 | 1865 | |
| 1866 | const target = comp.getTarget(); | |
| 1867 | ||
| 1825 | 1868 | // Add a `CObject` for each `c_source_files`. |
| 1826 | 1869 | try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len); |
| 1827 | 1870 | for (options.c_source_files) |c_source_file| { |
| ... | ... | @@ -1837,11 +1880,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1837 | 1880 | |
| 1838 | 1881 | const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; |
| 1839 | 1882 | |
| 1840 | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and | |
| 1841 | options.target.ofmt != .c) | |
| 1842 | { | |
| 1843 | if (comp.getTarget().isDarwin()) { | |
| 1844 | switch (comp.getTarget().abi) { | |
| 1883 | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) { | |
| 1884 | if (target.isDarwin()) { | |
| 1885 | switch (target.abi) { | |
| 1845 | 1886 | .none, |
| 1846 | 1887 | .simulator, |
| 1847 | 1888 | .macabi, |
| ... | ... | @@ -1852,9 +1893,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1852 | 1893 | // If we need to build glibc for the target, add work items for it. |
| 1853 | 1894 | // We go through the work queue so that building can be done in parallel. |
| 1854 | 1895 | if (comp.wantBuildGLibCFromSource()) { |
| 1855 | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; | |
| 1896 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; | |
| 1856 | 1897 | |
| 1857 | if (glibc.needsCrtiCrtn(comp.getTarget())) { | |
| 1898 | if (glibc.needsCrtiCrtn(target)) { | |
| 1858 | 1899 | try comp.work_queue.write(&[_]Job{ |
| 1859 | 1900 | .{ .glibc_crt_file = .crti_o }, |
| 1860 | 1901 | .{ .glibc_crt_file = .crtn_o }, |
| ... | ... | @@ -1867,10 +1908,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1867 | 1908 | }); |
| 1868 | 1909 | } |
| 1869 | 1910 | if (comp.wantBuildMuslFromSource()) { |
| 1870 | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; | |
| 1911 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; | |
| 1871 | 1912 | |
| 1872 | 1913 | try comp.work_queue.ensureUnusedCapacity(6); |
| 1873 | if (musl.needsCrtiCrtn(comp.getTarget())) { | |
| 1914 | if (musl.needsCrtiCrtn(target)) { | |
| 1874 | 1915 | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1875 | 1916 | .{ .musl_crt_file = .crti_o }, |
| 1876 | 1917 | .{ .musl_crt_file = .crtn_o }, |
| ... | ... | @@ -1887,7 +1928,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1887 | 1928 | }); |
| 1888 | 1929 | } |
| 1889 | 1930 | if (comp.wantBuildWasiLibcFromSource()) { |
| 1890 | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; | |
| 1931 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; | |
| 1891 | 1932 | |
| 1892 | 1933 | const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; |
| 1893 | 1934 | try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components |
| ... | ... | @@ -1902,7 +1943,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1902 | 1943 | }); |
| 1903 | 1944 | } |
| 1904 | 1945 | if (comp.wantBuildMinGWFromSource()) { |
| 1905 | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; | |
| 1946 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; | |
| 1906 | 1947 | |
| 1907 | 1948 | const static_lib_jobs = [_]Job{ |
| 1908 | 1949 | .{ .mingw_crt_file = .mingw32_lib }, |
| ... | ... | @@ -1921,7 +1962,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1921 | 1962 | } |
| 1922 | 1963 | } |
| 1923 | 1964 | // Generate Windows import libs. |
| 1924 | if (comp.getTarget().os.tag == .windows) { | |
| 1965 | if (target.os.tag == .windows) { | |
| 1925 | 1966 | const count = comp.bin_file.options.system_libs.count(); |
| 1926 | 1967 | try comp.work_queue.ensureUnusedCapacity(count); |
| 1927 | 1968 | var i: usize = 0; |
| ... | ... | @@ -1940,15 +1981,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1940 | 1981 | try comp.work_queue.writeItem(.libtsan); |
| 1941 | 1982 | } |
| 1942 | 1983 | |
| 1943 | // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt. | |
| 1944 | // Once they are capable this condition could be removed. When removing this condition, | |
| 1945 | // also test the use case of `build-obj -fcompiler-rt` with the native backends | |
| 1946 | // and make sure the compiler-rt symbols are emitted. | |
| 1947 | const capable_of_building_compiler_rt = build_options.have_llvm; | |
| 1948 | ||
| 1949 | const capable_of_building_zig_libc = build_options.have_llvm; | |
| 1950 | const capable_of_building_ssp = comp.bin_file.options.use_stage1; | |
| 1951 | ||
| 1952 | 1984 | if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { |
| 1953 | 1985 | if (is_exe_or_dyn_lib) { |
| 1954 | 1986 | log.debug("queuing a job to build compiler_rt_lib", .{}); |
| ... | ... | @@ -1962,8 +1994,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1962 | 1994 | } |
| 1963 | 1995 | } |
| 1964 | 1996 | if (needs_c_symbols) { |
| 1965 | // MinGW provides no libssp, use our own implementation. | |
| 1966 | if (comp.getTarget().isMinGW() and capable_of_building_ssp) { | |
| 1997 | // Related: https://github.com/ziglang/zig/issues/7265. | |
| 1998 | if (comp.bin_file.options.stack_protector != 0 and | |
| 1999 | (!comp.bin_file.options.link_libc or | |
| 2000 | !target_util.libcProvidesStackProtector(target))) | |
| 2001 | { | |
| 1967 | 2002 | try comp.work_queue.writeItem(.{ .libssp = {} }); |
| 1968 | 2003 | } |
| 1969 | 2004 | |
| ... | ... | @@ -4123,6 +4158,17 @@ pub fn addCCArgs( |
| 4123 | 4158 | try argv.append("-fno-omit-frame-pointer"); |
| 4124 | 4159 | } |
| 4125 | 4160 | |
| 4161 | const ssp_buf_size = comp.bin_file.options.stack_protector; | |
| 4162 | if (ssp_buf_size != 0) { | |
| 4163 | try argv.appendSlice(&[_][]const u8{ | |
| 4164 | "-fstack-protector-strong", | |
| 4165 | "--param", | |
| 4166 | try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}), | |
| 4167 | }); | |
| 4168 | } else { | |
| 4169 | try argv.append("-fno-stack-protector"); | |
| 4170 | } | |
| 4171 | ||
| 4126 | 4172 | switch (comp.bin_file.options.optimize_mode) { |
| 4127 | 4173 | .Debug => { |
| 4128 | 4174 | // windows c runtime requires -D_DEBUG if using debug libraries |
| ... | ... | @@ -4131,27 +4177,12 @@ pub fn addCCArgs( |
| 4131 | 4177 | // to -O1. Besides potentially impairing debugging, -O1/-Og significantly |
| 4132 | 4178 | // increases compile times. |
| 4133 | 4179 | try argv.append("-O0"); |
| 4134 | ||
| 4135 | if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { | |
| 4136 | try argv.append("-fstack-protector-strong"); | |
| 4137 | try argv.append("--param"); | |
| 4138 | try argv.append("ssp-buffer-size=4"); | |
| 4139 | } else { | |
| 4140 | try argv.append("-fno-stack-protector"); | |
| 4141 | } | |
| 4142 | 4180 | }, |
| 4143 | 4181 | .ReleaseSafe => { |
| 4144 | 4182 | // See the comment in the BuildModeFastRelease case for why we pass -O2 rather |
| 4145 | 4183 | // than -O3 here. |
| 4146 | 4184 | try argv.append("-O2"); |
| 4147 | if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { | |
| 4148 | try argv.append("-D_FORTIFY_SOURCE=2"); | |
| 4149 | try argv.append("-fstack-protector-strong"); | |
| 4150 | try argv.append("--param"); | |
| 4151 | try argv.append("ssp-buffer-size=4"); | |
| 4152 | } else { | |
| 4153 | try argv.append("-fno-stack-protector"); | |
| 4154 | } | |
| 4185 | try argv.append("-D_FORTIFY_SOURCE=2"); | |
| 4155 | 4186 | }, |
| 4156 | 4187 | .ReleaseFast => { |
| 4157 | 4188 | try argv.append("-DNDEBUG"); |
| ... | ... | @@ -4161,12 +4192,10 @@ pub fn addCCArgs( |
| 4161 | 4192 | // Zig code than it is for C code. Also, C programmers are used to their code |
| 4162 | 4193 | // running in -O2 and thus the -O3 path has been tested less. |
| 4163 | 4194 | try argv.append("-O2"); |
| 4164 | try argv.append("-fno-stack-protector"); | |
| 4165 | 4195 | }, |
| 4166 | 4196 | .ReleaseSmall => { |
| 4167 | 4197 | try argv.append("-DNDEBUG"); |
| 4168 | 4198 | try argv.append("-Os"); |
| 4169 | try argv.append("-fno-stack-protector"); | |
| 4170 | 4199 | }, |
| 4171 | 4200 | } |
| 4172 | 4201 | |
| ... | ... | @@ -5031,6 +5060,7 @@ fn buildOutputFromZig( |
| 5031 | 5060 | .use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1, |
| 5032 | 5061 | .want_sanitize_c = false, |
| 5033 | 5062 | .want_stack_check = false, |
| 5063 | .want_stack_protector = 0, | |
| 5034 | 5064 | .want_red_zone = comp.bin_file.options.red_zone, |
| 5035 | 5065 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 5036 | 5066 | .want_valgrind = false, |
| ... | ... | @@ -5311,6 +5341,7 @@ pub fn build_crt_file( |
| 5311 | 5341 | .optimize_mode = comp.compilerRtOptMode(), |
| 5312 | 5342 | .want_sanitize_c = false, |
| 5313 | 5343 | .want_stack_check = false, |
| 5344 | .want_stack_protector = 0, | |
| 5314 | 5345 | .want_red_zone = comp.bin_file.options.red_zone, |
| 5315 | 5346 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 5316 | 5347 | .want_valgrind = false, |
src/Sema.zig+8-7| ... | ... | @@ -7567,10 +7567,11 @@ fn handleExternLibName( |
| 7567 | 7567 | ) CompileError![:0]u8 { |
| 7568 | 7568 | blk: { |
| 7569 | 7569 | const mod = sema.mod; |
| 7570 | const comp = mod.comp; | |
| 7570 | 7571 | const target = mod.getTarget(); |
| 7571 | 7572 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); |
| 7572 | 7573 | if (target_util.is_libc_lib_name(target, lib_name)) { |
| 7573 | if (!mod.comp.bin_file.options.link_libc) { | |
| 7574 | if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { | |
| 7574 | 7575 | return sema.fail( |
| 7575 | 7576 | block, |
| 7576 | 7577 | src_loc, |
| ... | ... | @@ -7578,11 +7579,11 @@ fn handleExternLibName( |
| 7578 | 7579 | .{}, |
| 7579 | 7580 | ); |
| 7580 | 7581 | } |
| 7581 | mod.comp.bin_file.options.link_libc = true; | |
| 7582 | comp.bin_file.options.link_libc = true; | |
| 7582 | 7583 | break :blk; |
| 7583 | 7584 | } |
| 7584 | 7585 | if (target_util.is_libcpp_lib_name(target, lib_name)) { |
| 7585 | if (!mod.comp.bin_file.options.link_libcpp) { | |
| 7586 | if (!comp.bin_file.options.link_libcpp) { | |
| 7586 | 7587 | return sema.fail( |
| 7587 | 7588 | block, |
| 7588 | 7589 | src_loc, |
| ... | ... | @@ -7590,14 +7591,14 @@ fn handleExternLibName( |
| 7590 | 7591 | .{}, |
| 7591 | 7592 | ); |
| 7592 | 7593 | } |
| 7593 | mod.comp.bin_file.options.link_libcpp = true; | |
| 7594 | comp.bin_file.options.link_libcpp = true; | |
| 7594 | 7595 | break :blk; |
| 7595 | 7596 | } |
| 7596 | 7597 | if (mem.eql(u8, lib_name, "unwind")) { |
| 7597 | mod.comp.bin_file.options.link_libunwind = true; | |
| 7598 | comp.bin_file.options.link_libunwind = true; | |
| 7598 | 7599 | break :blk; |
| 7599 | 7600 | } |
| 7600 | if (!target.isWasm() and !mod.comp.bin_file.options.pic) { | |
| 7601 | if (!target.isWasm() and !comp.bin_file.options.pic) { | |
| 7601 | 7602 | return sema.fail( |
| 7602 | 7603 | block, |
| 7603 | 7604 | src_loc, |
| ... | ... | @@ -7605,7 +7606,7 @@ fn handleExternLibName( |
| 7605 | 7606 | .{ lib_name, lib_name }, |
| 7606 | 7607 | ); |
| 7607 | 7608 | } |
| 7608 | mod.comp.stage1AddLinkLib(lib_name) catch |err| { | |
| 7609 | comp.stage1AddLinkLib(lib_name) catch |err| { | |
| 7609 | 7610 | return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{ |
| 7610 | 7611 | lib_name, @errorName(err), |
| 7611 | 7612 | }); |
src/clang_options_data.zig+40-5| ... | ... | @@ -3290,7 +3290,14 @@ flagpd1("fno-stack-arrays"), |
| 3290 | 3290 | .psl = false, |
| 3291 | 3291 | }, |
| 3292 | 3292 | flagpd1("fno-stack-clash-protection"), |
| 3293 | flagpd1("fno-stack-protector"), | |
| 3293 | .{ | |
| 3294 | .name = "fno-stack-protector", | |
| 3295 | .syntax = .flag, | |
| 3296 | .zig_equivalent = .no_stack_protector, | |
| 3297 | .pd1 = true, | |
| 3298 | .pd2 = false, | |
| 3299 | .psl = false, | |
| 3300 | }, | |
| 3294 | 3301 | flagpd1("fno-stack-size-section"), |
| 3295 | 3302 | flagpd1("fno-standalone-debug"), |
| 3296 | 3303 | flagpd1("fno-strength-reduce"), |
| ... | ... | @@ -3588,9 +3595,30 @@ flagpd1("fstack-arrays"), |
| 3588 | 3595 | .psl = false, |
| 3589 | 3596 | }, |
| 3590 | 3597 | flagpd1("fstack-clash-protection"), |
| 3591 | flagpd1("fstack-protector"), | |
| 3592 | flagpd1("fstack-protector-all"), | |
| 3593 | flagpd1("fstack-protector-strong"), | |
| 3598 | .{ | |
| 3599 | .name = "fstack-protector", | |
| 3600 | .syntax = .flag, | |
| 3601 | .zig_equivalent = .stack_protector, | |
| 3602 | .pd1 = true, | |
| 3603 | .pd2 = false, | |
| 3604 | .psl = false, | |
| 3605 | }, | |
| 3606 | .{ | |
| 3607 | .name = "fstack-protector-all", | |
| 3608 | .syntax = .flag, | |
| 3609 | .zig_equivalent = .stack_protector, | |
| 3610 | .pd1 = true, | |
| 3611 | .pd2 = false, | |
| 3612 | .psl = false, | |
| 3613 | }, | |
| 3614 | .{ | |
| 3615 | .name = "fstack-protector-strong", | |
| 3616 | .syntax = .flag, | |
| 3617 | .zig_equivalent = .stack_protector, | |
| 3618 | .pd1 = true, | |
| 3619 | .pd2 = false, | |
| 3620 | .psl = false, | |
| 3621 | }, | |
| 3594 | 3622 | flagpd1("fstack-size-section"), |
| 3595 | 3623 | flagpd1("fstack-usage"), |
| 3596 | 3624 | flagpd1("fstandalone-debug"), |
| ... | ... | @@ -4809,7 +4837,14 @@ flagpd1("single_module"), |
| 4809 | 4837 | }, |
| 4810 | 4838 | sepd1("split-dwarf-file"), |
| 4811 | 4839 | sepd1("split-dwarf-output"), |
| 4812 | sepd1("stack-protector"), | |
| 4840 | .{ | |
| 4841 | .name = "stack-protector", | |
| 4842 | .syntax = .separate, | |
| 4843 | .zig_equivalent = .stack_protector, | |
| 4844 | .pd1 = true, | |
| 4845 | .pd2 = false, | |
| 4846 | .psl = false, | |
| 4847 | }, | |
| 4813 | 4848 | sepd1("stack-protector-buffer-size"), |
| 4814 | 4849 | sepd1("stack-usage-file"), |
| 4815 | 4850 | .{ |
src/codegen/llvm.zig+8-3| ... | ... | @@ -711,9 +711,14 @@ pub const Object = struct { |
| 711 | 711 | DeclGen.removeFnAttr(llvm_func, "noinline"); |
| 712 | 712 | } |
| 713 | 713 | |
| 714 | // TODO: port these over from stage1 | |
| 715 | // addLLVMFnAttr(llvm_fn, "sspstrong"); | |
| 716 | // addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4"); | |
| 714 | // TODO: disable this if safety is off for the function scope | |
| 715 | const ssp_buf_size = module.comp.bin_file.options.stack_protector; | |
| 716 | if (ssp_buf_size != 0) { | |
| 717 | var buf: [12]u8 = undefined; | |
| 718 | const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable; | |
| 719 | dg.addFnAttr(llvm_func, "sspstrong"); | |
| 720 | dg.addFnAttrString(llvm_func, "stack-protector-buffer-size", arg); | |
| 721 | } | |
| 717 | 722 | |
| 718 | 723 | // TODO: disable this if safety is off for the function scope |
| 719 | 724 | if (module.comp.bin_file.options.stack_check) { |
src/glibc.zig+1| ... | ... | @@ -1111,6 +1111,7 @@ fn buildSharedLib( |
| 1111 | 1111 | .optimize_mode = comp.compilerRtOptMode(), |
| 1112 | 1112 | .want_sanitize_c = false, |
| 1113 | 1113 | .want_stack_check = false, |
| 1114 | .want_stack_protector = 0, | |
| 1114 | 1115 | .want_red_zone = comp.bin_file.options.red_zone, |
| 1115 | 1116 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 1116 | 1117 | .want_valgrind = false, |
src/libcxx.zig+2| ... | ... | @@ -206,6 +206,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { |
| 206 | 206 | .link_mode = link_mode, |
| 207 | 207 | .want_sanitize_c = false, |
| 208 | 208 | .want_stack_check = false, |
| 209 | .want_stack_protector = 0, | |
| 209 | 210 | .want_red_zone = comp.bin_file.options.red_zone, |
| 210 | 211 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 211 | 212 | .want_valgrind = false, |
| ... | ... | @@ -349,6 +350,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { |
| 349 | 350 | .link_mode = link_mode, |
| 350 | 351 | .want_sanitize_c = false, |
| 351 | 352 | .want_stack_check = false, |
| 353 | .want_stack_protector = 0, | |
| 352 | 354 | .want_red_zone = comp.bin_file.options.red_zone, |
| 353 | 355 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 354 | 356 | .want_valgrind = false, |
src/libtsan.zig+1| ... | ... | @@ -211,6 +211,7 @@ pub fn buildTsan(comp: *Compilation) !void { |
| 211 | 211 | .link_mode = link_mode, |
| 212 | 212 | .want_sanitize_c = false, |
| 213 | 213 | .want_stack_check = false, |
| 214 | .want_stack_protector = 0, | |
| 214 | 215 | .want_valgrind = false, |
| 215 | 216 | .want_tsan = false, |
| 216 | 217 | .want_pic = true, |
src/libunwind.zig+1| ... | ... | @@ -113,6 +113,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { |
| 113 | 113 | .link_mode = link_mode, |
| 114 | 114 | .want_sanitize_c = false, |
| 115 | 115 | .want_stack_check = false, |
| 116 | .want_stack_protector = 0, | |
| 116 | 117 | .want_red_zone = comp.bin_file.options.red_zone, |
| 117 | 118 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 118 | 119 | .want_valgrind = false, |
src/link.zig+3| ... | ... | @@ -90,6 +90,9 @@ pub const Options = struct { |
| 90 | 90 | entry: ?[]const u8, |
| 91 | 91 | stack_size_override: ?u64, |
| 92 | 92 | image_base_override: ?u64, |
| 93 | /// 0 means no stack protector | |
| 94 | /// other value means stack protector with that buffer size. | |
| 95 | stack_protector: u32, | |
| 93 | 96 | cache_mode: CacheMode, |
| 94 | 97 | include_compiler_rt: bool, |
| 95 | 98 | /// Set to `true` to omit debug info. |
src/link/Elf.zig+6| ... | ... | @@ -1673,6 +1673,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1673 | 1673 | } |
| 1674 | 1674 | } |
| 1675 | 1675 | |
| 1676 | // stack-protector. | |
| 1677 | // Related: https://github.com/ziglang/zig/issues/7265 | |
| 1678 | if (comp.libssp_static_lib) |ssp| { | |
| 1679 | try argv.append(ssp.full_object_path); | |
| 1680 | } | |
| 1681 | ||
| 1676 | 1682 | // compiler-rt |
| 1677 | 1683 | if (compiler_rt_path) |p| { |
| 1678 | 1684 | try argv.append(p); |
src/main.zig+16| ... | ... | @@ -378,6 +378,8 @@ const usage_build_generic = |
| 378 | 378 | \\ -fno-lto Force-disable Link Time Optimization |
| 379 | 379 | \\ -fstack-check Enable stack probing in unsafe builds |
| 380 | 380 | \\ -fno-stack-check Disable stack probing in safe builds |
| 381 | \\ -fstack-protector Enable stack protection in unsafe builds | |
| 382 | \\ -fno-stack-protector Disable stack protection in safe builds | |
| 381 | 383 | \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds |
| 382 | 384 | \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds |
| 383 | 385 | \\ -fvalgrind Include valgrind client requests in release builds |
| ... | ... | @@ -668,6 +670,7 @@ fn buildOutputType( |
| 668 | 670 | var want_unwind_tables: ?bool = null; |
| 669 | 671 | var want_sanitize_c: ?bool = null; |
| 670 | 672 | var want_stack_check: ?bool = null; |
| 673 | var want_stack_protector: ?u32 = null; | |
| 671 | 674 | var want_red_zone: ?bool = null; |
| 672 | 675 | var omit_frame_pointer: ?bool = null; |
| 673 | 676 | var want_valgrind: ?bool = null; |
| ... | ... | @@ -1168,6 +1171,10 @@ fn buildOutputType( |
| 1168 | 1171 | want_stack_check = true; |
| 1169 | 1172 | } else if (mem.eql(u8, arg, "-fno-stack-check")) { |
| 1170 | 1173 | want_stack_check = false; |
| 1174 | } else if (mem.eql(u8, arg, "-fstack-protector")) { | |
| 1175 | want_stack_protector = Compilation.default_stack_protector_buffer_size; | |
| 1176 | } else if (mem.eql(u8, arg, "-fno-stack-protector")) { | |
| 1177 | want_stack_protector = 0; | |
| 1171 | 1178 | } else if (mem.eql(u8, arg, "-mred-zone")) { |
| 1172 | 1179 | want_red_zone = true; |
| 1173 | 1180 | } else if (mem.eql(u8, arg, "-mno-red-zone")) { |
| ... | ... | @@ -1521,6 +1528,12 @@ fn buildOutputType( |
| 1521 | 1528 | .no_color_diagnostics => color = .off, |
| 1522 | 1529 | .stack_check => want_stack_check = true, |
| 1523 | 1530 | .no_stack_check => want_stack_check = false, |
| 1531 | .stack_protector => { | |
| 1532 | if (want_stack_protector == null) { | |
| 1533 | want_stack_protector = Compilation.default_stack_protector_buffer_size; | |
| 1534 | } | |
| 1535 | }, | |
| 1536 | .no_stack_protector => want_stack_protector = 0, | |
| 1524 | 1537 | .unwind_tables => want_unwind_tables = true, |
| 1525 | 1538 | .no_unwind_tables => want_unwind_tables = false, |
| 1526 | 1539 | .nostdlib => ensure_libc_on_non_freestanding = false, |
| ... | ... | @@ -2859,6 +2872,7 @@ fn buildOutputType( |
| 2859 | 2872 | .want_unwind_tables = want_unwind_tables, |
| 2860 | 2873 | .want_sanitize_c = want_sanitize_c, |
| 2861 | 2874 | .want_stack_check = want_stack_check, |
| 2875 | .want_stack_protector = want_stack_protector, | |
| 2862 | 2876 | .want_red_zone = want_red_zone, |
| 2863 | 2877 | .omit_frame_pointer = omit_frame_pointer, |
| 2864 | 2878 | .want_valgrind = want_valgrind, |
| ... | ... | @@ -4663,6 +4677,8 @@ pub const ClangArgIterator = struct { |
| 4663 | 4677 | no_color_diagnostics, |
| 4664 | 4678 | stack_check, |
| 4665 | 4679 | no_stack_check, |
| 4680 | stack_protector, | |
| 4681 | no_stack_protector, | |
| 4666 | 4682 | strip, |
| 4667 | 4683 | exec_model, |
| 4668 | 4684 | emit_llvm, |
src/musl.zig+1| ... | ... | @@ -215,6 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { |
| 215 | 215 | .optimize_mode = comp.compilerRtOptMode(), |
| 216 | 216 | .want_sanitize_c = false, |
| 217 | 217 | .want_stack_check = false, |
| 218 | .want_stack_protector = 0, | |
| 218 | 219 | .want_red_zone = comp.bin_file.options.red_zone, |
| 219 | 220 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 220 | 221 | .want_valgrind = false, |
src/stage1.zig+1-1| ... | ... | @@ -416,7 +416,7 @@ export fn stage2_add_link_lib( |
| 416 | 416 | const target = comp.getTarget(); |
| 417 | 417 | const is_libc = target_util.is_libc_lib_name(target, lib_name); |
| 418 | 418 | if (is_libc) { |
| 419 | if (!comp.bin_file.options.link_libc) { | |
| 419 | if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { | |
| 420 | 420 | return "dependency on libc must be explicitly specified in the build command"; |
| 421 | 421 | } |
| 422 | 422 | return null; |
src/target.zig+9| ... | ... | @@ -300,6 +300,15 @@ pub fn supportsStackProbing(target: std.Target) bool { |
| 300 | 300 | (target.cpu.arch == .i386 or target.cpu.arch == .x86_64); |
| 301 | 301 | } |
| 302 | 302 | |
| 303 | pub fn supportsStackProtector(target: std.Target) bool { | |
| 304 | // TODO: investigate whether stack-protector works on wasm | |
| 305 | return !target.isWasm(); | |
| 306 | } | |
| 307 | ||
| 308 | pub fn libcProvidesStackProtector(target: std.Target) bool { | |
| 309 | return !target.isMinGW() and target.os.tag != .wasi; | |
| 310 | } | |
| 311 | ||
| 303 | 312 | pub fn supportsReturnAddress(target: std.Target) bool { |
| 304 | 313 | return switch (target.cpu.arch) { |
| 305 | 314 | .wasm32, .wasm64 => target.os.tag == .emscripten, |
tools/update_clang_options.zig+20| ... | ... | @@ -352,6 +352,26 @@ const known_options = [_]KnownOpt{ |
| 352 | 352 | .name = "fno-stack-check", |
| 353 | 353 | .ident = "no_stack_check", |
| 354 | 354 | }, |
| 355 | .{ | |
| 356 | .name = "stack-protector", | |
| 357 | .ident = "stack_protector", | |
| 358 | }, | |
| 359 | .{ | |
| 360 | .name = "fstack-protector", | |
| 361 | .ident = "stack_protector", | |
| 362 | }, | |
| 363 | .{ | |
| 364 | .name = "fno-stack-protector", | |
| 365 | .ident = "no_stack_protector", | |
| 366 | }, | |
| 367 | .{ | |
| 368 | .name = "fstack-protector-strong", | |
| 369 | .ident = "stack_protector", | |
| 370 | }, | |
| 371 | .{ | |
| 372 | .name = "fstack-protector-all", | |
| 373 | .ident = "stack_protector", | |
| 374 | }, | |
| 355 | 375 | .{ |
| 356 | 376 | .name = "MD", |
| 357 | 377 | .ident = "dep_file", |