Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Ptrace test for Memory Protection Key registers
0004  *
0005  * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
0006  * Copyright (C) 2018 IBM Corporation.
0007  */
0008 #include "ptrace.h"
0009 #include "child.h"
0010 
0011 #ifndef __NR_pkey_alloc
0012 #define __NR_pkey_alloc     384
0013 #endif
0014 
0015 #ifndef __NR_pkey_free
0016 #define __NR_pkey_free      385
0017 #endif
0018 
0019 #ifndef NT_PPC_PKEY
0020 #define NT_PPC_PKEY     0x110
0021 #endif
0022 
0023 #ifndef PKEY_DISABLE_EXECUTE
0024 #define PKEY_DISABLE_EXECUTE    0x4
0025 #endif
0026 
0027 #define AMR_BITS_PER_PKEY 2
0028 #define PKEY_REG_BITS (sizeof(u64) * 8)
0029 #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
0030 
0031 static const char user_read[] = "[User Read (Running)]";
0032 static const char user_write[] = "[User Write (Running)]";
0033 static const char ptrace_read_running[] = "[Ptrace Read (Running)]";
0034 static const char ptrace_write_running[] = "[Ptrace Write (Running)]";
0035 
0036 /* Information shared between the parent and the child. */
0037 struct shared_info {
0038     struct child_sync child_sync;
0039 
0040     /* AMR value the parent expects to read from the child. */
0041     unsigned long amr1;
0042 
0043     /* AMR value the parent is expected to write to the child. */
0044     unsigned long amr2;
0045 
0046     /* AMR value that ptrace should refuse to write to the child. */
0047     unsigned long invalid_amr;
0048 
0049     /* IAMR value the parent expects to read from the child. */
0050     unsigned long expected_iamr;
0051 
0052     /* UAMOR value the parent expects to read from the child. */
0053     unsigned long expected_uamor;
0054 
0055     /*
0056      * IAMR and UAMOR values that ptrace should refuse to write to the child
0057      * (even though they're valid ones) because userspace doesn't have
0058      * access to those registers.
0059      */
0060     unsigned long invalid_iamr;
0061     unsigned long invalid_uamor;
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 child(struct shared_info *info)
0070 {
0071     unsigned long reg;
0072     bool disable_execute = true;
0073     int pkey1, pkey2, pkey3;
0074     int ret;
0075 
0076     /* Wait until parent fills out the initial register values. */
0077     ret = wait_parent(&info->child_sync);
0078     if (ret)
0079         return ret;
0080 
0081     /* Get some pkeys so that we can change their bits in the AMR. */
0082     pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
0083     if (pkey1 < 0) {
0084         pkey1 = sys_pkey_alloc(0, 0);
0085         CHILD_FAIL_IF(pkey1 < 0, &info->child_sync);
0086 
0087         disable_execute = false;
0088     }
0089 
0090     pkey2 = sys_pkey_alloc(0, 0);
0091     CHILD_FAIL_IF(pkey2 < 0, &info->child_sync);
0092 
0093     pkey3 = sys_pkey_alloc(0, 0);
0094     CHILD_FAIL_IF(pkey3 < 0, &info->child_sync);
0095 
0096     info->amr1 |= 3ul << pkeyshift(pkey1);
0097     info->amr2 |= 3ul << pkeyshift(pkey2);
0098     /*
0099      * invalid amr value where we try to force write
0100      * things which are deined by a uamor setting.
0101      */
0102     info->invalid_amr = info->amr2 | (~0x0UL & ~info->expected_uamor);
0103 
0104     /*
0105      * if PKEY_DISABLE_EXECUTE succeeded we should update the expected_iamr
0106      */
0107     if (disable_execute)
0108         info->expected_iamr |= 1ul << pkeyshift(pkey1);
0109     else
0110         info->expected_iamr &= ~(1ul << pkeyshift(pkey1));
0111 
0112     /*
0113      * We allocated pkey2 and pkey 3 above. Clear the IAMR bits.
0114      */
0115     info->expected_iamr &= ~(1ul << pkeyshift(pkey2));
0116     info->expected_iamr &= ~(1ul << pkeyshift(pkey3));
0117 
0118     /*
0119      * Create an IAMR value different from expected value.
0120      * Kernel will reject an IAMR and UAMOR change.
0121      */
0122     info->invalid_iamr = info->expected_iamr | (1ul << pkeyshift(pkey1) | 1ul << pkeyshift(pkey2));
0123     info->invalid_uamor = info->expected_uamor & ~(0x3ul << pkeyshift(pkey1));
0124 
0125     printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
0126            user_write, info->amr1, pkey1, pkey2, pkey3);
0127 
0128     set_amr(info->amr1);
0129 
0130     /* Wait for parent to read our AMR value and write a new one. */
0131     ret = prod_parent(&info->child_sync);
0132     CHILD_FAIL_IF(ret, &info->child_sync);
0133 
0134     ret = wait_parent(&info->child_sync);
0135     if (ret)
0136         return ret;
0137 
0138     reg = mfspr(SPRN_AMR);
0139 
0140     printf("%-30s AMR: %016lx\n", user_read, reg);
0141 
0142     CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
0143 
0144     /*
0145      * Wait for parent to try to write an invalid AMR value.
0146      */
0147     ret = prod_parent(&info->child_sync);
0148     CHILD_FAIL_IF(ret, &info->child_sync);
0149 
0150     ret = wait_parent(&info->child_sync);
0151     if (ret)
0152         return ret;
0153 
0154     reg = mfspr(SPRN_AMR);
0155 
0156     printf("%-30s AMR: %016lx\n", user_read, reg);
0157 
0158     CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
0159 
0160     /*
0161      * Wait for parent to try to write an IAMR and a UAMOR value. We can't
0162      * verify them, but we can verify that the AMR didn't change.
0163      */
0164     ret = prod_parent(&info->child_sync);
0165     CHILD_FAIL_IF(ret, &info->child_sync);
0166 
0167     ret = wait_parent(&info->child_sync);
0168     if (ret)
0169         return ret;
0170 
0171     reg = mfspr(SPRN_AMR);
0172 
0173     printf("%-30s AMR: %016lx\n", user_read, reg);
0174 
0175     CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
0176 
0177     /* Now let parent now that we are finished. */
0178 
0179     ret = prod_parent(&info->child_sync);
0180     CHILD_FAIL_IF(ret, &info->child_sync);
0181 
0182     return TEST_PASS;
0183 }
0184 
0185 static int parent(struct shared_info *info, pid_t pid)
0186 {
0187     unsigned long regs[3];
0188     int ret, status;
0189 
0190     /*
0191      * Get the initial values for AMR, IAMR and UAMOR and communicate them
0192      * to the child.
0193      */
0194     ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
0195     PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
0196     PARENT_FAIL_IF(ret, &info->child_sync);
0197 
0198     info->amr1 = info->amr2 = regs[0];
0199     info->expected_iamr = regs[1];
0200     info->expected_uamor = regs[2];
0201 
0202     /* Wake up child so that it can set itself up. */
0203     ret = prod_child(&info->child_sync);
0204     PARENT_FAIL_IF(ret, &info->child_sync);
0205 
0206     ret = wait_child(&info->child_sync);
0207     if (ret)
0208         return ret;
0209 
0210     /* Verify that we can read the pkey registers from the child. */
0211     ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
0212     PARENT_FAIL_IF(ret, &info->child_sync);
0213 
0214     printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
0215            ptrace_read_running, regs[0], regs[1], regs[2]);
0216 
0217     PARENT_FAIL_IF(regs[0] != info->amr1, &info->child_sync);
0218     PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
0219     PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
0220 
0221     /* Write valid AMR value in child. */
0222     ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr2, 1);
0223     PARENT_FAIL_IF(ret, &info->child_sync);
0224 
0225     printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr2);
0226 
0227     /* Wake up child so that it can verify it changed. */
0228     ret = prod_child(&info->child_sync);
0229     PARENT_FAIL_IF(ret, &info->child_sync);
0230 
0231     ret = wait_child(&info->child_sync);
0232     if (ret)
0233         return ret;
0234 
0235     /* Write invalid AMR value in child. */
0236     ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->invalid_amr, 1);
0237     PARENT_FAIL_IF(ret, &info->child_sync);
0238 
0239     printf("%-30s AMR: %016lx\n", ptrace_write_running, info->invalid_amr);
0240 
0241     /* Wake up child so that it can verify it didn't change. */
0242     ret = prod_child(&info->child_sync);
0243     PARENT_FAIL_IF(ret, &info->child_sync);
0244 
0245     ret = wait_child(&info->child_sync);
0246     if (ret)
0247         return ret;
0248 
0249     /* Try to write to IAMR. */
0250     regs[0] = info->amr1;
0251     regs[1] = info->invalid_iamr;
0252     ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 2);
0253     PARENT_FAIL_IF(!ret, &info->child_sync);
0254 
0255     printf("%-30s AMR: %016lx IAMR: %016lx\n",
0256            ptrace_write_running, regs[0], regs[1]);
0257 
0258     /* Try to write to IAMR and UAMOR. */
0259     regs[2] = info->invalid_uamor;
0260     ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 3);
0261     PARENT_FAIL_IF(!ret, &info->child_sync);
0262 
0263     printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
0264            ptrace_write_running, regs[0], regs[1], regs[2]);
0265 
0266     /* Verify that all registers still have their expected values. */
0267     ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
0268     PARENT_FAIL_IF(ret, &info->child_sync);
0269 
0270     printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
0271            ptrace_read_running, regs[0], regs[1], regs[2]);
0272 
0273     PARENT_FAIL_IF(regs[0] != info->amr2, &info->child_sync);
0274     PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
0275     PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
0276 
0277     /* Wake up child so that it can verify AMR didn't change and wrap up. */
0278     ret = prod_child(&info->child_sync);
0279     PARENT_FAIL_IF(ret, &info->child_sync);
0280 
0281     ret = wait(&status);
0282     if (ret != pid) {
0283         printf("Child's exit status not captured\n");
0284         ret = TEST_PASS;
0285     } else if (!WIFEXITED(status)) {
0286         printf("Child exited abnormally\n");
0287         ret = TEST_FAIL;
0288     } else
0289         ret = WEXITSTATUS(status) ? TEST_FAIL : TEST_PASS;
0290 
0291     return ret;
0292 }
0293 
0294 static int ptrace_pkey(void)
0295 {
0296     struct shared_info *info;
0297     int shm_id;
0298     int ret;
0299     pid_t pid;
0300 
0301     shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
0302     info = shmat(shm_id, NULL, 0);
0303 
0304     ret = init_child_sync(&info->child_sync);
0305     if (ret)
0306         return ret;
0307 
0308     pid = fork();
0309     if (pid < 0) {
0310         perror("fork() failed");
0311         ret = TEST_FAIL;
0312     } else if (pid == 0)
0313         ret = child(info);
0314     else
0315         ret = parent(info, pid);
0316 
0317     shmdt(info);
0318 
0319     if (pid) {
0320         destroy_child_sync(&info->child_sync);
0321         shmctl(shm_id, IPC_RMID, NULL);
0322     }
0323 
0324     return ret;
0325 }
0326 
0327 int main(int argc, char *argv[])
0328 {
0329     return test_harness(ptrace_pkey, "ptrace_pkey");
0330 }