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 15const std = @import("std"); 16 17extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8; 18extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8; 19extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; 20extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; 21 22// Avoid dragging in the runtime safety mechanisms into this .o file. 23pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { 24 _ = msg; 25 _ = error_return_trace; 26 @setCold(true); 27 std.os.abort(); 28} 29 30export fn __stack_chk_fail() callconv(.C) noreturn { 31 @panic("stack smashing detected"); 32} 33 34export fn __chk_fail() callconv(.C) noreturn { 35 @panic("buffer overflow detected"); 36} 37 38// Emitted when targeting some architectures (eg. i386) 39// XXX: This symbol should be hidden 40export fn __stack_chk_fail_local() callconv(.C) noreturn { 41 __stack_chk_fail(); 42} 43 44// XXX: Initialize the canary with random data 45export 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 @bitCast(usize, buf); 50}; 51 52export 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 67export fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { 68 if (dest_n < n) __chk_fail(); 69 return strncpy(dest, src, n); 70} 71 72export fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 { 73 @setRuntimeSafety(false); 74 75 var avail = dest_n; 76 77 var dest_end: usize = 0; 78 while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { 79 avail -= 1; 80 } 81 82 if (avail < 1) __chk_fail(); 83 84 var i: usize = 0; 85 while (avail > 0 and src[i] != 0) : (i += 1) { 86 dest[dest_end + i] = src[i]; 87 avail -= 1; 88 } 89 90 if (avail < 1) __chk_fail(); 91 92 dest[dest_end + i] = 0; 93 94 return dest; 95} 96 97export fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { 98 @setRuntimeSafety(false); 99 100 var avail = dest_n; 101 102 var dest_end: usize = 0; 103 while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { 104 avail -= 1; 105 } 106 107 if (avail < 1) __chk_fail(); 108 109 var i: usize = 0; 110 while (avail > 0 and i < n and src[i] != 0) : (i += 1) { 111 dest[dest_end + i] = src[i]; 112 avail -= 1; 113 } 114 115 if (avail < 1) __chk_fail(); 116 117 dest[dest_end + i] = 0; 118 119 return dest; 120} 121 122export fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { 123 if (dest_n < n) __chk_fail(); 124 return memcpy(dest, src, n); 125} 126 127export fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { 128 if (dest_n < n) __chk_fail(); 129 return memmove(dest, src, n); 130} 131 132export fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { 133 if (dest_n < n) __chk_fail(); 134 return memset(dest, c, n); 135} 136