aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 23:51:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 23:51:42 -0400
commitb81a618dcd3ea99de292dbe624f41ca68f464376 (patch)
treec5fbe44f944da9d7dc0c224116be77094d379c8a /mm/memory.c
parent2f284c846331fa44be1300a3c2c3e85800268a00 (diff)
parenta9712bc12c40c172e393f85a9b2ba8db4bf59509 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: deal with races in /proc/*/{syscall,stack,personality} proc: enable writing to /proc/pid/mem proc: make check_mem_permission() return an mm_struct on success proc: hold cred_guard_mutex in check_mem_permission() proc: disable mem_write after exec mm: implement access_remote_vm mm: factor out main logic of access_process_vm mm: use mm_struct to resolve gate vma's in __get_user_pages mm: arch: rename in_gate_area_no_task to in_gate_area_no_mm mm: arch: make in_gate_area take an mm_struct instead of a task_struct mm: arch: make get_gate_vma take an mm_struct instead of a task_struct x86: mark associated mm when running a task in 32 bit compatibility mode x86: add context tag to mark mm when running a task in 32-bit compatibility mode auxv: require the target to be tracable (or yourself) close race in /proc/*/environ report errors in /proc/*/*map* sanely pagemap: close races with suid execve make sessionid permissions in /proc/*/task/* match those in /proc/* fix leaks in path_lookupat() Fix up trivial conflicts in fs/proc/base.c
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 20d5f7499ce2..51a5c23704af 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1486,9 +1486,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
1486 struct vm_area_struct *vma; 1486 struct vm_area_struct *vma;
1487 1487
1488 vma = find_extend_vma(mm, start); 1488 vma = find_extend_vma(mm, start);
1489 if (!vma && in_gate_area(tsk, start)) { 1489 if (!vma && in_gate_area(mm, start)) {
1490 unsigned long pg = start & PAGE_MASK; 1490 unsigned long pg = start & PAGE_MASK;
1491 struct vm_area_struct *gate_vma = get_gate_vma(tsk); 1491 struct vm_area_struct *gate_vma = get_gate_vma(mm);
1492 pgd_t *pgd; 1492 pgd_t *pgd;
1493 pud_t *pud; 1493 pud_t *pud;
1494 pmd_t *pmd; 1494 pmd_t *pmd;
@@ -1591,10 +1591,13 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
1591 return i ? i : -EFAULT; 1591 return i ? i : -EFAULT;
1592 BUG(); 1592 BUG();
1593 } 1593 }
1594 if (ret & VM_FAULT_MAJOR) 1594
1595 tsk->maj_flt++; 1595 if (tsk) {
1596 else 1596 if (ret & VM_FAULT_MAJOR)
1597 tsk->min_flt++; 1597 tsk->maj_flt++;
1598 else
1599 tsk->min_flt++;
1600 }
1598 1601
1599 if (ret & VM_FAULT_RETRY) { 1602 if (ret & VM_FAULT_RETRY) {
1600 if (nonblocking) 1603 if (nonblocking)
@@ -1641,7 +1644,8 @@ EXPORT_SYMBOL(__get_user_pages);
1641 1644
1642/** 1645/**
1643 * get_user_pages() - pin user pages in memory 1646 * get_user_pages() - pin user pages in memory
1644 * @tsk: task_struct of target task 1647 * @tsk: the task_struct to use for page fault accounting, or
1648 * NULL if faults are not to be recorded.
1645 * @mm: mm_struct of target mm 1649 * @mm: mm_struct of target mm
1646 * @start: starting user address 1650 * @start: starting user address
1647 * @nr_pages: number of pages from start to pin 1651 * @nr_pages: number of pages from start to pin
@@ -3499,7 +3503,7 @@ static int __init gate_vma_init(void)
3499__initcall(gate_vma_init); 3503__initcall(gate_vma_init);
3500#endif 3504#endif
3501 3505
3502struct vm_area_struct *get_gate_vma(struct task_struct *tsk) 3506struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
3503{ 3507{
3504#ifdef AT_SYSINFO_EHDR 3508#ifdef AT_SYSINFO_EHDR
3505 return &gate_vma; 3509 return &gate_vma;
@@ -3508,7 +3512,7 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
3508#endif 3512#endif
3509} 3513}
3510 3514
3511int in_gate_area_no_task(unsigned long addr) 3515int in_gate_area_no_mm(unsigned long addr)
3512{ 3516{
3513#ifdef AT_SYSINFO_EHDR 3517#ifdef AT_SYSINFO_EHDR
3514 if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) 3518 if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END))
@@ -3649,20 +3653,15 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
3649#endif 3653#endif
3650 3654
3651/* 3655/*
3652 * Access another process' address space. 3656 * Access another process' address space as given in mm. If non-NULL, use the
3653 * Source/target buffer must be kernel space, 3657 * given task for page fault accounting.
3654 * Do not walk the page table directly, use get_user_pages
3655 */ 3658 */
3656int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) 3659static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
3660 unsigned long addr, void *buf, int len, int write)
3657{ 3661{
3658 struct mm_struct *mm;
3659 struct vm_area_struct *vma; 3662 struct vm_area_struct *vma;
3660 void *old_buf = buf; 3663 void *old_buf = buf;
3661 3664
3662 mm = get_task_mm(tsk);
3663 if (!mm)
3664 return 0;
3665
3666 down_read(&mm->mmap_sem); 3665 down_read(&mm->mmap_sem);
3667 /* ignore errors, just check how much was successfully transferred */ 3666 /* ignore errors, just check how much was successfully transferred */
3668 while (len) { 3667 while (len) {
@@ -3711,11 +3710,47 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
3711 addr += bytes; 3710 addr += bytes;
3712 } 3711 }
3713 up_read(&mm->mmap_sem); 3712 up_read(&mm->mmap_sem);
3714 mmput(mm);
3715 3713
3716 return buf - old_buf; 3714 return buf - old_buf;
3717} 3715}
3718 3716
3717/**
3718 * @access_remote_vm - access another process' address space
3719 * @mm: the mm_struct of the target address space
3720 * @addr: start address to access
3721 * @buf: source or destination buffer
3722 * @len: number of bytes to transfer
3723 * @write: whether the access is a write
3724 *
3725 * The caller must hold a reference on @mm.
3726 */
3727int access_remote_vm(struct mm_struct *mm, unsigned long addr,
3728 void *buf, int len, int write)
3729{
3730 return __access_remote_vm(NULL, mm, addr, buf, len, write);
3731}
3732
3733/*
3734 * Access another process' address space.
3735 * Source/target buffer must be kernel space,
3736 * Do not walk the page table directly, use get_user_pages
3737 */
3738int access_process_vm(struct task_struct *tsk, unsigned long addr,
3739 void *buf, int len, int write)
3740{
3741 struct mm_struct *mm;
3742 int ret;
3743
3744 mm = get_task_mm(tsk);
3745 if (!mm)
3746 return 0;
3747
3748 ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
3749 mmput(mm);
3750
3751 return ret;
3752}
3753
3719/* 3754/*
3720 * Print the name of a VMA. 3755 * Print the name of a VMA.
3721 */ 3756 */