diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4c8bcd7dd8e0..29dc700e198c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -25,6 +25,17 @@ | |||
25 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | 27 | ||
28 | |||
29 | /* | ||
30 | * Initialize a new task whose father had been ptraced. | ||
31 | * | ||
32 | * Called from copy_process(). | ||
33 | */ | ||
34 | void ptrace_fork(struct task_struct *child, unsigned long clone_flags) | ||
35 | { | ||
36 | arch_ptrace_fork(child, clone_flags); | ||
37 | } | ||
38 | |||
28 | /* | 39 | /* |
29 | * ptrace a task: make the debugger its new parent and | 40 | * ptrace a task: make the debugger its new parent and |
30 | * move it to the ptrace list. | 41 | * move it to the ptrace list. |
@@ -72,6 +83,7 @@ void __ptrace_unlink(struct task_struct *child) | |||
72 | child->parent = child->real_parent; | 83 | child->parent = child->real_parent; |
73 | list_del_init(&child->ptrace_entry); | 84 | list_del_init(&child->ptrace_entry); |
74 | 85 | ||
86 | arch_ptrace_untrace(child); | ||
75 | if (task_is_traced(child)) | 87 | if (task_is_traced(child)) |
76 | ptrace_untrace(child); | 88 | ptrace_untrace(child); |
77 | } | 89 | } |
@@ -115,6 +127,8 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
115 | 127 | ||
116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 128 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
117 | { | 129 | { |
130 | const struct cred *cred = current_cred(), *tcred; | ||
131 | |||
118 | /* May we inspect the given task? | 132 | /* May we inspect the given task? |
119 | * This check is used both for attaching with ptrace | 133 | * This check is used both for attaching with ptrace |
120 | * and for allowing access to sensitive information in /proc. | 134 | * and for allowing access to sensitive information in /proc. |
@@ -127,13 +141,19 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
127 | /* Don't let security modules deny introspection */ | 141 | /* Don't let security modules deny introspection */ |
128 | if (task == current) | 142 | if (task == current) |
129 | return 0; | 143 | return 0; |
130 | if (((current->uid != task->euid) || | 144 | rcu_read_lock(); |
131 | (current->uid != task->suid) || | 145 | tcred = __task_cred(task); |
132 | (current->uid != task->uid) || | 146 | if ((cred->uid != tcred->euid || |
133 | (current->gid != task->egid) || | 147 | cred->uid != tcred->suid || |
134 | (current->gid != task->sgid) || | 148 | cred->uid != tcred->uid || |
135 | (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) | 149 | cred->gid != tcred->egid || |
150 | cred->gid != tcred->sgid || | ||
151 | cred->gid != tcred->gid) && | ||
152 | !capable(CAP_SYS_PTRACE)) { | ||
153 | rcu_read_unlock(); | ||
136 | return -EPERM; | 154 | return -EPERM; |
155 | } | ||
156 | rcu_read_unlock(); | ||
137 | smp_rmb(); | 157 | smp_rmb(); |
138 | if (task->mm) | 158 | if (task->mm) |
139 | dumpable = get_dumpable(task->mm); | 159 | dumpable = get_dumpable(task->mm); |
@@ -163,6 +183,14 @@ int ptrace_attach(struct task_struct *task) | |||
163 | if (same_thread_group(task, current)) | 183 | if (same_thread_group(task, current)) |
164 | goto out; | 184 | goto out; |
165 | 185 | ||
186 | /* Protect exec's credential calculations against our interference; | ||
187 | * SUID, SGID and LSM creds get determined differently under ptrace. | ||
188 | */ | ||
189 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
190 | if (retval < 0) | ||
191 | goto out; | ||
192 | |||
193 | retval = -EPERM; | ||
166 | repeat: | 194 | repeat: |
167 | /* | 195 | /* |
168 | * Nasty, nasty. | 196 | * Nasty, nasty. |
@@ -202,6 +230,7 @@ repeat: | |||
202 | bad: | 230 | bad: |
203 | write_unlock_irqrestore(&tasklist_lock, flags); | 231 | write_unlock_irqrestore(&tasklist_lock, flags); |
204 | task_unlock(task); | 232 | task_unlock(task); |
233 | mutex_unlock(¤t->cred_exec_mutex); | ||
205 | out: | 234 | out: |
206 | return retval; | 235 | return retval; |
207 | } | 236 | } |