]>
Commit | Line | Data |
---|---|---|
5e993f12 | 1 | --- kernel/ptrace.c |
2 | +++ kernel/ptrace.c | |
3 | @@ -207,60 +207,6 @@ int ptrace_detach(struct task_struct *ch | |
4 | return 0; | |
5 | } | |
6 | ||
7 | -/* | |
8 | - * Access another process' address space. | |
9 | - * Source/target buffer must be kernel space, | |
10 | - * Do not walk the page table directly, use get_user_pages | |
11 | - */ | |
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 | - | |
61 | int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) | |
62 | { | |
63 | int copied = 0; | |
64 | --- mm/memory.c | |
65 | +++ mm/memory.c | |
66 | @@ -2445,3 +2445,56 @@ int in_gate_area_no_task(unsigned long a | |
67 | } | |
68 | ||
69 | #endif /* __HAVE_ARCH_GATE_AREA */ | |
70 | + | |
71 | +/* | |
72 | + * Access another process' address space. | |
73 | + * Source/target buffer must be kernel space, | |
74 | + * Do not walk the page table directly, use get_user_pages | |
75 | + */ | |
76 | +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | |
77 | +{ | |
78 | + struct mm_struct *mm; | |
79 | + struct vm_area_struct *vma; | |
80 | + struct page *page; | |
81 | + void *old_buf = buf; | |
82 | + | |
83 | + mm = get_task_mm(tsk); | |
84 | + if (!mm) | |
85 | + return 0; | |
86 | + | |
87 | + down_read(&mm->mmap_sem); | |
88 | + /* ignore errors, just check how much was sucessfully transfered */ | |
89 | + while (len) { | |
90 | + int bytes, ret, offset; | |
91 | + void *maddr; | |
92 | + | |
93 | + ret = get_user_pages(tsk, mm, addr, 1, | |
94 | + write, 1, &page, &vma); | |
95 | + if (ret <= 0) | |
96 | + break; | |
97 | + | |
98 | + bytes = len; | |
99 | + offset = addr & (PAGE_SIZE-1); | |
100 | + if (bytes > PAGE_SIZE-offset) | |
101 | + bytes = PAGE_SIZE-offset; | |
102 | + | |
103 | + maddr = kmap(page); | |
104 | + if (write) { | |
105 | + copy_to_user_page(vma, page, addr, | |
106 | + maddr + offset, buf, bytes); | |
107 | + set_page_dirty_lock(page); | |
108 | + } else { | |
109 | + copy_from_user_page(vma, page, addr, | |
110 | + buf, maddr + offset, bytes); | |
111 | + } | |
112 | + kunmap(page); | |
113 | + page_cache_release(page); | |
114 | + len -= bytes; | |
115 | + buf += bytes; | |
116 | + addr += bytes; | |
117 | + } | |
118 | + up_read(&mm->mmap_sem); | |
119 | + mmput(mm); | |
120 | + | |
121 | + return buf - old_buf; | |
122 | +} | |
123 | --- mm/nommu.c | |
124 | +++ mm/nommu.c | |
125 | @@ -1213,3 +1213,51 @@ struct page *filemap_nopage(struct vm_ar | |
126 | BUG(); | |
127 | return NULL; | |
128 | } | |
129 | + | |
130 | +/* | |
131 | + * Access another process' address space. | |
132 | + * - source/target buffer must be kernel space | |
133 | + */ | |
134 | +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | |
135 | +{ | |
136 | + struct vm_list_struct *vml; | |
137 | + struct vm_area_struct *vma; | |
138 | + struct mm_struct *mm; | |
139 | + | |
140 | + if (addr + len < addr) | |
141 | + return 0; | |
142 | + | |
143 | + mm = get_task_mm(tsk); | |
144 | + if (!mm) | |
145 | + return 0; | |
146 | + | |
147 | + down_read(&mm->mmap_sem); | |
148 | + | |
149 | + /* the access must start within one of the target process's mappings */ | |
150 | + for (vml = mm->context.vmlist; vml; vml = vml->next) { | |
151 | + if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end) | |
152 | + break; | |
153 | + } | |
154 | + | |
155 | + if (vml) { | |
156 | + vma = vml->vma; | |
157 | + | |
158 | + /* don't overrun this mapping */ | |
159 | + if (addr + len >= vma->vm_end) | |
160 | + len = vma->vm_end - addr; | |
161 | + | |
162 | + /* only read or write mappings where it is permitted */ | |
163 | + if (write && vma->vm_flags & VM_WRITE) | |
164 | + len -= copy_to_user((void *) addr, buf, len); | |
165 | + else if (!write && vma->vm_flags & VM_READ) | |
166 | + len -= copy_from_user(buf, (void *) addr, len); | |
167 | + else | |
168 | + len = 0; | |
169 | + } else { | |
170 | + len = 0; | |
171 | + } | |
172 | + | |
173 | + up_read(&mm->mmap_sem); | |
174 | + mmput(mm); | |
175 | + return len; | |
176 | +} |