OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_or32_unified_v2.3/] [kernel/] [ptrace.c] - Blame information for rev 3

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * linux/kernel/ptrace.c
3
 *
4
 * (C) Copyright 1999 Linus Torvalds
5
 *
6
 * Common interfaces for "ptrace()" which we do not want
7
 * to continually duplicate across every architecture.
8
 */
9
 
10
#include <linux/capability.h>
11
#include <linux/module.h>
12
#include <linux/sched.h>
13
#include <linux/errno.h>
14
#include <linux/mm.h>
15
#include <linux/highmem.h>
16
#include <linux/pagemap.h>
17
#include <linux/smp_lock.h>
18
#include <linux/ptrace.h>
19
#include <linux/security.h>
20
#include <linux/signal.h>
21
#include <linux/audit.h>
22
#include <linux/pid_namespace.h>
23
 
24
#include <asm/pgtable.h>
25
#include <asm/uaccess.h>
26
 
27
/*
28
 * ptrace a task: make the debugger its new parent and
29
 * move it to the ptrace list.
30
 *
31
 * Must be called with the tasklist lock write-held.
32
 */
33
void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
34
{
35
        BUG_ON(!list_empty(&child->ptrace_list));
36
        if (child->parent == new_parent)
37
                return;
38
        list_add(&child->ptrace_list, &child->parent->ptrace_children);
39
        remove_parent(child);
40
        child->parent = new_parent;
41
        add_parent(child);
42
}
43
 
44
/*
45
 * Turn a tracing stop into a normal stop now, since with no tracer there
46
 * would be no way to wake it up with SIGCONT or SIGKILL.  If there was a
47
 * signal sent that would resume the child, but didn't because it was in
48
 * TASK_TRACED, resume it now.
49
 * Requires that irqs be disabled.
50
 */
51
void ptrace_untrace(struct task_struct *child)
52
{
53
        spin_lock(&child->sighand->siglock);
54
        if (child->state == TASK_TRACED) {
55
                if (child->signal->flags & SIGNAL_STOP_STOPPED) {
56
                        child->state = TASK_STOPPED;
57
                } else {
58
                        signal_wake_up(child, 1);
59
                }
60
        }
61
        spin_unlock(&child->sighand->siglock);
62
}
63
 
64
/*
65
 * unptrace a task: move it back to its original parent and
66
 * remove it from the ptrace list.
67
 *
68
 * Must be called with the tasklist lock write-held.
69
 */
70
void __ptrace_unlink(struct task_struct *child)
71
{
72
        BUG_ON(!child->ptrace);
73
 
74
        child->ptrace = 0;
75
        if (!list_empty(&child->ptrace_list)) {
76
                list_del_init(&child->ptrace_list);
77
                remove_parent(child);
78
                child->parent = child->real_parent;
79
                add_parent(child);
80
        }
81
 
82
        if (child->state == TASK_TRACED)
83
                ptrace_untrace(child);
84
}
85
 
86
/*
87
 * Check that we have indeed attached to the thing..
88
 */
89
int ptrace_check_attach(struct task_struct *child, int kill)
90
{
91
        int ret = -ESRCH;
92
 
93
        /*
94
         * We take the read lock around doing both checks to close a
95
         * possible race where someone else was tracing our child and
96
         * detached between these two checks.  After this locked check,
97
         * we are sure that this is our traced child and that can only
98
         * be changed by us so it's not changing right after this.
99
         */
100
        read_lock(&tasklist_lock);
101
        if ((child->ptrace & PT_PTRACED) && child->parent == current &&
102
            (!(child->ptrace & PT_ATTACHED) || child->real_parent != current)
103
            && child->signal != NULL) {
104
                ret = 0;
105
                spin_lock_irq(&child->sighand->siglock);
106
                if (child->state == TASK_STOPPED) {
107
                        child->state = TASK_TRACED;
108
                } else if (child->state != TASK_TRACED && !kill) {
109
                        ret = -ESRCH;
110
                }
111
                spin_unlock_irq(&child->sighand->siglock);
112
        }
113
        read_unlock(&tasklist_lock);
114
 
115
        if (!ret && !kill) {
116
                wait_task_inactive(child);
117
        }
118
 
119
        /* All systems go.. */
120
        return ret;
121
}
122
 
