diff --git a/mm/mincore.c b/mm/mincore.c index da2be56a7b8f..9977229bea92 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -209,6 +209,22 @@ static void mincore_page_range(struct vm_area_struct *vma, } while (pgd++, addr = next, addr != end); } +static inline bool can_do_mincore(struct vm_area_struct *vma) +{ + if (vma_is_anonymous(vma)) + return true; + if (!vma->vm_file) + return false; + /* + * Reveal pagecache information only for non-anonymous mappings that + * correspond to the files the calling process could (if tried) open + * for writing; otherwise we'd be including shared non-exclusive + * mappings, which opens a side channel. + */ + return inode_owner_or_capable(file_inode(vma->vm_file)) || + inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0; +} + /* * Do a chunk of "sys_mincore()". We've already checked * all the arguments, we hold the mmap semaphore: we should @@ -224,6 +240,11 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v return -ENOMEM; end = min(vma->vm_end, addr + (pages << PAGE_SHIFT)); + if (!can_do_mincore(vma)) { + unsigned long pages = DIV_ROUND_UP(end - addr, PAGE_SIZE); + memset(vec, 1, pages); + return pages; + } if (is_vm_hugetlb_page(vma)) { mincore_hugetlb_page_range(vma, addr, end, vec);