]>
Commit | Line | Data |
---|---|---|
1 | --- a/mm/memory.c | |
2 | +++ b/mm/memory.c | |
3 | @@ -2505,3 +2505,56 @@ #endif | |
4 | } | |
5 | ||
6 | #endif /* __HAVE_ARCH_GATE_AREA */ | |
7 | + | |
8 | +/* | |
9 | + * Access another process' address space. | |
10 | + * Source/target buffer must be kernel space, | |
11 | + * Do not walk the page table directly, use get_user_pages | |
12 | + */ | |
13 | +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | |
14 | +{ | |
15 | + struct mm_struct *mm; | |
16 | + struct vm_area_struct *vma; | |
17 | + struct page *page; | |
18 | + void *old_buf = buf; | |
19 | + | |
20 | + mm = get_task_mm(tsk); | |
21 | + if (!mm) | |
22 | + return 0; | |
23 | + | |
24 | + down_read(&mm->mmap_sem); | |
25 | + /* ignore errors, just check how much was sucessfully transfered */ | |
26 | + while (len) { | |
27 | + int bytes, ret, offset; | |
28 | + void *maddr; | |
29 | + | |
30 | + ret = get_user_pages(tsk, mm, addr, 1, | |
31 | + write, 1, &page, &vma); | |
32 | + if (ret <= 0) | |
33 | + break; | |
34 | + | |
35 | + bytes = len; | |
36 | + offset = addr & (PAGE_SIZE-1); | |
37 | + if (bytes > PAGE_SIZE-offset) | |
38 | + bytes = PAGE_SIZE-offset; | |
39 | + | |
40 | + maddr = kmap(page); | |
41 | + if (write) { | |
42 | + copy_to_user_page(vma, page, addr, | |
43 | + maddr + offset, buf, bytes); | |
44 | + set_page_dirty_lock(page); | |
45 | + } else { | |
46 | + copy_from_user_page(vma, page, addr, | |
47 | + buf, maddr + offset, bytes); | |
48 | + } | |
49 | + kunmap(page); | |
50 | + page_cache_release(page); | |
51 | + len -= bytes; | |
52 | + buf += bytes; | |
53 | + addr += bytes; | |
54 | + } | |
55 | + up_read(&mm->mmap_sem); | |
56 | + mmput(mm); | |
57 | + | |
58 | + return buf - old_buf; | |
59 | +} | |
60 | --- a/mm/nommu.c | |
61 | +++ b/mm/nommu.c | |
62 | @@ -1206,3 +1206,51 @@ struct page *filemap_nopage(struct vm_ar | |
63 | BUG(); | |
64 | return NULL; | |
65 | } | |
66 | + | |
67 | +/* | |
68 | + * Access another process' address space. | |
69 | + * - source/target buffer must be kernel space | |
70 | + */ | |
71 | +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | |
72 | +{ | |
73 | + struct vm_list_struct *vml; | |
74 | + struct vm_area_struct *vma; | |
75 | + struct mm_struct *mm; | |
76 | +printk("!!! OH YEAH\n"); | |
77 | + if (addr + len < addr) | |
78 | + return 0; | |
79 | + | |
80 | + mm = get_task_mm(tsk); | |
81 | + if (!mm) | |
82 | + return 0; | |
83 | + | |
84 | + down_read(&mm->mmap_sem); | |
85 | + | |
86 | + /* the access must start within one of the target process's mappings */ | |
87 | + for (vml = mm->context.vmlist; vml; vml = vml->next) { | |
88 | + if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end) | |
89 | + break; | |
90 | + } | |
91 | + | |
92 | + if (vml) { | |
93 | + vma = vml->vma; | |
94 | + | |
95 | + /* don't overrun this mapping */ | |
96 | + if (addr + len >= vma->vm_end) | |
97 | + len = vma->vm_end - addr; | |
98 | + | |
99 | + /* only read or write mappings where it is permitted */ | |
100 | + if (write && vma->vm_flags & VM_WRITE) | |
101 | + len -= copy_to_user((void *) addr, buf, len); | |
102 | + else if (!write && vma->vm_flags & VM_READ) | |
103 | + len -= copy_from_user(buf, (void *) addr, len); | |
104 | + else | |
105 | + len = 0; | |
106 | + } else { | |
107 | + len = 0; | |
108 | + } | |
109 | + | |
110 | + up_read(&mm->mmap_sem); | |
111 | + mmput(mm); | |
112 | + return len; | |
113 | +} |