zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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 }