core-pkey.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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. info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2);
  110. printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
  111. user_write, info->amr, pkey1, pkey2, pkey3);
  112. mtspr(SPRN_AMR, info->amr);
  113. /*
  114. * We won't use pkey3. This tests whether the kernel restores the UAMOR
  115. * permissions after a key is freed.
  116. */
  117. sys_pkey_free(pkey3);
  118. info->core_time = time(NULL);
  119. /* Crash. */
  120. ptr = 0;
  121. *ptr = 1;
  122. /* Shouldn't get here. */
  123. FAIL_IF(true);
  124. return TEST_FAIL;
  125. }
  126. /* Return file size if filename exists and pass sanity check, or zero if not. */
  127. static off_t try_core_file(const char *filename, struct shared_info *info,
  128. pid_t pid)
  129. {
  130. struct stat buf;
  131. int ret;
  132. ret = stat(filename, &buf);
  133. if (ret == -1)
  134. return TEST_FAIL;
  135. /* Make sure we're not using a stale core file. */
  136. return buf.st_mtime >= info->core_time ? buf.st_size : TEST_FAIL;
  137. }
  138. static Elf64_Nhdr *next_note(Elf64_Nhdr *nhdr)
  139. {
  140. return (void *) nhdr + sizeof(*nhdr) +
  141. __ALIGN_KERNEL(nhdr->n_namesz, 4) +
  142. __ALIGN_KERNEL(nhdr->n_descsz, 4);
  143. }
  144. static int check_core_file(struct shared_info *info, Elf64_Ehdr *ehdr,
  145. off_t core_size)
  146. {
  147. unsigned long *regs;
  148. Elf64_Phdr *phdr;
  149. Elf64_Nhdr *nhdr;
  150. size_t phdr_size;
  151. void *p = ehdr, *note;
  152. int ret;
  153. ret = memcmp(ehdr->e_ident, ELFMAG, SELFMAG);
  154. FAIL_IF(ret);
  155. FAIL_IF(ehdr->e_type != ET_CORE);
  156. FAIL_IF(ehdr->e_machine != EM_PPC64);
  157. FAIL_IF(ehdr->e_phoff == 0 || ehdr->e_phnum == 0);
  158. /*
  159. * e_phnum is at most 65535 so calculating the size of the
  160. * program header cannot overflow.
  161. */
  162. phdr_size = sizeof(*phdr) * ehdr->e_phnum;
  163. /* Sanity check the program header table location. */
  164. FAIL_IF(ehdr->e_phoff + phdr_size < ehdr->e_phoff);
  165. FAIL_IF(ehdr->e_phoff + phdr_size > core_size);
  166. /* Find the PT_NOTE segment. */
  167. for (phdr = p + ehdr->e_phoff;
  168. (void *) phdr < p + ehdr->e_phoff + phdr_size;
  169. phdr += ehdr->e_phentsize)
  170. if (phdr->p_type == PT_NOTE)
  171. break;
  172. FAIL_IF((void *) phdr >= p + ehdr->e_phoff + phdr_size);
  173. /* Find the NT_PPC_PKEY note. */
  174. for (nhdr = p + phdr->p_offset;
  175. (void *) nhdr < p + phdr->p_offset + phdr->p_filesz;
  176. nhdr = next_note(nhdr))
  177. if (nhdr->n_type == NT_PPC_PKEY)
  178. break;
  179. FAIL_IF((void *) nhdr >= p + phdr->p_offset + phdr->p_filesz);
  180. FAIL_IF(nhdr->n_descsz == 0);
  181. p = nhdr;
  182. note = p + sizeof(*nhdr) + __ALIGN_KERNEL(nhdr->n_namesz, 4);
  183. regs = (unsigned long *) note;
  184. printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
  185. core_read_running, regs[0], regs[1], regs[2]);
  186. FAIL_IF(regs[0] != info->amr);
  187. FAIL_IF(regs[1] != info->iamr);
  188. FAIL_IF(regs[2] != info->uamor);
  189. return TEST_PASS;
  190. }
  191. static int parent(struct shared_info *info, pid_t pid)
  192. {
  193. char *filenames, *filename[3];
  194. int fd, i, ret, status;
  195. unsigned long regs[3];
  196. off_t core_size;
  197. void *core;
  198. /*
  199. * Get the initial values for AMR, IAMR and UAMOR and communicate them
  200. * to the child.
  201. */
  202. ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
  203. PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
  204. PARENT_FAIL_IF(ret, &info->child_sync);
  205. info->amr = regs[0];
  206. info->iamr = regs[1];
  207. info->uamor = regs[2];
  208. /* Wake up child so that it can set itself up. */
  209. ret = prod_child(&info->child_sync);
  210. PARENT_FAIL_IF(ret, &info->child_sync);
  211. ret = wait(&status);
  212. if (ret != pid) {
  213. printf("Child's exit status not captured\n");
  214. return TEST_FAIL;
  215. } else if (!WIFSIGNALED(status) || !WCOREDUMP(status)) {
  216. printf("Child didn't dump core\n");
  217. return TEST_FAIL;
  218. }
  219. /* Construct array of core file names to try. */
  220. filename[0] = filenames = malloc(PATH_MAX);
  221. if (!filenames) {
  222. perror("Error allocating memory");
  223. return TEST_FAIL;
  224. }
  225. ret = snprintf(filename[0], PATH_MAX, "core-pkey.%d", pid);
  226. if (ret < 0 || ret >= PATH_MAX) {
  227. ret = TEST_FAIL;
  228. goto out;
  229. }
  230. filename[1] = filename[0] + ret + 1;
  231. ret = snprintf(filename[1], PATH_MAX - ret - 1, "core.%d", pid);
  232. if (ret < 0 || ret >= PATH_MAX - ret - 1) {
  233. ret = TEST_FAIL;
  234. goto out;
  235. }
  236. filename[2] = "core";
  237. for (i = 0; i < 3; i++) {
  238. core_size = try_core_file(filename[i], info, pid);
  239. if (core_size != TEST_FAIL)
  240. break;
  241. }
  242. if (i == 3) {
  243. printf("Couldn't find core file\n");
  244. ret = TEST_FAIL;
  245. goto out;
  246. }
  247. fd = open(filename[i], O_RDONLY);
  248. if (fd == -1) {
  249. perror("Error opening core file");
  250. ret = TEST_FAIL;
  251. goto out;
  252. }
  253. core = mmap(NULL, core_size, PROT_READ, MAP_PRIVATE, fd, 0);
  254. if (core == (void *) -1) {
  255. perror("Error mmaping core file");
  256. ret = TEST_FAIL;
  257. goto out;
  258. }
  259. ret = check_core_file(info, core, core_size);
  260. munmap(core, core_size);
  261. close(fd);
  262. unlink(filename[i]);
  263. out:
  264. free(filenames);
  265. return ret;
  266. }
  267. static int write_core_pattern(const char *core_pattern)
  268. {
  269. size_t len = strlen(core_pattern), ret;
  270. FILE *f;
  271. f = fopen(core_pattern_file, "w");
  272. if (!f) {
  273. perror("Error writing to core_pattern file");
  274. return TEST_FAIL;
  275. }
  276. ret = fwrite(core_pattern, 1, len, f);
  277. fclose(f);
  278. if (ret != len) {
  279. perror("Error writing to core_pattern file");
  280. return TEST_FAIL;
  281. }
  282. return TEST_PASS;
  283. }
  284. static int setup_core_pattern(char **core_pattern_, bool *changed_)
  285. {
  286. FILE *f;
  287. char *core_pattern;
  288. int ret;
  289. core_pattern = malloc(PATH_MAX);
  290. if (!core_pattern) {
  291. perror("Error allocating memory");
  292. return TEST_FAIL;
  293. }
  294. f = fopen(core_pattern_file, "r");
  295. if (!f) {
  296. perror("Error opening core_pattern file");
  297. ret = TEST_FAIL;
  298. goto out;
  299. }
  300. ret = fread(core_pattern, 1, PATH_MAX, f);
  301. fclose(f);
  302. if (!ret) {
  303. perror("Error reading core_pattern file");
  304. ret = TEST_FAIL;
  305. goto out;
  306. }
  307. /* Check whether we can predict the name of the core file. */
  308. if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
  309. *changed_ = false;
  310. else {
  311. ret = write_core_pattern("core-pkey.%p");
  312. if (ret)
  313. goto out;
  314. *changed_ = true;
  315. }
  316. *core_pattern_ = core_pattern;
  317. ret = TEST_PASS;
  318. out:
  319. if (ret)
  320. free(core_pattern);
  321. return ret;
  322. }
  323. static int core_pkey(void)
  324. {
  325. char *core_pattern;
  326. bool changed_core_pattern;
  327. struct shared_info *info;
  328. int shm_id;
  329. int ret;
  330. pid_t pid;
  331. ret = setup_core_pattern(&core_pattern, &changed_core_pattern);
  332. if (ret)
  333. return ret;
  334. shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
  335. info = shmat(shm_id, NULL, 0);
  336. ret = init_child_sync(&info->child_sync);
  337. if (ret)
  338. return ret;
  339. pid = fork();
  340. if (pid < 0) {
  341. perror("fork() failed");
  342. ret = TEST_FAIL;
  343. } else if (pid == 0)
  344. ret = child(info);
  345. else
  346. ret = parent(info, pid);
  347. shmdt(info);
  348. if (pid) {
  349. destroy_child_sync(&info->child_sync);
  350. shmctl(shm_id, IPC_RMID, NULL);
  351. if (changed_core_pattern)
  352. write_core_pattern(core_pattern);
  353. }
  354. free(core_pattern);
  355. return ret;
  356. }
  357. int main(int argc, char *argv[])
  358. {
  359. return test_harness(core_pkey, "core_pkey");
  360. }