core-pkey.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Ptrace test for Memory Protection Key registers
  4. *
  5. * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
  6. * Copyright (C) 2018 IBM Corporation.
  7. */
  8. #include <limits.h>
  9. #include <linux/kernel.h>
  10. #include <sys/mman.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <sys/time.h>
  14. #include <sys/resource.h>
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17. #include "ptrace.h"
  18. #include "child.h"
  19. #ifndef __NR_pkey_alloc
  20. #define __NR_pkey_alloc 384
  21. #endif
  22. #ifndef __NR_pkey_free
  23. #define __NR_pkey_free 385
  24. #endif
  25. #ifndef NT_PPC_PKEY
  26. #define NT_PPC_PKEY 0x110
  27. #endif
  28. #ifndef PKEY_DISABLE_EXECUTE
  29. #define PKEY_DISABLE_EXECUTE 0x4
  30. #endif
  31. #define AMR_BITS_PER_PKEY 2
  32. #define PKEY_REG_BITS (sizeof(u64) * 8)
  33. #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
  34. #define CORE_FILE_LIMIT (5 * 1024 * 1024) /* 5 MB should be enough */
  35. static const char core_pattern_file[] = "/proc/sys/kernel/core_pattern";
  36. static const char user_write[] = "[User Write (Running)]";
  37. static const char core_read_running[] = "[Core Read (Running)]";
  38. /* Information shared between the parent and the child. */
  39. struct shared_info {
  40. struct child_sync child_sync;
  41. /* AMR value the parent expects to read in the core file. */
  42. unsigned long amr;
  43. /* IAMR value the parent expects to read in the core file. */
  44. unsigned long iamr;
  45. /* UAMOR value the parent expects to read in the core file. */
  46. unsigned long uamor;
  47. /* When the child crashed. */
  48. time_t core_time;
  49. };
  50. static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
  51. {
  52. return syscall(__NR_pkey_alloc, flags, init_access_rights);
  53. }
  54. static int sys_pkey_free(int pkey)
  55. {
  56. return syscall(__NR_pkey_free, pkey);
  57. }
  58. static int increase_core_file_limit(void)
  59. {
  60. struct rlimit rlim;
  61. int ret;
  62. ret = getrlimit(RLIMIT_CORE, &rlim);
  63. FAIL_IF(ret);
  64. if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
  65. rlim.rlim_cur = CORE_FILE_LIMIT;
  66. if (rlim.rlim_max != RLIM_INFINITY &&
  67. rlim.rlim_max < CORE_FILE_LIMIT)
  68. rlim.rlim_max = CORE_FILE_LIMIT;
  69. ret = setrlimit(RLIMIT_CORE, &rlim);
  70. FAIL_IF(ret);
  71. }
  72. ret = getrlimit(RLIMIT_FSIZE, &rlim);
  73. FAIL_IF(ret);
  74. if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
  75. rlim.rlim_cur = CORE_FILE_LIMIT;
  76. if (rlim.rlim_max != RLIM_INFINITY &&
  77. rlim.rlim_max < CORE_FILE_LIMIT)
  78. rlim.rlim_max = CORE_FILE_LIMIT;
  79. ret = setrlimit(RLIMIT_FSIZE, &rlim);
  80. FAIL_IF(ret);
  81. }
  82. return TEST_PASS;
  83. }
  84. static int child(struct shared_info *info)
  85. {
  86. bool disable_execute = true;
  87. int pkey1, pkey2, pkey3;
  88. int *ptr, ret;
  89. /* Wait until parent fills out the initial register values. */
  90. ret = wait_parent(&info->child_sync);
  91. if (ret)
  92. return ret;
  93. ret = increase_core_file_limit();
  94. FAIL_IF(ret);
  95. /* Get some pkeys so that we can change their bits in the AMR. */
  96. pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
  97. if (pkey1 < 0) {
  98. pkey1 = sys_pkey_alloc(0, 0);
  99. FAIL_IF(pkey1 < 0);
  100. disable_execute = false;
  101. }
  102. pkey2 = sys_pkey_alloc(0, 0);
  103. FAIL_IF(pkey2 < 0);
  104. pkey3 = sys_pkey_alloc(0, 0);
  105. FAIL_IF(pkey3 < 0);
  106. info->amr |= 3ul << pkeyshift(pkey1) | 2ul << pkeyshift(pkey2);
  107. if (disable_execute)
  108. info->iamr |= 1ul << pkeyshift(pkey1);
  109. else
  110. info->iamr &= ~(1ul << pkeyshift(pkey1));
  111. info->iamr &= ~(1ul << pkeyshift(pkey2) | 1ul << pkeyshift(pkey3));
  112. info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2);
  113. printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
  114. user_write, info->amr, pkey1, pkey2, pkey3);
  115. mtspr(SPRN_AMR, info->amr);
  116. /*
  117. * We won't use pkey3. This tests whether the kernel restores the UAMOR
  118. * permissions after a key is freed.
  119. */
  120. sys_pkey_free(pkey3);
  121. info->core_time = time(NULL);
  122. /* Crash. */
  123. ptr = 0;
  124. *ptr = 1;
  125. /* Shouldn't get here. */
  126. FAIL_IF(true);
  127. return TEST_FAIL;
  128. }
  129. /* Return file size if filename exists and pass sanity check, or zero if not. */
  130. static off_t try_core_file(const char *filename, struct shared_info *info,
  131. pid_t pid)
  132. {
  133. struct stat buf;
  134. int ret;
  135. ret = stat(filename, &buf);
  136. if (ret == -1)
  137. return TEST_FAIL;
  138. /* Make sure we're not using a stale core file. */
  139. return buf.st_mtime >= info->core_time ? buf.st_size : TEST_FAIL;
  140. }
  141. static Elf64_Nhdr *next_note(Elf64_Nhdr *nhdr)
  142. {
  143. return (void *) nhdr + sizeof(*nhdr) +
  144. __ALIGN_KERNEL(nhdr->n_namesz, 4) +
  145. __ALIGN_KERNEL(nhdr->n_descsz, 4);
  146. }
  147. static int check_core_file(struct shared_info *info, Elf64_Ehdr *ehdr,
  148. off_t core_size)
  149. {
  150. unsigned long *regs;
  151. Elf64_Phdr *phdr;
  152. Elf64_Nhdr *nhdr;
  153. size_t phdr_size;
  154. void *p = ehdr, *note;
  155. int ret;
  156. ret = memcmp(ehdr->e_ident, ELFMAG, SELFMAG);
  157. FAIL_IF(ret);
  158. FAIL_IF(ehdr->e_type != ET_CORE);
  159. FAIL_IF(ehdr->e_machine != EM_PPC64);
  160. FAIL_IF(ehdr->e_phoff == 0 || ehdr->e_phnum == 0);
  161. /*
  162. * e_phnum is at most 65535 so calculating the size of the
  163. * program header cannot overflow.
  164. */
  165. phdr_size = sizeof(*phdr) * ehdr->e_phnum;
  166. /* Sanity check the program header table location. */
  167. FAIL_IF(ehdr->e_phoff + phdr_size < ehdr->e_phoff);
  168. FAIL_IF(ehdr->e_phoff + phdr_size > core_size);
  169. /* Find the PT_NOTE segment. */
  170. for (phdr = p + ehdr->e_phoff;
  171. (void *) phdr < p + ehdr->e_phoff + phdr_size;
  172. phdr += ehdr->e_phentsize)
  173. if (phdr->p_type == PT_NOTE)
  174. break;
  175. FAIL_IF((void *) phdr >= p + ehdr->e_phoff + phdr_size);
  176. /* Find the NT_PPC_PKEY note. */
  177. for (nhdr = p + phdr->p_offset;
  178. (void *) nhdr < p + phdr->p_offset + phdr->p_filesz;
  179. nhdr = next_note(nhdr))
  180. if (nhdr->n_type == NT_PPC_PKEY)
  181. break;
  182. FAIL_IF((void *) nhdr >= p + phdr->p_offset + phdr->p_filesz);
  183. FAIL_IF(nhdr->n_descsz == 0);
  184. p = nhdr;
  185. note = p + sizeof(*nhdr) + __ALIGN_KERNEL(nhdr->n_namesz, 4);
  186. regs = (unsigned long *) note;
  187. printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
  188. core_read_running, regs[0], regs[1], regs[2]);
  189. FAIL_IF(regs[0] != info->amr);
  190. FAIL_IF(regs[1] != info->iamr);
  191. FAIL_IF(regs[2] != info->uamor);
  192. return TEST_PASS;
  193. }
  194. static int parent(struct shared_info *info, pid_t pid)
  195. {
  196. char *filenames, *filename[3];
  197. int fd, i, ret, status;
  198. unsigned long regs[3];
  199. off_t core_size;
  200. void *core;
  201. /*
  202. * Get the initial values for AMR, IAMR and UAMOR and communicate them
  203. * to the child.
  204. */
  205. ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
  206. PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
  207. PARENT_FAIL_IF(ret, &info->child_sync);
  208. info->amr = regs[0];
  209. info->iamr = regs[1];
  210. info->uamor = regs[2];
  211. /* Wake up child so that it can set itself up. */
  212. ret = prod_child(&info->child_sync);
  213. PARENT_FAIL_IF(ret, &info->child_sync);
  214. ret = wait(&status);
  215. if (ret != pid) {
  216. printf("Child's exit status not captured\n");
  217. return TEST_FAIL;
  218. } else if (!WIFSIGNALED(status) || !WCOREDUMP(status)) {
  219. printf("Child didn't dump core\n");
  220. return TEST_FAIL;
  221. }
  222. /* Construct array of core file names to try. */
  223. filename[0] = filenames = malloc(PATH_MAX);
  224. if (!filenames) {
  225. perror("Error allocating memory");
  226. return TEST_FAIL;
  227. }
  228. ret = snprintf(filename[0], PATH_MAX, "core-pkey.%d", pid);
  229. if (ret < 0 || ret >= PATH_MAX) {
  230. ret = TEST_FAIL;
  231. goto out;
  232. }
  233. filename[1] = filename[0] + ret + 1;
  234. ret = snprintf(filename[1], PATH_MAX - ret - 1, "core.%d", pid);
  235. if (ret < 0 || ret >= PATH_MAX - ret - 1) {
  236. ret = TEST_FAIL;
  237. goto out;
  238. }
  239. filename[2] = "core";
  240. for (i = 0; i < 3; i++) {
  241. core_size = try_core_file(filename[i], info, pid);
  242. if (core_size != TEST_FAIL)
  243. break;
  244. }
  245. if (i == 3) {
  246. printf("Couldn't find core file\n");
  247. ret = TEST_FAIL;
  248. goto out;
  249. }
  250. fd = open(filename[i], O_RDONLY);
  251. if (fd == -1) {
  252. perror("Error opening core file");
  253. ret = TEST_FAIL;
  254. goto out;
  255. }
  256. core = mmap(NULL, core_size, PROT_READ, MAP_PRIVATE, fd, 0);
  257. if (core == (void *) -1) {
  258. perror("Error mmaping core file");
  259. ret = TEST_FAIL;
  260. goto out;
  261. }
  262. ret = check_core_file(info, core, core_size);
  263. munmap(core, core_size);
  264. close(fd);
  265. unlink(filename[i]);
  266. out:
  267. free(filenames);
  268. return ret;
  269. }
  270. static int write_core_pattern(const char *core_pattern)
  271. {
  272. size_t len = strlen(core_pattern), ret;
  273. FILE *f;
  274. f = fopen(core_pattern_file, "w");
  275. if (!f) {
  276. perror("Error writing to core_pattern file");
  277. return TEST_FAIL;
  278. }
  279. ret = fwrite(core_pattern, 1, len, f);
  280. fclose(f);
  281. if (ret != len) {
  282. perror("Error writing to core_pattern file");
  283. return TEST_FAIL;
  284. }
  285. return TEST_PASS;
  286. }
  287. static int setup_core_pattern(char **core_pattern_, bool *changed_)
  288. {
  289. FILE *f;
  290. char *core_pattern;
  291. int ret;
  292. core_pattern = malloc(PATH_MAX);
  293. if (!core_pattern) {
  294. perror("Error allocating memory");
  295. return TEST_FAIL;
  296. }
  297. f = fopen(core_pattern_file, "r");
  298. if (!f) {
  299. perror("Error opening core_pattern file");
  300. ret = TEST_FAIL;
  301. goto out;
  302. }
  303. ret = fread(core_pattern, 1, PATH_MAX, f);
  304. fclose(f);
  305. if (!ret) {
  306. perror("Error reading core_pattern file");
  307. ret = TEST_FAIL;
  308. goto out;
  309. }
  310. /* Check whether we can predict the name of the core file. */
  311. if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
  312. *changed_ = false;
  313. else {
  314. ret = write_core_pattern("core-pkey.%p");
  315. if (ret)
  316. goto out;
  317. *changed_ = true;
  318. }
  319. *core_pattern_ = core_pattern;
  320. ret = TEST_PASS;
  321. out:
  322. if (ret)
  323. free(core_pattern);
  324. return ret;
  325. }
  326. static int core_pkey(void)
  327. {
  328. char *core_pattern;
  329. bool changed_core_pattern;
  330. struct shared_info *info;
  331. int shm_id;
  332. int ret;
  333. pid_t pid;
  334. ret = setup_core_pattern(&core_pattern, &changed_core_pattern);
  335. if (ret)
  336. return ret;
  337. shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
  338. info = shmat(shm_id, NULL, 0);
  339. ret = init_child_sync(&info->child_sync);
  340. if (ret)
  341. return ret;
  342. pid = fork();
  343. if (pid < 0) {
  344. perror("fork() failed");
  345. ret = TEST_FAIL;
  346. } else if (pid == 0)
  347. ret = child(info);
  348. else
  349. ret = parent(info, pid);
  350. shmdt(info);
  351. if (pid) {
  352. destroy_child_sync(&info->child_sync);
  353. shmctl(shm_id, IPC_RMID, NULL);
  354. if (changed_core_pattern)
  355. write_core_pattern(core_pattern);
  356. }
  357. free(core_pattern);
  358. return ret;
  359. }
  360. int main(int argc, char *argv[])
  361. {
  362. return test_harness(core_pkey, "core_pkey");
  363. }