Skip to content

Commit 1e98779

Browse files
hansendcIngo Molnar
authored andcommitted
mm/gup: Introduce get_user_pages_remote()
For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations. This patch introduces a new get_user_pages() variant: get_user_pages_remote() Which is a replacement for when get_user_pages() is called on non-current tsk/mm. We also introduce a new gup flag: FOLL_REMOTE which can be used for the "__" gup variants to get this new behavior. The uprobes is_trap_at_addr() location holds mmap_sem and calls get_user_pages(current->mm) on an instruction address. This makes it a pretty unique gup caller. Being an instruction access and also really originating from the kernel (vs. the app), I opted to consider this a 'remote' access where protection keys will not be enforced. Without protection keys, this patch should not change any behavior. Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Srikar Dronamraju <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: [email protected] Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 1fe3f29 commit 1e98779

File tree

11 files changed

+77
-27
lines changed

11 files changed

+77
-27
lines changed

drivers/gpu/drm/etnaviv/etnaviv_gem.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,9 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
753753

754754
down_read(&mm->mmap_sem);
755755
while (pinned < npages) {
756-
ret = get_user_pages(task, mm, ptr, npages - pinned,
757-
!etnaviv_obj->userptr.ro, 0,
758-
pvec + pinned, NULL);
756+
ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
757+
!etnaviv_obj->userptr.ro, 0,
758+
pvec + pinned, NULL);
759759
if (ret < 0)
760760
break;
761761

drivers/gpu/drm/i915/i915_gem_userptr.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -584,11 +584,11 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
584584

585585
down_read(&mm->mmap_sem);
586586
while (pinned < npages) {
587-
ret = get_user_pages(work->task, mm,
588-
obj->userptr.ptr + pinned * PAGE_SIZE,
589-
npages - pinned,
590-
!obj->userptr.read_only, 0,
591-
pvec + pinned, NULL);
587+
ret = get_user_pages_remote(work->task, mm,
588+
obj->userptr.ptr + pinned * PAGE_SIZE,
589+
npages - pinned,
590+
!obj->userptr.read_only, 0,
591+
pvec + pinned, NULL);
592592
if (ret < 0)
593593
break;
594594

drivers/infiniband/core/umem_odp.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -572,10 +572,10 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
572572
* complex (and doesn't gain us much performance in most use
573573
* cases).
574574
*/
575-
npages = get_user_pages(owning_process, owning_mm, user_virt,
576-
gup_num_pages,
577-
access_mask & ODP_WRITE_ALLOWED_BIT, 0,
578-
local_page_list, NULL);
575+
npages = get_user_pages_remote(owning_process, owning_mm,
576+
user_virt, gup_num_pages,
577+
access_mask & ODP_WRITE_ALLOWED_BIT,
578+
0, local_page_list, NULL);
579579
up_read(&owning_mm->mmap_sem);
580580

581581
if (npages < 0)

fs/exec.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,12 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
198198
return NULL;
199199
}
200200
#endif
201-
ret = get_user_pages(current, bprm->mm, pos,
202-
1, write, 1, &page, NULL);
201+
/*
202+
* We are doing an exec(). 'current' is the process
203+
* doing the exec and bprm->mm is the new process's mm.
204+
*/
205+
ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
206+
1, &page, NULL);
203207
if (ret <= 0)
204208
return NULL;
205209

include/linux/mm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,10 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
12251225
unsigned long start, unsigned long nr_pages,
12261226
unsigned int foll_flags, struct page **pages,
12271227
struct vm_area_struct **vmas, int *nonblocking);
1228+
long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
1229+
unsigned long start, unsigned long nr_pages,
1230+
int write, int force, struct page **pages,
1231+
struct vm_area_struct **vmas);
12281232
long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
12291233
unsigned long start, unsigned long nr_pages,
12301234
int write, int force, struct page **pages,
@@ -2170,6 +2174,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
21702174
#define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */
21712175
#define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */
21722176
#define FOLL_MLOCK 0x1000 /* lock present pages */
2177+
#define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */
21732178

21742179
typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
21752180
void *data);

kernel/events/uprobes.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
299299

300300
retry:
301301
/* Read the page with vaddr into memory */
302-
ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
302+
ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
303303
if (ret <= 0)
304304
return ret;
305305

@@ -1700,7 +1700,13 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
17001700
if (likely(result == 0))
17011701
goto out;
17021702

