diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 23:51:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 23:51:42 -0400 |
commit | b81a618dcd3ea99de292dbe624f41ca68f464376 (patch) | |
tree | c5fbe44f944da9d7dc0c224116be77094d379c8a /mm/memory.c | |
parent | 2f284c846331fa44be1300a3c2c3e85800268a00 (diff) | |
parent | a9712bc12c40c172e393f85a9b2ba8db4bf59509 (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.c | 73 |
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 | ||
3502 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 3506 | struct 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 | ||
3511 | int in_gate_area_no_task(unsigned long addr) | 3515 | int 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 | */ |
3656 | int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | 3659 | static 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 | */ | ||
3727 | int 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 | */ | ||
3738 | int 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 | */ |