pku.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include "libcflat.h"
  2. #include "x86/desc.h"
  3. #include "x86/processor.h"
  4. #include "x86/vm.h"
  5. #include "x86/msr.h"
  6. #define X86_FEATURE_PKU 3
  7. #define CR0_WP_MASK (1UL << 16)
  8. #define PTE_PKEY_BIT 59
  9. #define USER_BASE (1 << 24)
  10. #define USER_VAR(v) (*((__typeof__(&(v))) (((unsigned long)&v) + USER_BASE)))
  11. volatile int pf_count = 0;
  12. volatile unsigned save;
  13. volatile unsigned test;
  14. void set_cr0_wp(int wp)
  15. {
  16. unsigned long cr0 = read_cr0();
  17. cr0 &= ~CR0_WP_MASK;
  18. if (wp)
  19. cr0 |= CR0_WP_MASK;
  20. write_cr0(cr0);
  21. }
  22. void do_pf_tss(unsigned long error_code)
  23. {
  24. pf_count++;
  25. save = test;
  26. write_pkru(0);
  27. }
  28. extern void pf_tss(void);
  29. asm ("pf_tss: \n\t"
  30. #ifdef __x86_64__
  31. // no task on x86_64, save/restore caller-save regs
  32. "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n"
  33. "push %r8; push %r9; push %r10; push %r11\n"
  34. #endif
  35. "call do_pf_tss \n\t"
  36. #ifdef __x86_64__
  37. "pop %r11; pop %r10; pop %r9; pop %r8\n"
  38. "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n"
  39. #endif
  40. "add $"S", %"R "sp\n\t" // discard error code
  41. "iret"W" \n\t"
  42. "jmp pf_tss\n\t"
  43. );
  44. static void init_test()
  45. {
  46. pf_count = 0;
  47. invlpg(&test);
  48. invlpg(&USER_VAR(test));
  49. write_pkru(0);
  50. set_cr0_wp(0);
  51. }
  52. int main(int ac, char **av)
  53. {
  54. unsigned long i;
  55. unsigned int pkey = 0x2;
  56. unsigned int pkru_ad = 0x10;
  57. unsigned int pkru_wd = 0x20;
  58. if (!(cpuid_indexed(7, 0).c & (1 << X86_FEATURE_PKU))) {
  59. printf("PKU not enabled\n");
  60. return report_summary();
  61. }
  62. setup_vm();
  63. setup_alt_stack();
  64. set_intr_alt_stack(14, pf_tss);
  65. wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA);
  66. for (i = 0; i < USER_BASE; i += PAGE_SIZE) {
  67. *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PT_USER_MASK;
  68. *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
  69. invlpg((void *)i);
  70. }
  71. for (i = USER_BASE; i < 2 * USER_BASE; i += PAGE_SIZE) {
  72. *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~USER_BASE;
  73. *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
  74. invlpg((void *)i);
  75. }
  76. write_cr4(read_cr4() | X86_CR4_PKE);
  77. write_cr3(read_cr3());
  78. init_test();
  79. set_cr0_wp(1);
  80. write_pkru(pkru_ad);
  81. test = 21;
  82. report("write to supervisor page when pkru is ad and wp == 1", pf_count == 0 && test == 21);
  83. init_test();
  84. set_cr0_wp(0);
  85. write_pkru(pkru_ad);
  86. test = 22;
  87. report("write to supervisor page when pkru is ad and wp == 0", pf_count == 0 && test == 22);
  88. init_test();
  89. set_cr0_wp(1);
  90. write_pkru(pkru_wd);
  91. test = 23;
  92. report("write to supervisor page when pkru is wd and wp == 1", pf_count == 0 && test == 23);
  93. init_test();
  94. set_cr0_wp(0);
  95. write_pkru(pkru_wd);
  96. test = 24;
  97. report("write to supervisor page when pkru is wd and wp == 0", pf_count == 0 && test == 24);
  98. init_test();
  99. write_pkru(pkru_wd);
  100. set_cr0_wp(0);
  101. USER_VAR(test) = 25;
  102. report("write to user page when pkru is wd and wp == 0", pf_count == 0 && test == 25);
  103. init_test();
  104. write_pkru(pkru_wd);
  105. set_cr0_wp(1);
  106. USER_VAR(test) = 26;
  107. report("write to user page when pkru is wd and wp == 1", pf_count == 1 && test == 26 && save == 25);
  108. init_test();
  109. write_pkru(pkru_ad);
  110. (void)USER_VAR(test);
  111. report("read from user page when pkru is ad", pf_count == 1 && save == 26);
  112. // TODO: implicit kernel access from ring 3 (e.g. int)
  113. return report_summary();
  114. }