test-memwipe.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <stdlib.h>
  5. #include "crypto.h"
  6. #include "compat.h"
  7. #undef MIN
  8. #define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
  9. static unsigned fill_a_buffer_memset(void) __attribute__((noinline));
  10. static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline));
  11. static unsigned fill_a_buffer_nothing(void) __attribute__((noinline));
  12. static unsigned fill_heap_buffer_memset(void) __attribute__((noinline));
  13. static unsigned fill_heap_buffer_memwipe(void) __attribute__((noinline));
  14. static unsigned fill_heap_buffer_nothing(void) __attribute__((noinline));
  15. static unsigned check_a_buffer(void) __attribute__((noinline));
  16. const char *s = NULL;
  17. #define BUF_LEN 2048
  18. #define FILL_BUFFER_IMPL() \
  19. unsigned int i; \
  20. unsigned sum = 0; \
  21. \
  22. /* Fill up a 1k buffer with a recognizable pattern. */ \
  23. for (i = 0; i < BUF_LEN; i += strlen(s)) { \
  24. memcpy(buf+i, s, MIN(strlen(s), BUF_LEN-i)); \
  25. } \
  26. \
  27. /* Use the buffer as input to a computation so the above can't get */ \
  28. /* optimized away. */ \
  29. for (i = 0; i < BUF_LEN; ++i) { \
  30. sum += (unsigned char)buf[i]; \
  31. }
  32. static unsigned
  33. fill_a_buffer_memset(void)
  34. {
  35. char buf[BUF_LEN];
  36. FILL_BUFFER_IMPL()
  37. memset(buf, 0, sizeof(buf));
  38. return sum;
  39. }
  40. static unsigned
  41. fill_a_buffer_memwipe(void)
  42. {
  43. char buf[BUF_LEN];
  44. FILL_BUFFER_IMPL()
  45. memwipe(buf, 0, sizeof(buf));
  46. return sum;
  47. }
  48. static unsigned
  49. fill_a_buffer_nothing(void)
  50. {
  51. char buf[BUF_LEN];
  52. FILL_BUFFER_IMPL()
  53. return sum;
  54. }
  55. static inline int
  56. vmemeq(volatile char *a, const char *b, size_t n)
  57. {
  58. while (n--) {
  59. if (*a++ != *b++)
  60. return 0;
  61. }
  62. return 1;
  63. }
  64. static unsigned
  65. check_a_buffer(void)
  66. {
  67. unsigned int i;
  68. volatile char buf[1024];
  69. unsigned sum = 0;
  70. /* See if this buffer has the string in it.
  71. YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM AN UNINITIALIZED
  72. BUFFER.
  73. If you know a better way to figure out whether the compiler eliminated
  74. the memset/memwipe calls or not, please let me know.
  75. */
  76. for (i = 0; i < BUF_LEN - strlen(s); ++i) {
  77. if (vmemeq(buf+i, s, strlen(s)))
  78. ++sum;
  79. }
  80. return sum;
  81. }
  82. static char *heap_buf = NULL;
  83. static unsigned
  84. fill_heap_buffer_memset(void)
  85. {
  86. char *buf = heap_buf = malloc(BUF_LEN);
  87. FILL_BUFFER_IMPL()
  88. memset(buf, 0, BUF_LEN);
  89. free(buf);
  90. return sum;
  91. }
  92. static unsigned
  93. fill_heap_buffer_memwipe(void)
  94. {
  95. char *buf = heap_buf = malloc(BUF_LEN);
  96. FILL_BUFFER_IMPL()
  97. memwipe(buf, 0, BUF_LEN);
  98. free(buf);
  99. return sum;
  100. }
  101. static unsigned
  102. fill_heap_buffer_nothing(void)
  103. {
  104. char *buf = heap_buf = malloc(BUF_LEN);
  105. FILL_BUFFER_IMPL()
  106. free(buf);
  107. return sum;
  108. }
  109. static unsigned
  110. check_heap_buffer(void)
  111. {
  112. unsigned int i;
  113. unsigned sum = 0;
  114. volatile char *buf = heap_buf;
  115. /* See if this buffer has the string in it.
  116. YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM A FREED BUFFER.
  117. If you know a better way to figure out whether the compiler eliminated
  118. the memset/memwipe calls or not, please let me know.
  119. */
  120. for (i = 0; i < BUF_LEN - strlen(s); ++i) {
  121. if (vmemeq(buf+i, s, strlen(s)))
  122. ++sum;
  123. }
  124. return sum;
  125. }
  126. static struct testcase {
  127. const char *name;
  128. /* this spacing satisfies make check-spaces */
  129. unsigned
  130. (*fill_fn)(void);
  131. unsigned
  132. (*check_fn)(void);
  133. } testcases[] = {
  134. { "nil", fill_a_buffer_nothing, check_a_buffer },
  135. { "nil-heap", fill_heap_buffer_nothing, check_heap_buffer },
  136. { "memset", fill_a_buffer_memset, check_a_buffer },
  137. { "memset-heap", fill_heap_buffer_memset, check_heap_buffer },
  138. { "memwipe", fill_a_buffer_memwipe, check_a_buffer },
  139. { "memwipe-heap", fill_heap_buffer_memwipe, check_heap_buffer },
  140. { NULL, NULL, NULL }
  141. };
  142. int
  143. main(int argc, char **argv)
  144. {
  145. unsigned x, x2;
  146. int i;
  147. int working = 1;
  148. unsigned found[6];
  149. (void) argc; (void) argv;
  150. s = "squamous haberdasher gallimaufry";
  151. memset(found, 0, sizeof(found));
  152. for (i = 0; testcases[i].name; ++i) {
  153. x = testcases[i].fill_fn();
  154. found[i] = testcases[i].check_fn();
  155. x2 = fill_a_buffer_nothing();
  156. if (x != x2) {
  157. working = 0;
  158. }
  159. }
  160. if (!working || !found[0] || !found[1]) {
  161. printf("It appears that this test case may not give you reliable "
  162. "information. Sorry.\n");
  163. }
  164. if (!found[2] && !found[3]) {
  165. printf("It appears that memset is good enough on this platform. Good.\n");
  166. }
  167. if (found[4] || found[5]) {
  168. printf("ERROR: memwipe does not wipe data!\n");
  169. return 1;
  170. } else {
  171. printf("OKAY: memwipe seems to work.\n");
  172. return 0;
  173. }
  174. }