lkml.org 
[lkml]   [2020]   [Nov]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip: x86/sgx] mm: Add 'mprotect' hook to struct vm_operations_struct
    The following commit has been merged into the x86/sgx branch of tip:

    Commit-ID: 95bb7c42ac8a94ce3d0eb059ad64430390351ccb
    Gitweb: https://git.kernel.org/tip/95bb7c42ac8a94ce3d0eb059ad64430390351ccb
    Author: Sean Christopherson <sean.j.christopherson@intel.com>
    AuthorDate: Fri, 13 Nov 2020 00:01:21 +02:00
    Committer: Borislav Petkov <bp@suse.de>
    CommitterDate: Tue, 17 Nov 2020 14:36:14 +01:00

    mm: Add 'mprotect' hook to struct vm_operations_struct

    Background
    ==========

    1. SGX enclave pages are populated with data by copying from normal memory
    via ioctl() (SGX_IOC_ENCLAVE_ADD_PAGES), which will be added later in
    this series.
    2. It is desirable to be able to restrict those normal memory data sources.
    For instance, to ensure that the source data is executable before
    copying data to an executable enclave page.
    3. Enclave page permissions are dynamic (just like normal permissions) and
    can be adjusted at runtime with mprotect().

    This creates a problem because the original data source may have long since
    vanished at the time when enclave page permissions are established (mmap()
    or mprotect()).

    The solution (elsewhere in this series) is to force enclave creators to
    declare their paging permission *intent* up front to the ioctl(). This
    intent can be immediately compared to the source data’s mapping and
    rejected if necessary.

    The “intent” is also stashed off for later comparison with enclave
    PTEs. This ensures that any future mmap()/mprotect() operations
    performed by the enclave creator or done on behalf of the enclave
    can be compared with the earlier declared permissions.

    Problem
    =======

    There is an existing mmap() hook which allows SGX to perform this
    permission comparison at mmap() time. However, there is no corresponding
    ->mprotect() hook.

    Solution
    ========

    Add a vm_ops->mprotect() hook so that mprotect() operations which are
    inconsistent with any page's stashed intent can be rejected by the driver.

    Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
    Co-developed-by: Jarkko Sakkinen <jarkko@kernel.org>
    Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
    Signed-off-by: Borislav Petkov <bp@suse.de>
    Acked-by: Jethro Beekman <jethro@fortanix.com>
    Acked-by: Dave Hansen <dave.hansen@intel.com>
    Acked-by: Mel Gorman <mgorman@techsingularity.net>
    Acked-by: Hillf Danton <hdanton@sina.com>
    Cc: linux-mm@kvack.org
    Link: https://lkml.kernel.org/r/20201112220135.165028-11-jarkko@kernel.org
    ---
    include/linux/mm.h | 7 +++++++
    mm/mprotect.c | 7 +++++++
    2 files changed, 14 insertions(+)

    diff --git a/include/linux/mm.h b/include/linux/mm.h
    index db6ae4d..1813fa8 100644
    --- a/include/linux/mm.h
    +++ b/include/linux/mm.h
    @@ -559,6 +559,13 @@ struct vm_operations_struct {
    void (*close)(struct vm_area_struct * area);
    int (*split)(struct vm_area_struct * area, unsigned long addr);
    int (*mremap)(struct vm_area_struct * area);
    + /*
    + * Called by mprotect() to make driver-specific permission
    + * checks before mprotect() is finalised. The VMA must not
    + * be modified. Returns 0 if eprotect() can proceed.
    + */
    + int (*mprotect)(struct vm_area_struct *vma, unsigned long start,
    + unsigned long end, unsigned long newflags);
    vm_fault_t (*fault)(struct vm_fault *vmf);
    vm_fault_t (*huge_fault)(struct vm_fault *vmf,
    enum page_entry_size pe_size);
    diff --git a/mm/mprotect.c b/mm/mprotect.c
    index 56c02be..ab70902 100644
    --- a/mm/mprotect.c
    +++ b/mm/mprotect.c
    @@ -616,9 +616,16 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
    tmp = vma->vm_end;
    if (tmp > end)
    tmp = end;
    +
    + if (vma->vm_ops && vma->vm_ops->mprotect)
    + error = vma->vm_ops->mprotect(vma, nstart, tmp, newflags);
    + if (error)
    + goto out;
    +
    error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
    if (error)
    goto out;
    +
    nstart = tmp;

    if (nstart < prev->vm_end)
    \
     
     \ /
      Last update: 2020-11-18 18:39    [W:4.571 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site