aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c84
1 files changed, 23 insertions, 61 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 921c22ad16e4..4d50e06fd745 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -28,7 +28,7 @@
28 * 28 *
29 * Must be called with the tasklist lock write-held. 29 * Must be called with the tasklist lock write-held.
30 */ 30 */
31void __ptrace_link(task_t *child, task_t *new_parent) 31void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
32{ 32{
33 BUG_ON(!list_empty(&child->ptrace_list)); 33 BUG_ON(!list_empty(&child->ptrace_list));
34 if (child->parent == new_parent) 34 if (child->parent == new_parent)
@@ -46,7 +46,7 @@ void __ptrace_link(task_t *child, task_t *new_parent)
46 * TASK_TRACED, resume it now. 46 * TASK_TRACED, resume it now.
47 * Requires that irqs be disabled. 47 * Requires that irqs be disabled.
48 */ 48 */
49void ptrace_untrace(task_t *child) 49void ptrace_untrace(struct task_struct *child)
50{ 50{
51 spin_lock(&child->sighand->siglock); 51 spin_lock(&child->sighand->siglock);
52 if (child->state == TASK_TRACED) { 52 if (child->state == TASK_TRACED) {
@@ -65,7 +65,7 @@ void ptrace_untrace(task_t *child)
65 * 65 *
66 * Must be called with the tasklist lock write-held. 66 * Must be called with the tasklist lock write-held.
67 */ 67 */
68void __ptrace_unlink(task_t *child) 68void __ptrace_unlink(struct task_struct *child)
69{ 69{
70 BUG_ON(!child->ptrace); 70 BUG_ON(!child->ptrace);
71 71
@@ -120,8 +120,18 @@ int ptrace_check_attach(struct task_struct *child, int kill)
120 120
121static int may_attach(struct task_struct *task) 121static int may_attach(struct task_struct *task)
122{ 122{
123 if (!task->mm) 123 /* May we inspect the given task?
124 return -EPERM; 124 * This check is used both for attaching with ptrace
125 * and for allowing access to sensitive information in /proc.
126 *
127 * ptrace_attach denies several cases that /proc allows
128 * because setting up the necessary parent/child relationship
129 * or halting the specified task is impossible.
130 */
131 int dumpable = 0;
132 /* Don't let security modules deny introspection */
133 if (task == current)
134 return 0;
125 if (((current->uid != task->euid) || 135 if (((current->uid != task->euid) ||
126 (current->uid != task->suid) || 136 (current->uid != task->suid) ||
127 (current->uid != task->uid) || 137 (current->uid != task->uid) ||
@@ -130,7 +140,9 @@ static int may_attach(struct task_struct *task)
130 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) 140 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
131 return -EPERM; 141 return -EPERM;
132 smp_rmb(); 142 smp_rmb();
133 if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) 143 if (task->mm)
144 dumpable = task->mm->dumpable;
145 if (!dumpable && !capable(CAP_SYS_PTRACE))
134 return -EPERM; 146 return -EPERM;
135 147
136 return security_ptrace(current, task); 148 return security_ptrace(current, task);
@@ -176,6 +188,8 @@ repeat:
176 goto repeat; 188 goto repeat;
177 } 189 }
178 190
191 if (!task->mm)
192 goto bad;
179 /* the same process cannot be attached many times */ 193 /* the same process cannot be attached many times */
180 if (task->ptrace & PT_PTRACED) 194 if (task->ptrace & PT_PTRACED)
181 goto bad; 195 goto bad;
@@ -200,7 +214,7 @@ out:
200 return retval; 214 return retval;
201} 215}
202 216
203void __ptrace_detach(struct task_struct *child, unsigned int data) 217static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
204{ 218{
205 child->exit_code = data; 219 child->exit_code = data;
206 /* .. re-parent .. */ 220 /* .. re-parent .. */
@@ -219,6 +233,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
219 ptrace_disable(child); 233 ptrace_disable(child);
220 234
221 write_lock_irq(&tasklist_lock); 235 write_lock_irq(&tasklist_lock);
236 /* protect against de_thread()->release_task() */
222 if (child->ptrace) 237 if (child->ptrace)
223 __ptrace_detach(child, data); 238 __ptrace_detach(child, data);
224 write_unlock_irq(&tasklist_lock); 239 write_unlock_irq(&tasklist_lock);
@@ -226,60 +241,6 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
226 return 0; 241 return 0;
227} 242}
228 243
229/*
230 * Access another process' address space.
231 * Source/target buffer must be kernel space,
232 * Do not walk the page table directly, use get_user_pages
233 */
234
235int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
236{
237 struct mm_struct *mm;
238 struct vm_area_struct *vma;
239 struct page *page;
240 void *old_buf = buf;
241
242 mm = get_task_mm(tsk);
243 if (!mm)
244 return 0;
245
246 down_read(&mm->mmap_sem);
247 /* ignore errors, just check how much was sucessfully transfered */
248 while (len) {
249 int bytes, ret, offset;
250 void *maddr;
251
252 ret = get_user_pages(tsk, mm, addr, 1,
253 write, 1, &page, &vma);
254 if (ret <= 0)
255 break;
256
257 bytes = len;
258 offset = addr & (PAGE_SIZE-1);
259 if (bytes > PAGE_SIZE-offset)
260 bytes = PAGE_SIZE-offset;
261
262 maddr = kmap(page);
263 if (write) {
264 copy_to_user_page(vma, page, addr,
265 maddr + offset, buf, bytes);
266 set_page_dirty_lock(page);
267 } else {
268 copy_from_user_page(vma, page, addr,
269 buf, maddr + offset, bytes);
270 }
271 kunmap(page);
272 page_cache_release(page);
273 len -= bytes;
274 buf += bytes;
275 addr += bytes;
276 }
277 up_read(&mm->mmap_sem);
278 mmput(mm);
279
280 return buf - old_buf;
281}
282
283int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) 244int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
284{ 245{
285 int copied = 0; 246 int copied = 0;
@@ -479,6 +440,7 @@ struct task_struct *ptrace_get_task_struct(pid_t pid)
479 child = find_task_by_pid(pid); 440 child = find_task_by_pid(pid);
480 if (child) 441 if (child)
481 get_task_struct(child); 442 get_task_struct(child);
443
482 read_unlock(&tasklist_lock); 444 read_unlock(&tasklist_lock);
483 if (!child) 445 if (!child)
484 return ERR_PTR(-ESRCH); 446 return ERR_PTR(-ESRCH);