ssp.zig (4524B) - Raw
1 //! 2 //! Small Zig reimplementation of gcc's libssp. 3 //! 4 //! This library implements most of the builtins required by the stack smashing 5 //! protection as implemented by gcc&clang. 6 //! Missing exports: 7 //! - __gets_chk 8 //! - __mempcpy_chk 9 //! - __snprintf_chk 10 //! - __sprintf_chk 11 //! - __stpcpy_chk 12 //! - __vsnprintf_chk 13 //! - __vsprintf_chk 14 15 const std = @import("std"); 16 const common = @import("./common.zig"); 17 const builtin = @import("builtin"); 18 19 extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.c) ?[*]u8; 20 extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; 21 extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; 22 23 comptime { 24 @export(&__stack_chk_fail, .{ .name = "__stack_chk_fail", .linkage = common.linkage, .visibility = common.visibility }); 25 @export(&__chk_fail, .{ .name = "__chk_fail", .linkage = common.linkage, .visibility = common.visibility }); 26 @export(&__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = common.linkage, .visibility = common.visibility }); 27 @export(&__strcpy_chk, .{ .name = "__strcpy_chk", .linkage = common.linkage, .visibility = common.visibility }); 28 @export(&__strncpy_chk, .{ .name = "__strncpy_chk", .linkage = common.linkage, .visibility = common.visibility }); 29 @export(&__strcat_chk, .{ .name = "__strcat_chk", .linkage = common.linkage, .visibility = common.visibility }); 30 @export(&__strncat_chk, .{ .name = "__strncat_chk", .linkage = common.linkage, .visibility = common.visibility }); 31 @export(&__memcpy_chk, .{ .name = "__memcpy_chk", .linkage = common.linkage, .visibility = common.visibility }); 32 @export(&__memmove_chk, .{ .name = "__memmove_chk", .linkage = common.linkage, .visibility = common.visibility }); 33 @export(&__memset_chk, .{ .name = "__memset_chk", .linkage = common.linkage, .visibility = common.visibility }); 34 } 35 36 fn __stack_chk_fail() callconv(.c) noreturn { 37 @panic("stack smashing detected"); 38 } 39 40 fn __chk_fail() callconv(.c) noreturn { 41 @panic("buffer overflow detected"); 42 } 43 44 // TODO: Initialize the canary with random data 45 var __stack_chk_guard: usize = blk: { 46 var buf = [1]u8{0} ** @sizeOf(usize); 47 buf[@sizeOf(usize) - 1] = 255; 48 buf[@sizeOf(usize) - 2] = '\n'; 49 break :blk @as(usize, @bitCast(buf)); 50 }; 51 52 fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.c) [*:0]u8 { 53 @setRuntimeSafety(false); 54 55 var i: usize = 0; 56 while (i < dest_n and src[i] != 0) : (i += 1) { 57 dest[i] = src[i]; 58 } 59 60 if (i == dest_n) __chk_fail(); 61 62 dest[i] = 0; 63 64 return dest; 65 } 66 67 fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.c) [*:0]u8 { 68 @setRuntimeSafety(false); 69 if (dest_n < n) __chk_fail(); 70 var i: usize = 0; 71 while (i < n and src[i] != 0) : (i += 1) { 72 dest[i] = src[i]; 73 } 74 while (i < n) : (i += 1) { 75 dest[i] = 0; 76 } 77 return dest; 78 } 79 80 fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.c) [*:0]u8 { 81 @setRuntimeSafety(false); 82 83 var avail = dest_n; 84 85 var dest_end: usize = 0; 86 while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { 87 avail -= 1; 88 } 89 90 if (avail < 1) __chk_fail(); 91 92 var i: usize = 0; 93 while (avail > 0 and src[i] != 0) : (i += 1) { 94 dest[dest_end + i] = src[i]; 95 avail -= 1; 96 } 97 98 if (avail < 1) __chk_fail(); 99 100 dest[dest_end + i] = 0; 101 102 return dest; 103 } 104 105 fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.c) [*:0]u8 { 106 @setRuntimeSafety(false); 107 108 var avail = dest_n; 109 110 var dest_end: usize = 0; 111 while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { 112 avail -= 1; 113 } 114 115 if (avail < 1) __chk_fail(); 116 117 var i: usize = 0; 118 while (avail > 0 and i < n and src[i] != 0) : (i += 1) { 119 dest[dest_end + i] = src[i]; 120 avail -= 1; 121 } 122 123 if (avail < 1) __chk_fail(); 124 125 dest[dest_end + i] = 0; 126 127 return dest; 128 } 129 130 fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { 131 if (dest_n < n) __chk_fail(); 132 return memcpy(dest, src, n); 133 } 134 135 fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { 136 if (dest_n < n) __chk_fail(); 137 return memmove(dest, src, n); 138 } 139 140 fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { 141 if (dest_n < n) __chk_fail(); 142 return memset(dest, c, n); 143 }