1
0

winmiscs.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * winmiscs.c: Windows-specific standalone functions. Has the same
  3. * relationship to winmisc.c that utils.c does to misc.c, but the
  4. * corresponding name 'winutils.c' was already taken.
  5. */
  6. #include "putty.h"
  7. #ifndef NO_SECUREZEROMEMORY
  8. /*
  9. * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
  10. */
  11. void smemclr(void *b, size_t n) {
  12. if (b && n > 0)
  13. SecureZeroMemory(b, n);
  14. }
  15. #endif
  16. #ifdef MINEFIELD
  17. /*
  18. * Minefield - a Windows equivalent for Electric Fence
  19. */
  20. #define PAGESIZE 4096
  21. /*
  22. * Design:
  23. *
  24. * We start by reserving as much virtual address space as Windows
  25. * will sensibly (or not sensibly) let us have. We flag it all as
  26. * invalid memory.
  27. *
  28. * Any allocation attempt is satisfied by committing one or more
  29. * pages, with an uncommitted page on either side. The returned
  30. * memory region is jammed up against the _end_ of the pages.
  31. *
  32. * Freeing anything causes instantaneous decommitment of the pages
  33. * involved, so stale pointers are caught as soon as possible.
  34. */
  35. static int minefield_initialised = 0;
  36. static void *minefield_region = NULL;
  37. static long minefield_size = 0;
  38. static long minefield_npages = 0;
  39. static long minefield_curpos = 0;
  40. static unsigned short *minefield_admin = NULL;
  41. static void *minefield_pages = NULL;
  42. static void minefield_admin_hide(int hide)
  43. {
  44. int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
  45. VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
  46. }
  47. static void minefield_init(void)
  48. {
  49. int size;
  50. int admin_size;
  51. int i;
  52. for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
  53. minefield_region = VirtualAlloc(NULL, size,
  54. MEM_RESERVE, PAGE_NOACCESS);
  55. if (minefield_region)
  56. break;
  57. }
  58. minefield_size = size;
  59. /*
  60. * Firstly, allocate a section of that to be the admin block.
  61. * We'll need a two-byte field for each page.
  62. */
  63. minefield_admin = minefield_region;
  64. minefield_npages = minefield_size / PAGESIZE;
  65. admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
  66. minefield_npages = (minefield_size - admin_size) / PAGESIZE;
  67. minefield_pages = (char *) minefield_region + admin_size;
  68. /*
  69. * Commit the admin region.
  70. */
  71. VirtualAlloc(minefield_admin, minefield_npages * 2,
  72. MEM_COMMIT, PAGE_READWRITE);
  73. /*
  74. * Mark all pages as unused (0xFFFF).
  75. */
  76. for (i = 0; i < minefield_npages; i++)
  77. minefield_admin[i] = 0xFFFF;
  78. /*
  79. * Hide the admin region.
  80. */
  81. minefield_admin_hide(1);
  82. minefield_initialised = 1;
  83. }
  84. static void minefield_bomb(void)
  85. {
  86. div(1, *(int *) minefield_pages);
  87. }
  88. static void *minefield_alloc(int size)
  89. {
  90. int npages;
  91. int pos, lim, region_end, region_start;
  92. int start;
  93. int i;
  94. npages = (size + PAGESIZE - 1) / PAGESIZE;
  95. minefield_admin_hide(0);
  96. /*
  97. * Search from current position until we find a contiguous
  98. * bunch of npages+2 unused pages.
  99. */
  100. pos = minefield_curpos;
  101. lim = minefield_npages;
  102. while (1) {
  103. /* Skip over used pages. */
  104. while (pos < lim && minefield_admin[pos] != 0xFFFF)
  105. pos++;
  106. /* Count unused pages. */
  107. start = pos;
  108. while (pos < lim && pos - start < npages + 2 &&
  109. minefield_admin[pos] == 0xFFFF)
  110. pos++;
  111. if (pos - start == npages + 2)
  112. break;
  113. /* If we've reached the limit, reset the limit or stop. */
  114. if (pos >= lim) {
  115. if (lim == minefield_npages) {
  116. /* go round and start again at zero */
  117. lim = minefield_curpos;
  118. pos = 0;
  119. } else {
  120. minefield_admin_hide(1);
  121. return NULL;
  122. }
  123. }
  124. }
  125. minefield_curpos = pos - 1;
  126. /*
  127. * We have npages+2 unused pages starting at start. We leave
  128. * the first and last of these alone and use the rest.
  129. */
  130. region_end = (start + npages + 1) * PAGESIZE;
  131. region_start = region_end - size;
  132. /* FIXME: could align here if we wanted */
  133. /*
  134. * Update the admin region.
  135. */
  136. for (i = start + 2; i < start + npages + 1; i++)
  137. minefield_admin[i] = 0xFFFE; /* used but no region starts here */
  138. minefield_admin[start + 1] = region_start % PAGESIZE;
  139. minefield_admin_hide(1);
  140. VirtualAlloc((char *) minefield_pages + region_start, size,
  141. MEM_COMMIT, PAGE_READWRITE);
  142. return (char *) minefield_pages + region_start;
  143. }
  144. static void minefield_free(void *ptr)
  145. {
  146. int region_start, i, j;
  147. minefield_admin_hide(0);
  148. region_start = (char *) ptr - (char *) minefield_pages;
  149. i = region_start / PAGESIZE;
  150. if (i < 0 || i >= minefield_npages ||
  151. minefield_admin[i] != region_start % PAGESIZE)
  152. minefield_bomb();
  153. for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
  154. minefield_admin[j] = 0xFFFF;
  155. }
  156. VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
  157. minefield_admin_hide(1);
  158. }
  159. static int minefield_get_size(void *ptr)
  160. {
  161. int region_start, i, j;
  162. minefield_admin_hide(0);
  163. region_start = (char *) ptr - (char *) minefield_pages;
  164. i = region_start / PAGESIZE;
  165. if (i < 0 || i >= minefield_npages ||
  166. minefield_admin[i] != region_start % PAGESIZE)
  167. minefield_bomb();
  168. for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
  169. minefield_admin_hide(1);
  170. return j * PAGESIZE - region_start;
  171. }
  172. void *minefield_c_malloc(size_t size)
  173. {
  174. if (!minefield_initialised)
  175. minefield_init();
  176. return minefield_alloc(size);
  177. }
  178. void minefield_c_free(void *p)
  179. {
  180. if (!minefield_initialised)
  181. minefield_init();
  182. minefield_free(p);
  183. }
  184. /*
  185. * realloc _always_ moves the chunk, for rapid detection of code
  186. * that assumes it won't.
  187. */
  188. void *minefield_c_realloc(void *p, size_t size)
  189. {
  190. size_t oldsize;
  191. void *q;
  192. if (!minefield_initialised)
  193. minefield_init();
  194. q = minefield_alloc(size);
  195. oldsize = minefield_get_size(p);
  196. memcpy(q, p, (oldsize < size ? oldsize : size));
  197. minefield_free(p);
  198. return q;
  199. }
  200. #endif /* MINEFIELD */
  201. #if defined _MSC_VER && _MSC_VER < 1800
  202. /*
  203. * Work around lack of strtoumax in older MSVC libraries
  204. */
  205. uintmax_t strtoumax(const char *nptr, char **endptr, int base)
  206. {
  207. return _strtoui64(nptr, endptr, base);
  208. }
  209. #endif
  210. #if defined _M_ARM || defined _M_ARM64
  211. bool platform_aes_hw_available(void)
  212. {
  213. return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
  214. }
  215. bool platform_sha256_hw_available(void)
  216. {
  217. return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
  218. }
  219. bool platform_sha1_hw_available(void)
  220. {
  221. return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
  222. }
  223. #endif
  224. bool is_console_handle(HANDLE handle)
  225. {
  226. DWORD ignored_output;
  227. if (GetConsoleMode(handle, &ignored_output))
  228. return true;
  229. return false;
  230. }