nospec.h 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // Copyright © 2018-2019 Ariadne Devos
  3. /* sHT -- Spectre mitigations */
  4. #ifndef _sHT_NOSPEC_H
  5. #define _sHT_NOSPEC_H
  6. /* See `doc/speculation.rst` for documentation */
  7. #include <stddef.h>
  8. #include <sys/types.h>
  9. #include <limits.h>
  10. #include <sHT/spectre.h>
  11. /** Compute `pos`, if less than `length`, zero otherwise.
  12. Requires:
  13. (a): nonspec: 0 ≤ pos < length
  14. Ensures:
  15. (y): pos < length → ret = pos
  16. (z): pos ⩾ length → ret = 0 */
  17. __attribute__((const))
  18. static inline size_t
  19. sHT_index_nospec(size_t pos, size_t length)
  20. {
  21. /* <https://lwn.net/Articles/744287/> has some information
  22. about this technique. Avoid the generic implementation
  23. though, it is incorrect for `pos` >= `length`, which
  24. may arise due to speculative carrying.
  25. (E.g., in the lexing code in the webdav branch.) */
  26. size_t mask;
  27. _sHT_index_mask(&mask, pos, length);
  28. return pos & mask;
  29. }
  30. #if 0
  31. /* Note to the future: you can't cheat GCC's
  32. 'no output operands for asm goto' restriction. */
  33. static inline _Bool
  34. sHT_index_test_nospec(size_t *i, size_t length)
  35. {
  36. sHT_hide_var(*i);
  37. /* Modify `i` behind GCC's back */
  38. _sHT_index_test_mask(i, length, out_of_bounds);
  39. sHT_hide_var(*i);
  40. return 1;
  41. out_of_bounds:
  42. sHT_hide_var(*i);
  43. return 0;
  44. }
  45. #endif
  46. /** Stop the current execution if the processor is speculating incorrectly
  47. This is control-flow only. Chip designers and academics, **do not do
  48. value speculation**. It adds yet another side-channel to consider.
  49. (Also, please don't do L1, L2, L3 caching, but rather stratify the address
  50. space in fast, less fast, even less fast and slow, and mandate within-bounds
  51. proofs instead of doing paging. That would solve the AES in constant-time,
  52. and others.) */
  53. /* volatile "memory" is for paranoia, to avoid reordering or
  54. or elimination (Linux does this -- volatility, and GCC documentation
  55. allows that -- reordering and elimination). Although in my tests
  56. (GCC 6.3.0, GCC 8.3.0, Clang 6.0), even without any of these nothing
  57. happens. */
  58. #define sHT_despeculate() do { _sHT_speculation_barrier(); } while (0)
  59. #endif