master
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");
16const common = @import("./common.zig");
17const builtin = @import("builtin");
18
19extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.c) ?[*]u8;
20extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8;
21extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8;
22
23comptime {
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
36fn __stack_chk_fail() callconv(.c) noreturn {
37 @panic("stack smashing detected");
38}
39
40fn __chk_fail() callconv(.c) noreturn {
41 @panic("buffer overflow detected");
42}
43
44// TODO: Initialize the canary with random data
45var __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
52fn __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
67fn __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
80fn __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
105fn __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
130fn __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
135fn __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
140fn __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}