0001
0002
0003
0004
0005
0006
0007
0008 #include <limits.h>
0009 #include <linux/kernel.h>
0010 #include <sys/mman.h>
0011 #include <sys/types.h>
0012 #include <sys/stat.h>
0013 #include <sys/time.h>
0014 #include <sys/resource.h>
0015 #include <fcntl.h>
0016 #include <unistd.h>
0017 #include "ptrace.h"
0018 #include "child.h"
0019
0020 #ifndef __NR_pkey_alloc
0021 #define __NR_pkey_alloc 384
0022 #endif
0023
0024 #ifndef __NR_pkey_free
0025 #define __NR_pkey_free 385
0026 #endif
0027
0028 #ifndef NT_PPC_PKEY
0029 #define NT_PPC_PKEY 0x110
0030 #endif
0031
0032 #ifndef PKEY_DISABLE_EXECUTE
0033 #define PKEY_DISABLE_EXECUTE 0x4
0034 #endif
0035
0036 #define AMR_BITS_PER_PKEY 2
0037 #define PKEY_REG_BITS (sizeof(u64) * 8)
0038 #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
0039
0040 #define CORE_FILE_LIMIT (5 * 1024 * 1024)
0041
0042 static const char core_pattern_file[] = "/proc/sys/kernel/core_pattern";
0043
0044 static const char user_write[] = "[User Write (Running)]";
0045 static const char core_read_running[] = "[Core Read (Running)]";
0046
0047
0048 struct shared_info {
0049 struct child_sync child_sync;
0050
0051
0052 unsigned long amr;
0053
0054
0055 unsigned long iamr;
0056
0057
0058 unsigned long uamor;
0059
0060
0061 time_t core_time;
0062 };
0063
0064 static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
0065 {
0066 return syscall(__NR_pkey_alloc, flags, init_access_rights);
0067 }
0068
0069 static int sys_pkey_free(int pkey)
0070 {
0071 return syscall(__NR_pkey_free, pkey);
0072 }
0073
0074 static int increase_core_file_limit(void)
0075 {
0076 struct rlimit rlim;
0077 int ret;
0078
0079 ret = getrlimit(RLIMIT_CORE, &rlim);
0080 FAIL_IF(ret);
0081
0082 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
0083 rlim.rlim_cur = CORE_FILE_LIMIT;
0084
0085 if (rlim.rlim_max != RLIM_INFINITY &&
0086 rlim.rlim_max < CORE_FILE_LIMIT)
0087 rlim.rlim_max = CORE_FILE_LIMIT;
0088
0089 ret = setrlimit(RLIMIT_CORE, &rlim);
0090 FAIL_IF(ret);
0091 }
0092
0093 ret = getrlimit(RLIMIT_FSIZE, &rlim);
0094 FAIL_IF(ret);
0095
0096 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
0097 rlim.rlim_cur = CORE_FILE_LIMIT;
0098
0099 if (rlim.rlim_max != RLIM_INFINITY &&
0100 rlim.rlim_max < CORE_FILE_LIMIT)
0101 rlim.rlim_max = CORE_FILE_LIMIT;
0102
0103 ret = setrlimit(RLIMIT_FSIZE, &rlim);
0104 FAIL_IF(ret);
0105 }
0106
0107 return TEST_PASS;
0108 }
0109
0110 static int child(struct shared_info *info)
0111 {
0112 bool disable_execute = true;
0113 int pkey1, pkey2, pkey3;
0114 int *ptr, ret;
0115
0116
0117 ret = wait_parent(&info->child_sync);
0118 if (ret)
0119 return ret;
0120
0121 ret = increase_core_file_limit();
0122 FAIL_IF(ret);
0123
0124
0125 pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
0126 if (pkey1 < 0) {
0127 pkey1 = sys_pkey_alloc(0, 0);
0128 FAIL_IF(pkey1 < 0);
0129
0130 disable_execute = false;
0131 }
0132
0133 pkey2 = sys_pkey_alloc(0, 0);
0134 FAIL_IF(pkey2 < 0);
0135
0136 pkey3 = sys_pkey_alloc(0, 0);
0137 FAIL_IF(pkey3 < 0);
0138
0139 info->amr |= 3ul << pkeyshift(pkey1) | 2ul << pkeyshift(pkey2);
0140
0141 if (disable_execute)
0142 info->iamr |= 1ul << pkeyshift(pkey1);
0143 else
0144 info->iamr &= ~(1ul << pkeyshift(pkey1));
0145
0146 info->iamr &= ~(1ul << pkeyshift(pkey2) | 1ul << pkeyshift(pkey3));
0147
0148 info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2);
0149
0150 printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
0151 user_write, info->amr, pkey1, pkey2, pkey3);
0152
0153 set_amr(info->amr);
0154
0155
0156
0157
0158
0159 sys_pkey_free(pkey3);
0160
0161 info->core_time = time(NULL);
0162
0163
0164 ptr = 0;
0165 *ptr = 1;
0166
0167
0168 FAIL_IF(true);
0169
0170 return TEST_FAIL;
0171 }
0172
0173
0174 static off_t try_core_file(const char *filename, struct shared_info *info,
0175 pid_t pid)
0176 {
0177 struct stat buf;
0178 int ret;
0179
0180 ret = stat(filename, &buf);
0181 if (ret == -1)
0182 return TEST_FAIL;
0183
0184
0185 return buf.st_mtime >= info->core_time ? buf.st_size : TEST_FAIL;
0186 }
0187
0188 static Elf64_Nhdr *next_note(Elf64_Nhdr *nhdr)
0189 {
0190 return (void *) nhdr + sizeof(*nhdr) +
0191 __ALIGN_KERNEL(nhdr->n_namesz, 4) +
0192 __ALIGN_KERNEL(nhdr->n_descsz, 4);
0193 }
0194
0195 static int check_core_file(struct shared_info *info, Elf64_Ehdr *ehdr,
0196 off_t core_size)
0197 {
0198 unsigned long *regs;
0199 Elf64_Phdr *phdr;
0200 Elf64_Nhdr *nhdr;
0201 size_t phdr_size;
0202 void *p = ehdr, *note;
0203 int ret;
0204
0205 ret = memcmp(ehdr->e_ident, ELFMAG, SELFMAG);
0206 FAIL_IF(ret);
0207
0208 FAIL_IF(ehdr->e_type != ET_CORE);
0209 FAIL_IF(ehdr->e_machine != EM_PPC64);
0210 FAIL_IF(ehdr->e_phoff == 0 || ehdr->e_phnum == 0);
0211
0212
0213
0214
0215
0216 phdr_size = sizeof(*phdr) * ehdr->e_phnum;
0217
0218
0219 FAIL_IF(ehdr->e_phoff + phdr_size < ehdr->e_phoff);
0220 FAIL_IF(ehdr->e_phoff + phdr_size > core_size);
0221
0222
0223 for (phdr = p + ehdr->e_phoff;
0224 (void *) phdr < p + ehdr->e_phoff + phdr_size;
0225 phdr += ehdr->e_phentsize)
0226 if (phdr->p_type == PT_NOTE)
0227 break;
0228
0229 FAIL_IF((void *) phdr >= p + ehdr->e_phoff + phdr_size);
0230
0231
0232 for (nhdr = p + phdr->p_offset;
0233 (void *) nhdr < p + phdr->p_offset + phdr->p_filesz;
0234 nhdr = next_note(nhdr))
0235 if (nhdr->n_type == NT_PPC_PKEY)
0236 break;
0237
0238 FAIL_IF((void *) nhdr >= p + phdr->p_offset + phdr->p_filesz);
0239 FAIL_IF(nhdr->n_descsz == 0);
0240
0241 p = nhdr;
0242 note = p + sizeof(*nhdr) + __ALIGN_KERNEL(nhdr->n_namesz, 4);
0243
0244 regs = (unsigned long *) note;
0245
0246 printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
0247 core_read_running, regs[0], regs[1], regs[2]);
0248
0249 FAIL_IF(regs[0] != info->amr);
0250 FAIL_IF(regs[1] != info->iamr);
0251 FAIL_IF(regs[2] != info->uamor);
0252
0253 return TEST_PASS;
0254 }
0255
0256 static int parent(struct shared_info *info, pid_t pid)
0257 {
0258 char *filenames, *filename[3];
0259 int fd, i, ret, status;
0260 unsigned long regs[3];
0261 off_t core_size;
0262 void *core;
0263
0264
0265
0266
0267
0268 ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
0269 PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
0270 PARENT_FAIL_IF(ret, &info->child_sync);
0271
0272 info->amr = regs[0];
0273 info->iamr = regs[1];
0274 info->uamor = regs[2];
0275
0276
0277 ret = prod_child(&info->child_sync);
0278 PARENT_FAIL_IF(ret, &info->child_sync);
0279
0280 ret = wait(&status);
0281 if (ret != pid) {
0282 printf("Child's exit status not captured\n");
0283 return TEST_FAIL;
0284 } else if (!WIFSIGNALED(status) || !WCOREDUMP(status)) {
0285 printf("Child didn't dump core\n");
0286 return TEST_FAIL;
0287 }
0288
0289
0290
0291 filename[0] = filenames = malloc(PATH_MAX);
0292 if (!filenames) {
0293 perror("Error allocating memory");
0294 return TEST_FAIL;
0295 }
0296
0297 ret = snprintf(filename[0], PATH_MAX, "core-pkey.%d", pid);
0298 if (ret < 0 || ret >= PATH_MAX) {
0299 ret = TEST_FAIL;
0300 goto out;
0301 }
0302
0303 filename[1] = filename[0] + ret + 1;
0304 ret = snprintf(filename[1], PATH_MAX - ret - 1, "core.%d", pid);
0305 if (ret < 0 || ret >= PATH_MAX - ret - 1) {
0306 ret = TEST_FAIL;
0307 goto out;
0308 }
0309 filename[2] = "core";
0310
0311 for (i = 0; i < 3; i++) {
0312 core_size = try_core_file(filename[i], info, pid);
0313 if (core_size != TEST_FAIL)
0314 break;
0315 }
0316
0317 if (i == 3) {
0318 printf("Couldn't find core file\n");
0319 ret = TEST_FAIL;
0320 goto out;
0321 }
0322
0323 fd = open(filename[i], O_RDONLY);
0324 if (fd == -1) {
0325 perror("Error opening core file");
0326 ret = TEST_FAIL;
0327 goto out;
0328 }
0329
0330 core = mmap(NULL, core_size, PROT_READ, MAP_PRIVATE, fd, 0);
0331 if (core == (void *) -1) {
0332 perror("Error mmaping core file");
0333 ret = TEST_FAIL;
0334 goto out;
0335 }
0336
0337 ret = check_core_file(info, core, core_size);
0338
0339 munmap(core, core_size);
0340 close(fd);
0341 unlink(filename[i]);
0342
0343 out:
0344 free(filenames);
0345
0346 return ret;
0347 }
0348
0349 static int write_core_pattern(const char *core_pattern)
0350 {
0351 size_t len = strlen(core_pattern), ret;
0352 FILE *f;
0353
0354 f = fopen(core_pattern_file, "w");
0355 SKIP_IF_MSG(!f, "Try with root privileges");
0356
0357 ret = fwrite(core_pattern, 1, len, f);
0358 fclose(f);
0359 if (ret != len) {
0360 perror("Error writing to core_pattern file");
0361 return TEST_FAIL;
0362 }
0363
0364 return TEST_PASS;
0365 }
0366
0367 static int setup_core_pattern(char **core_pattern_, bool *changed_)
0368 {
0369 FILE *f;
0370 char *core_pattern;
0371 int ret;
0372
0373 core_pattern = malloc(PATH_MAX);
0374 if (!core_pattern) {
0375 perror("Error allocating memory");
0376 return TEST_FAIL;
0377 }
0378
0379 f = fopen(core_pattern_file, "r");
0380 if (!f) {
0381 perror("Error opening core_pattern file");
0382 ret = TEST_FAIL;
0383 goto out;
0384 }
0385
0386 ret = fread(core_pattern, 1, PATH_MAX, f);
0387 fclose(f);
0388 if (!ret) {
0389 perror("Error reading core_pattern file");
0390 ret = TEST_FAIL;
0391 goto out;
0392 }
0393
0394
0395 if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
0396 *changed_ = false;
0397 else {
0398 ret = write_core_pattern("core-pkey.%p");
0399 if (ret)
0400 goto out;
0401
0402 *changed_ = true;
0403 }
0404
0405 *core_pattern_ = core_pattern;
0406 ret = TEST_PASS;
0407
0408 out:
0409 if (ret)
0410 free(core_pattern);
0411
0412 return ret;
0413 }
0414
0415 static int core_pkey(void)
0416 {
0417 char *core_pattern;
0418 bool changed_core_pattern;
0419 struct shared_info *info;
0420 int shm_id;
0421 int ret;
0422 pid_t pid;
0423
0424 ret = setup_core_pattern(&core_pattern, &changed_core_pattern);
0425 if (ret)
0426 return ret;
0427
0428 shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
0429 info = shmat(shm_id, NULL, 0);
0430
0431 ret = init_child_sync(&info->child_sync);
0432 if (ret)
0433 return ret;
0434
0435 pid = fork();
0436 if (pid < 0) {
0437 perror("fork() failed");
0438 ret = TEST_FAIL;
0439 } else if (pid == 0)
0440 ret = child(info);
0441 else
0442 ret = parent(info, pid);
0443
0444 shmdt(info);
0445
0446 if (pid) {
0447 destroy_child_sync(&info->child_sync);
0448 shmctl(shm_id, IPC_RMID, NULL);
0449
0450 if (changed_core_pattern)
0451 write_core_pattern(core_pattern);
0452 }
0453
0454 free(core_pattern);
0455
0456 return ret;
0457 }
0458
0459 int main(int argc, char *argv[])
0460 {
0461 return test_harness(core_pkey, "core_pkey");
0462 }