Skip to content
  • John Sperbeck's avatar
    powerpc/mm: Fix SEGV on mapped region to return SEGV_ACCERR · ecb101ae
    John Sperbeck authored
    The recent refactoring of the powerpc page fault handler in commit
    c3350602 ("powerpc/mm: Make bad_area* helper functions") caused
    access to protected memory regions to indicate SEGV_MAPERR instead of
    the traditional SEGV_ACCERR in the si_code field of a user-space
    signal handler. This can confuse debug libraries that temporarily
    change the protection of memory regions, and expect to use SEGV_ACCERR
    as an indication to restore access to a region.
    
    This commit restores the previous behavior. The following program
    exhibits the issue:
    
        $ ./repro read  || echo "FAILED"
        $ ./repro write || echo "FAILED"
        $ ./repro exec  || echo "FAILED"
    
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <unistd.h>
        #include <signal.h>
        #include <sys/mman.h>
        #include <assert.h>
    
        static void segv_handler(int n, siginfo_t *info, void *arg) {
                _exit(info->si_code == SEGV_ACCERR ? 0 : 1);
        }
    
        int main(int argc, char **argv)
        {
                void *p = NULL;
                struct sigaction act = {
                        .sa_sigaction = segv_handler,
                        .sa_flags = SA_SIGINFO,
                };
    
                assert(argc == 2);
                p = mmap(NULL, getpagesize(),
                        (strcmp(argv[1], "write") == 0) ? PROT_READ : 0,
                        MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
                assert(p != MAP_FAILED);
    
                assert(sigaction(SIGSEGV, &act, NULL) == 0);
                if (strcmp(argv[1], "read") == 0)
                        printf("%c", *(unsigned char *)p);
                else if (strcmp(argv[1], "write") == 0)
                        *(unsigned char *)p = 0;
                else if (strcmp(argv[1], "exec") == 0)
                        ((void (*)(void))p)();
                return 1;  /* failed to generate SEGV */
        }
    
    Fixes: c3350602
    
     ("powerpc/mm: Make bad_area* helper functions")
    Cc: stable@vger.kernel.org # v4.14+
    Signed-off-by: default avatarJohn Sperbeck <jsperbeck@google.com>
    Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
    [mpe: Add commit references in change log]
    Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    ecb101ae