Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // Copyright 2019, Michael Ellerman, IBM Corp.
0004 //
0005 // Test that out-of-bounds reads/writes behave as expected.
0006 
0007 #include <setjmp.h>
0008 #include <stdbool.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <sys/types.h>
0013 #include <sys/wait.h>
0014 #include <unistd.h>
0015 
0016 #include "utils.h"
0017 
0018 // Old distros (Ubuntu 16.04 at least) don't define this
0019 #ifndef SEGV_BNDERR
0020 #define SEGV_BNDERR 3
0021 #endif
0022 
0023 // 64-bit kernel is always here
0024 #define PAGE_OFFSET (0xcul << 60)
0025 
0026 static unsigned long kernel_virt_end;
0027 
0028 static volatile int fault_code;
0029 static volatile unsigned long fault_addr;
0030 static jmp_buf setjmp_env;
0031 
0032 static void segv_handler(int n, siginfo_t *info, void *ctxt_v)
0033 {
0034     fault_code = info->si_code;
0035     fault_addr = (unsigned long)info->si_addr;
0036     siglongjmp(setjmp_env, 1);
0037 }
0038 
0039 int bad_access(char *p, bool write)
0040 {
0041     char x = 0;
0042 
0043     fault_code = 0;
0044     fault_addr = 0;
0045 
0046     if (sigsetjmp(setjmp_env, 1) == 0) {
0047         if (write)
0048             *p = 1;
0049         else
0050             x = *p;
0051 
0052         printf("Bad - no SEGV! (%c)\n", x);
0053         return 1;
0054     }
0055 
0056     // If we see MAPERR that means we took a page fault rather than an SLB
0057     // miss. We only expect to take page faults for addresses within the
0058     // valid kernel range.
0059     FAIL_IF(fault_code == SEGV_MAPERR && \
0060         (fault_addr < PAGE_OFFSET || fault_addr >= kernel_virt_end));
0061 
0062     FAIL_IF(fault_code != SEGV_MAPERR && fault_code != SEGV_BNDERR);
0063 
0064     return 0;
0065 }
0066 
0067 static int test(void)
0068 {
0069     unsigned long i, j, addr, region_shift, page_shift, page_size;
0070     struct sigaction sig;
0071     bool hash_mmu;
0072 
0073     sig = (struct sigaction) {
0074         .sa_sigaction = segv_handler,
0075         .sa_flags = SA_SIGINFO,
0076     };
0077 
0078     FAIL_IF(sigaction(SIGSEGV, &sig, NULL) != 0);
0079 
0080     FAIL_IF(using_hash_mmu(&hash_mmu));
0081 
0082     page_size = sysconf(_SC_PAGESIZE);
0083     if (page_size == (64 * 1024))
0084         page_shift = 16;
0085     else
0086         page_shift = 12;
0087 
0088     if (page_size == (64 * 1024) || !hash_mmu) {
0089         region_shift = 52;
0090 
0091         // We have 7 512T regions (4 kernel linear, vmalloc, io, vmemmap)
0092         kernel_virt_end = PAGE_OFFSET + (7 * (512ul << 40));
0093     } else if (page_size == (4 * 1024) && hash_mmu) {
0094         region_shift = 46;
0095 
0096         // We have 7 64T regions (4 kernel linear, vmalloc, io, vmemmap)
0097         kernel_virt_end = PAGE_OFFSET + (7 * (64ul << 40));
0098     } else
0099         FAIL_IF(true);
0100 
0101     printf("Using %s MMU, PAGE_SIZE = %dKB start address 0x%016lx\n",
0102            hash_mmu ? "hash" : "radix",
0103            (1 << page_shift) >> 10,
0104            1ul << region_shift);
0105 
0106     // This generates access patterns like:
0107     //   0x0010000000000000
0108     //   0x0010000000010000
0109     //   0x0010000000020000
0110     //   ...
0111     //   0x0014000000000000
0112     //   0x0018000000000000
0113     //   0x0020000000000000
0114     //   0x0020000000010000
0115     //   0x0020000000020000
0116     //   ...
0117     //   0xf400000000000000
0118     //   0xf800000000000000
0119 
0120     for (i = 1; i <= ((0xful << 60) >> region_shift); i++) {
0121         for (j = page_shift - 1; j < 60; j++) {
0122             unsigned long base, delta;
0123 
0124             base  = i << region_shift;
0125             delta = 1ul << j;
0126 
0127             if (delta >= base)
0128                 break;
0129 
0130             addr = (base | delta) & ~((1 << page_shift) - 1);
0131 
0132             FAIL_IF(bad_access((char *)addr, false));
0133             FAIL_IF(bad_access((char *)addr, true));
0134         }
0135     }
0136 
0137     return 0;
0138 }
0139 
0140 int main(void)
0141 {
0142     test_harness_set_timeout(300);
0143     return test_harness(test, "bad_accesses");
0144 }