• Greg Hackmann's avatar
    arm64: mm: check for upper PAGE_SHIFT bits in pfn_valid() · 355cccb6
    Greg Hackmann authored
    commit 5ad356ea upstream.
    
    ARM64's pfn_valid() shifts away the upper PAGE_SHIFT bits of the input
    before seeing if the PFN is valid.  This leads to false positives when
    some of the upper bits are set, but the lower bits match a valid PFN.
    
    For example, the following userspace code looks up a bogus entry in
    /proc/kpageflags:
    
        int pagemap = open("/proc/self/pagemap", O_RDONLY);
        int pageflags = open("/proc/kpageflags", O_RDONLY);
        uint64_t pfn, val;
    
        lseek64(pagemap, [...], SEEK_SET);
        read(pagemap, &pfn, sizeof(pfn));
        if (pfn & (1UL << 63)) {        /* valid PFN */
            pfn &= ((1UL << 55) - 1);   /* clear flag bits */
            pfn |= (1UL << 55);
            lseek64(pageflags, pfn * sizeof(uint64_t), SEEK_SET);
            read(pageflags, &val, sizeof(val));
        }
    
    On ARM64 this causes the userspace process to crash with SIGSEGV rather
    than reading (1 << KPF_NOPAGE).  kpageflags_read() treats the offset as
    valid, and stable_page_flags() will try to access an address between the
    user and kernel address ranges.
    
    Fixes: c1cc1552 ("arm64: MMU initialisation")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarGreg Hackmann <ghackmann@google.com>
    Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    355cccb6
init.c 9.73 KB