1703-
result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
1703+
/*
1704+
* The NULL 'tsk' here ensures that any faults that occur here
1705+
* will not be accounted to the task. 'mm' *is* current->mm,
1706+
* but we treat this as a 'remote' access since it is
1707+
* essentially a kernel access to the memory.
1708+
*/
1709+
result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
17041710
if (result < 0)
17051711
return result;
17061712

mm/gup.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
870870
EXPORT_SYMBOL(get_user_pages_unlocked);
871871

872872
/*
873-
* get_user_pages() - pin user pages in memory
873+
* get_user_pages_remote() - pin user pages in memory
874874
* @tsk: the task_struct to use for page fault accounting, or
875875
* NULL if faults are not to be recorded.
876876
* @mm: mm_struct of target mm
@@ -924,12 +924,29 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
924924
* should use get_user_pages because it cannot pass
925925
* FAULT_FLAG_ALLOW_RETRY to handle_mm_fault.
926926
*/
927-
long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
928-
unsigned long start, unsigned long nr_pages, int write,
929-
int force, struct page **pages, struct vm_area_struct **vmas)
927+
long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
928+
unsigned long start, unsigned long nr_pages,
929+
int write, int force, struct page **pages,
930+
struct vm_area_struct **vmas)
930931
{
931932
return __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
932-
pages, vmas, NULL, false, FOLL_TOUCH);
933+
pages, vmas, NULL, false,
934+
FOLL_TOUCH | FOLL_REMOTE);
935+
}
936+
EXPORT_SYMBOL(get_user_pages_remote);
937+
938+
/*
939+
* This is the same as get_user_pages_remote() for the time
940+
* being.
941+
*/
942+
long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
943+
unsigned long start, unsigned long nr_pages,
944+
int write, int force, struct page **pages,
945+
struct vm_area_struct **vmas)
946+
{
947+
return __get_user_pages_locked(tsk, mm, start, nr_pages,
948+
write, force, pages, vmas, NULL, false,
949+
FOLL_TOUCH);
933950
}
934951
EXPORT_SYMBOL(get_user_pages);
935952

mm/memory.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3685,7 +3685,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
36853685
void *maddr;
36863686
struct page *page = NULL;
36873687

3688-
ret = get_user_pages(tsk, mm, addr, 1,
3688+
ret = get_user_pages_remote(tsk, mm, addr, 1,
36893689
write, 1, &page, &vma);
36903690
if (ret <= 0) {
36913691
#ifndef CONFIG_HAVE_IOREMAP_PROT

mm/process_vm_access.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,14 @@ static int process_vm_rw_single_vec(unsigned long addr,
9898
int pages = min(nr_pages, max_pages_per_loop);
9999
size_t bytes;
100100

101-
/* Get the pages we're interested in */
102-
pages = get_user_pages_unlocked(task, mm, pa, pages,
103-
vm_write, 0, process_pages);
101+
/*
102+
* Get the pages we're interested in. We must
103+
* add FOLL_REMOTE because task/mm might not
104+
* current/current->mm
105+
*/
106+
pages = __get_user_pages_unlocked(task, mm, pa, pages,
107+
vm_write, 0, process_pages,
108+
FOLL_REMOTE);
104109
if (pages <= 0)
105110
return -EFAULT;
106111

security/tomoyo/domain.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,14 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
874874
}
875875
/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
876876
#ifdef CONFIG_MMU
877-
if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
877+
/*
878+
* This is called at execve() time in order to dig around
879+
* in the argv/environment of the new proceess
880+
* (represented by bprm). 'current' is the process doing
881+
* the execve().
882+
*/
883+
if (get_user_pages_remote(current, bprm->mm, pos, 1,
884+
0, 1, &page, NULL) <= 0)
878885
return false;
879886
#else
880887
page = bprm->page[pos / PAGE_SIZE];

virt/kvm/async_pf.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ static void async_pf_execute(struct work_struct *work)
7979

8080
might_sleep();
8181

82-
get_user_pages_unlocked(NULL, mm, addr, 1, 1, 0, NULL);
82+
/*
83+
* This work is run asynchromously to the task which owns
84+
* mm and might be done in another context, so we must
85+
* use FOLL_REMOTE.
86+
*/
87+
__get_user_pages_unlocked(NULL, mm, addr, 1, 1, 0, NULL, FOLL_REMOTE);
88+
8389
kvm_async_page_present_sync(vcpu, apf);
8490

8591
spin_lock(&vcpu->async_pf.lock);

0 commit comments

Comments
 (0)