1 /* $OpenBSD: explicit_bzero.c,v 1.6 2014/07/11 01:10:35 matthew Exp $ */ 2 /* 3 * Copyright (c) 2014 Google Inc. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <assert.h> 19 #include <errno.h> 20 #include <signal.h> 21 #include <string.h> 22 #include <unistd.h> 23 24 #define ASSERT_EQ(a, b) assert((a) == (b)) 25 #define ASSERT_NE(a, b) assert((a) != (b)) 26 #define ASSERT_GE(a, b) assert((a) >= (b)) 27 28 /* 128 bits of random data. */ 29 static const char secret[16] = { 30 0xa0, 0x6c, 0x0c, 0x81, 0xba, 0xd8, 0x5b, 0x0c, 31 0xb0, 0xd6, 0xd4, 0xe3, 0xeb, 0x52, 0x5f, 0x96, 32 }; 33 34 enum { 35 SECRETCOUNT = 64, 36 SECRETBYTES = SECRETCOUNT * sizeof(secret) 37 }; 38 39 static char altstack[SIGSTKSZ + SECRETBYTES]; 40 41 static void 42 setup_stack(void) 43 { 44 const stack_t sigstk = { 45 .ss_sp = altstack, 46 .ss_size = sizeof(altstack), 47 }; 48 49 ASSERT_EQ(0, sigaltstack(&sigstk, NULL)); 50 } 51 52 static void 53 assert_on_stack(void) 54 { 55 stack_t cursigstk; 56 ASSERT_EQ(0, sigaltstack(NULL, &cursigstk)); 57 ASSERT_EQ(SS_ONSTACK, cursigstk.ss_flags & (SS_DISABLE|SS_ONSTACK)); 58 } 59 60 static void 61 call_on_stack(void (*fn)(int)) 62 { 63 /* 64 * This is a bit more complicated than strictly necessary, but 65 * it ensures we don't have any flaky test failures due to 66 * inherited signal masks/actions/etc. 67 * 68 * On systems where SA_ONSTACK is not supported, this could 69 * alternatively be implemented using makecontext() or 70 * pthread_attr_setstack(). 71 */ 72 73 const struct sigaction sigact = { 74 .sa_handler = fn, 75 .sa_flags = SA_ONSTACK, 76 }; 77 struct sigaction oldsigact; 78 sigset_t sigset, oldsigset; 79 80 /* First, block all signals. */ 81 ASSERT_EQ(0, sigemptyset(&sigset)); 82 ASSERT_EQ(0, sigfillset(&sigset)); 83 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset, &oldsigset)); 84 85 /* Next setup the signal handler for SIGUSR1. */ 86 ASSERT_EQ(0, sigaction(SIGUSR1, &sigact, &oldsigact)); 87 88 /* Raise SIGUSR1 and momentarily unblock it to run the handler. */ 89 ASSERT_EQ(0, raise(SIGUSR1)); 90 ASSERT_EQ(0, sigdelset(&sigset, SIGUSR1)); 91 ASSERT_EQ(-1, sigsuspend(&sigset)); 92 ASSERT_EQ(EINTR, errno); 93 94 /* Restore the original signal action, stack, and mask. */ 95 ASSERT_EQ(0, sigaction(SIGUSR1, &oldsigact, NULL)); 96 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &oldsigset, NULL)); 97 } 98 99 static void 100 populate_secret(char *buf, size_t len) 101 { 102 int i, fds[2]; 103 ASSERT_EQ(0, pipe(fds)); 104 105 for (i = 0; i < SECRETCOUNT; i++) 106 ASSERT_EQ(sizeof(secret), write(fds[1], secret, sizeof(secret))); 107 ASSERT_EQ(0, close(fds[1])); 108 109 ASSERT_EQ(len, read(fds[0], buf, len)); 110 ASSERT_EQ(0, close(fds[0])); 111 } 112 113 static int 114 count_secrets(const char *buf) 115 { 116 int res = 0; 117 size_t i; 118 for (i = 0; i < SECRETCOUNT; i++) { 119 if (memcmp(buf + i * sizeof(secret), secret, 120 sizeof(secret)) == 0) 121 res += 1; 122 } 123 return (res); 124 } 125 126 static char * 127 test_without_bzero() 128 { 129 char buf[SECRETBYTES]; 130 assert_on_stack(); 131 populate_secret(buf, sizeof(buf)); 132 char *res = memmem(altstack, sizeof(altstack), buf, sizeof(buf)); 133 ASSERT_NE(NULL, res); 134 return (res); 135 } 136 137 static char * 138 test_with_bzero() 139 { 140 char buf[SECRETBYTES]; 141 assert_on_stack(); 142 populate_secret(buf, sizeof(buf)); 143 char *res = memmem(altstack, sizeof(altstack), buf, sizeof(buf)); 144 ASSERT_NE(NULL, res); 145 explicit_bzero(buf, sizeof(buf)); 146 return (res); 147 } 148 149 static void 150 do_test_without_bzero(int signo) 151 { 152 char *buf = test_without_bzero(); 153 ASSERT_GE(count_secrets(buf), 1); 154 } 155 156 static void 157 do_test_with_bzero(int signo) 158 { 159 char *buf = test_with_bzero(); 160 ASSERT_EQ(count_secrets(buf), 0); 161 } 162 163 int 164 main() 165 { 166 setup_stack(); 167 168 /* 169 * Solaris and OS X clobber the signal stack after returning to the 170 * normal stack, so we need to inspect altstack while we're still 171 * running on it. Unfortunately, this means we risk clobbering the 172 * buffer ourselves. 173 * 174 * To minimize this risk, test_with{,out}_bzero() are responsible for 175 * locating the offset of their buf variable within altstack, and 176 * and returning that address. Then we can simply memcmp() repeatedly 177 * to count how many instances of secret we found. 178 */ 179 180 /* 181 * First, test that if we *don't* call explicit_bzero, that we 182 * *are* able to find at least one instance of the secret data still 183 * on the stack. This sanity checks that call_on_stack() and 184 * populate_secret() work as intended. 185 */ 186 memset(altstack, 0, sizeof(altstack)); 187 call_on_stack(do_test_without_bzero); 188 189 /* 190 * Now test with a call to explicit_bzero() and check that we 191 * *don't* find any instances of the secret data. 192 */ 193 memset(altstack, 0, sizeof(altstack)); 194 call_on_stack(do_test_with_bzero); 195 196 return (0); 197 } 198