seal_elf.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <sys/mman.h>
  4. #include <stdint.h>
  5. #include <asm-generic/unistd.h>
  6. #include <string.h>
  7. #include <sys/time.h>
  8. #include <sys/resource.h>
  9. #include <stdbool.h>
  10. #include "../kselftest.h"
  11. #include <syscall.h>
  12. #include <errno.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <fcntl.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/vfs.h>
  18. #include <sys/stat.h>
  19. #include "mseal_helpers.h"
  20. /*
  21. * define sys_xyx to call syscall directly.
  22. */
  23. static int sys_mseal(void *start, size_t len)
  24. {
  25. int sret;
  26. errno = 0;
  27. sret = syscall(__NR_mseal, start, len, 0);
  28. return sret;
  29. }
  30. static inline int sys_mprotect(void *ptr, size_t size, unsigned long prot)
  31. {
  32. int sret;
  33. errno = 0;
  34. sret = syscall(__NR_mprotect, ptr, size, prot);
  35. return sret;
  36. }
  37. static bool seal_support(void)
  38. {
  39. int ret;
  40. void *ptr;
  41. unsigned long page_size = getpagesize();
  42. ptr = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  43. if (ptr == (void *) -1)
  44. return false;
  45. ret = sys_mseal(ptr, page_size);
  46. if (ret < 0)
  47. return false;
  48. return true;
  49. }
  50. const char somestr[4096] = {"READONLY"};
  51. static void test_seal_elf(void)
  52. {
  53. int ret;
  54. FILE *maps;
  55. char line[512];
  56. uintptr_t addr_start, addr_end;
  57. char prot[5];
  58. char filename[256];
  59. unsigned long page_size = getpagesize();
  60. unsigned long long ptr = (unsigned long long) somestr;
  61. char *somestr2 = (char *)somestr;
  62. /*
  63. * Modify the protection of readonly somestr
  64. */
  65. if (((unsigned long long)ptr % page_size) != 0)
  66. ptr = (unsigned long long)ptr & ~(page_size - 1);
  67. ksft_print_msg("somestr = %s\n", somestr);
  68. ksft_print_msg("change protection to rw\n");
  69. ret = sys_mprotect((void *)ptr, page_size, PROT_READ|PROT_WRITE);
  70. FAIL_TEST_IF_FALSE(!ret);
  71. *somestr2 = 'A';
  72. ksft_print_msg("somestr is modified to: %s\n", somestr);
  73. ret = sys_mprotect((void *)ptr, page_size, PROT_READ);
  74. FAIL_TEST_IF_FALSE(!ret);
  75. maps = fopen("/proc/self/maps", "r");
  76. FAIL_TEST_IF_FALSE(maps);
  77. /*
  78. * apply sealing to elf binary
  79. */
  80. while (fgets(line, sizeof(line), maps)) {
  81. if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*u %255[^\n]",
  82. &addr_start, &addr_end, prot, filename) == 4) {
  83. if (strlen(filename)) {
  84. /*
  85. * seal the mapping if read only.
  86. */
  87. if (strstr(prot, "r-")) {
  88. ret = sys_mseal((void *)addr_start, addr_end - addr_start);
  89. FAIL_TEST_IF_FALSE(!ret);
  90. ksft_print_msg("sealed: %lx-%lx %s %s\n",
  91. addr_start, addr_end, prot, filename);
  92. if ((uintptr_t) somestr >= addr_start &&
  93. (uintptr_t) somestr <= addr_end)
  94. ksft_print_msg("mapping for somestr found\n");
  95. }
  96. }
  97. }
  98. }
  99. fclose(maps);
  100. ret = sys_mprotect((void *)ptr, page_size, PROT_READ | PROT_WRITE);
  101. FAIL_TEST_IF_FALSE(ret < 0);
  102. ksft_print_msg("somestr is sealed, mprotect is rejected\n");
  103. REPORT_TEST_PASS();
  104. }
  105. int main(int argc, char **argv)
  106. {
  107. bool test_seal = seal_support();
  108. ksft_print_header();
  109. ksft_print_msg("pid=%d\n", getpid());
  110. if (!test_seal)
  111. ksft_exit_skip("sealing not supported, check CONFIG_64BIT\n");
  112. ksft_set_plan(1);
  113. test_seal_elf();
  114. ksft_finished();
  115. }