123
int __ptrace_may_attach(struct task_struct *task)
124
{
125
        /* May we inspect the given task?
126
         * This check is used both for attaching with ptrace
127
         * and for allowing access to sensitive information in /proc.
128
         *
129
         * ptrace_attach denies several cases that /proc allows
130
         * because setting up the necessary parent/child relationship
131
         * or halting the specified task is impossible.
132
         */
133
        int dumpable = 0;
134
        /* Don't let security modules deny introspection */
135
        if (task == current)
136
                return 0;
137
        if (((current->uid != task->euid) ||
138
             (current->uid != task->suid) ||
139
             (current->uid != task->uid) ||
140
             (current->gid != task->egid) ||
141
             (current->gid != task->sgid) ||
142
             (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
143
                return -EPERM;
144
        smp_rmb();
145
        if (task->mm)
146
                dumpable = get_dumpable(task->mm);
147
        if (!dumpable && !capable(CAP_SYS_PTRACE))
148
                return -EPERM;
149
 
150
        return security_ptrace(current, task);
151
}
152
 
153
int ptrace_may_attach(struct task_struct *task)
154
{
155
        int err;
156
        task_lock(task);
157
        err = __ptrace_may_attach(task);
158
        task_unlock(task);
159
        return !err;
160
}
161
 
162
int ptrace_attach(struct task_struct *task)
163
{
164
        int retval;
165
        unsigned long flags;
166
 
167
        audit_ptrace(task);
168
 
169
        retval = -EPERM;
170
        if (task->pid <= 1)
171
                goto out;
172
        if (same_thread_group(task, current))
173
                goto out;
174
 
175
repeat:
176
        /*
177
         * Nasty, nasty.
178
         *
179
         * We want to hold both the task-lock and the
180
         * tasklist_lock for writing at the same time.
181
         * But that's against the rules (tasklist_lock
182
         * is taken for reading by interrupts on other
183
         * cpu's that may have task_lock).
184
         */
185
        task_lock(task);
186
        if (!write_trylock_irqsave(&tasklist_lock, flags)) {
187
                task_unlock(task);
188
                do {
189
                        cpu_relax();
190
                } while (!write_can_lock(&tasklist_lock));
191
                goto repeat;
192
        }
193
 
194
        if (!task->mm)
195
                goto bad;
196
        /* the same process cannot be attached many times */
197
        if (task->ptrace & PT_PTRACED)
198
                goto bad;
199
        retval = __ptrace_may_attach(task);
200
        if (retval)
201
                goto bad;
202
 
203
        /* Go */
204
        task->ptrace |= PT_PTRACED | ((task->real_parent != current)
205
                                      ? PT_ATTACHED : 0);
206
        if (capable(CAP_SYS_PTRACE))
207
                task->ptrace |= PT_PTRACE_CAP;
208
 
209
        __ptrace_link(task, current);
210
 
211
        force_sig_specific(SIGSTOP, task);
212
 
213
bad:
214
        write_unlock_irqrestore(&tasklist_lock, flags);
215
        task_unlock(task);
216
out:
217
        return retval;
218
}
219
 
220
static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
221
{
222
        child->exit_code = data;
223
        /* .. re-parent .. */
224
        __ptrace_unlink(child);
225
        /* .. and wake it up. */
226
        if (child->exit_state != EXIT_ZOMBIE)
227
                wake_up_process(child);
228
}
229
 
230
int ptrace_detach(struct task_struct *child, unsigned int data)
231
{
232
        if (!valid_signal(data))
233
                return -EIO;
234
 
235
        /* Architecture-specific hardware disable .. */
236
        ptrace_disable(child);
237
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
238
 
239
        write_lock_irq(&tasklist_lock);
240
        /* protect against de_thread()->release_task() */
241
        if (child->ptrace)
242
                __ptrace_detach(child, data);
243
        write_unlock_irq(&tasklist_lock);
244
 
245
        return 0;
246
}
247
 
248
int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
249
{
250
        int copied = 0;
251
 
252
        while (len > 0) {
253
                char buf[128];
254
                int this_len, retval;
255
 
256
                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
257
                retval = access_process_vm(tsk, src, buf, this_len, 0);
258
                if (!retval) {
259
                        if (copied)
260
                                break;
261
                        return -EIO;
262
                }
263
                if (copy_to_user(dst, buf, retval))
264
                        return -EFAULT;
265
                copied += retval;
266
                src += retval;
267
                dst += retval;
268
                len -= retval;
269
        }
270
        return copied;
271
}
272
 
273
int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
274
{
275
        int copied = 0;
276
 
277
        while (len > 0) {
278
                char buf[128];
279
                int this_len, retval;
280
 
281
                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
282
                if (copy_from_user(buf, src, this_len))
283
                        return -EFAULT;
284
                retval = access_process_vm(tsk, dst, buf, this_len, 1);
285
                if (!retval) {
286
                        if (copied)
287
                                break;
288
                        return -EIO;
289
                }
290
                copied += retval;
291
                src += retval;
292
                dst += retval;
293
                len -= retval;
294
        }
295
        return copied;
296
}
297
 
298
static int ptrace_setoptions(struct task_struct *child, long data)
299
{
300
        child->ptrace &= ~PT_TRACE_MASK;
301
 
302
        if (data & PTRACE_O_TRACESYSGOOD)
303
                child->ptrace |= PT_TRACESYSGOOD;
304
 
305
        if (data & PTRACE_O_TRACEFORK)
306
                child->ptrace |= PT_TRACE_FORK;
307
 
308
        if (data & PTRACE_O_TRACEVFORK)
309
                child->ptrace |= PT_TRACE_VFORK;
310
 
311
        if (data & PTRACE_O_TRACECLONE)
312
                child->ptrace |= PT_TRACE_CLONE;
313
 
314
        if (data & PTRACE_O_TRACEEXEC)
315
                child->ptrace |= PT_TRACE_EXEC;
316
 
317
        if (data & PTRACE_O_TRACEVFORKDONE)
318
                child->ptrace |= PT_TRACE_VFORK_DONE;
319
 
320
        if (data & PTRACE_O_TRACEEXIT)
321
                child->ptrace |= PT_TRACE_EXIT;
322
 
323
        return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
324
}
325
 
326
static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
327
{
328
        siginfo_t lastinfo;
329
        int error = -ESRCH;
330
 
331
        read_lock(&tasklist_lock);
332
        if (likely(child->sighand != NULL)) {
333
                error = -EINVAL;
334
                spin_lock_irq(&child->sighand->siglock);
335
                if (likely(child->last_siginfo != NULL)) {
336
                        lastinfo = *child->last_siginfo;
337
                        error = 0;
338
                }
339
                spin_unlock_irq(&child->sighand->siglock);
340
        }
341
        read_unlock(&tasklist_lock);
342
        if (!error)
343
                return copy_siginfo_to_user(data, &lastinfo);
344
        return error;
345
}
346
 
347
static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
348
{
349
        siginfo_t newinfo;
350
        int error = -ESRCH;
351
 
352
        if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
353
                return -EFAULT;
354
 
355
        read_lock(&tasklist_lock);
356
        if (likely(child->sighand != NULL)) {
357
                error = -EINVAL;
358
                spin_lock_irq(&child->sighand->siglock);
359
                if (likely(child->last_siginfo != NULL)) {
360
                        *child->last_siginfo = newinfo;
361
                        error = 0;
362
                }
363
                spin_unlock_irq(&child->sighand->siglock);
364
        }
365
        read_unlock(&tasklist_lock);
366
        return error;
367
}
368
 
369
int ptrace_request(struct task_struct *child, long request,
370
                   long addr, long data)
371
{
372
        int ret = -EIO;
373
 
374
        switch (request) {
375
#ifdef PTRACE_OLDSETOPTIONS
376
        case PTRACE_OLDSETOPTIONS:
377
#endif
378
        case PTRACE_SETOPTIONS:
379
                ret = ptrace_setoptions(child, data);
380
                break;
381
        case PTRACE_GETEVENTMSG:
382
                ret = put_user(child->ptrace_message, (unsigned long __user *) data);
383
                break;
384
        case PTRACE_GETSIGINFO:
385
                ret = ptrace_getsiginfo(child, (siginfo_t __user *) data);
386
                break;
387
        case PTRACE_SETSIGINFO:
388
                ret = ptrace_setsiginfo(child, (siginfo_t __user *) data);
389
                break;
390
        case PTRACE_DETACH:      /* detach a process that was attached. */
391
                ret = ptrace_detach(child, data);
392
                break;
393
        default:
394
                break;
395
        }
396
 
397
        return ret;
398
}
399
 
400
/**
401
 * ptrace_traceme  --  helper for PTRACE_TRACEME
402
 *
403
 * Performs checks and sets PT_PTRACED.
404
 * Should be used by all ptrace implementations for PTRACE_TRACEME.
405
 */
406
int ptrace_traceme(void)
407
{
408
        int ret = -EPERM;
409
 
410
        /*
411
         * Are we already being traced?
412
         */
413
        task_lock(current);
414
        if (!(current->ptrace & PT_PTRACED)) {
415
                ret = security_ptrace(current->parent, current);
416
                /*
417
                 * Set the ptrace bit in the process ptrace flags.
418
                 */
419
                if (!ret)
420
                        current->ptrace |= PT_PTRACED;
421
        }
422
        task_unlock(current);
423
        return ret;
424
}
425
 
426
/**
427
 * ptrace_get_task_struct  --  grab a task struct reference for ptrace
428
 * @pid:       process id to grab a task_struct reference of
429
 *
430
 * This function is a helper for ptrace implementations.  It checks
431
 * permissions and then grabs a task struct for use of the actual
432
 * ptrace implementation.
433
 *
434
 * Returns the task_struct for @pid or an ERR_PTR() on failure.
435
 */
436
struct task_struct *ptrace_get_task_struct(pid_t pid)
437
{
438
        struct task_struct *child;
439
 
440
        /*
441
         * Tracing init is not allowed.
442
         */
443
        if (pid == 1)
444
                return ERR_PTR(-EPERM);
445
 
446
        read_lock(&tasklist_lock);
447
        child = find_task_by_vpid(pid);
448
        if (child)
449
                get_task_struct(child);
450
 
451
        read_unlock(&tasklist_lock);
452
        if (!child)
453
                return ERR_PTR(-ESRCH);
454
        return child;
455
}
456
 
457
#ifndef arch_ptrace_attach
458
#define arch_ptrace_attach(child)       do { } while (0)
459
#endif
460
 
461
#ifndef __ARCH_SYS_PTRACE
462
asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
463
{
464
        struct task_struct *child;
465
        long ret;
466
 
467
        /*
468
         * This lock_kernel fixes a subtle race with suid exec
469
         */
470
        lock_kernel();
471
        if (request == PTRACE_TRACEME) {
472
                ret = ptrace_traceme();
473
                goto out;
474
        }
475
 
476
        child = ptrace_get_task_struct(pid);
477
        if (IS_ERR(child)) {
478
                ret = PTR_ERR(child);
479
                goto out;
480
        }
481
 
482
        if (request == PTRACE_ATTACH) {
483
                ret = ptrace_attach(child);
484
                /*
485
                 * Some architectures need to do book-keeping after
486
                 * a ptrace attach.
487
                 */
488
                if (!ret)
489
                        arch_ptrace_attach(child);
490
                goto out_put_task_struct;
491
        }
492
 
493
        ret = ptrace_check_attach(child, request == PTRACE_KILL);
494
        if (ret < 0)
495
                goto out_put_task_struct;
496
 
497
        ret = arch_ptrace(child, request, addr, data);
498
        if (ret < 0)
499
                goto out_put_task_struct;
500
 
501
 out_put_task_struct:
502
        put_task_struct(child);
503
 out:
504
        unlock_kernel();
505
        return ret;
506
}
507
#endif /* __ARCH_SYS_PTRACE */
508
 
509
int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
510
{
511
        unsigned long tmp;
512
        int copied;
513
 
514
        copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0);
515
        if (copied != sizeof(tmp))
516
                return -EIO;
517
        return put_user(tmp, (unsigned long __user *)data);
518
}
519
 
520
int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
521
{
522
        int copied;
523
 
524
        copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);
525
        return (copied == sizeof(data)) ? 0 : -EIO;
526
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.