diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 100a71cfdaba..29dc700e198c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -127,6 +127,8 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
127 | 127 | ||
128 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 128 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
129 | { | 129 | { |
130 | const struct cred *cred = current_cred(), *tcred; | ||
131 | |||
130 | /* May we inspect the given task? | 132 | /* May we inspect the given task? |
131 | * This check is used both for attaching with ptrace | 133 | * This check is used both for attaching with ptrace |
132 | * and for allowing access to sensitive information in /proc. | 134 | * and for allowing access to sensitive information in /proc. |
@@ -139,13 +141,19 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
139 | /* Don't let security modules deny introspection */ | 141 | /* Don't let security modules deny introspection */ |
140 | if (task == current) | 142 | if (task == current) |
141 | return 0; | 143 | return 0; |
142 | if (((current->uid != task->euid) || | 144 | rcu_read_lock(); |
143 | (current->uid != task->suid) || | 145 | tcred = __task_cred(task); |
144 | (current->uid != task->uid) || | 146 | if ((cred->uid != tcred->euid || |
145 | (current->gid != task->egid) || | 147 | cred->uid != tcred->suid || |
146 | (current->gid != task->sgid) || | 148 | cred->uid != tcred->uid || |
147 | (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(); | ||
148 | return -EPERM; | 154 | return -EPERM; |
155 | } | ||
156 | rcu_read_unlock(); | ||
149 | smp_rmb(); | 157 | smp_rmb(); |
150 | if (task->mm) | 158 | if (task->mm) |
151 | dumpable = get_dumpable(task->mm); | 159 | dumpable = get_dumpable(task->mm); |
@@ -175,6 +183,14 @@ int ptrace_attach(struct task_struct *task) | |||
175 | if (same_thread_group(task, current)) | 183 | if (same_thread_group(task, current)) |
176 | goto out; | 184 | goto out; |
177 | 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; | ||
178 | repeat: | 194 | repeat: |
179 | /* | 195 | /* |
180 | * Nasty, nasty. | 196 | * Nasty, nasty. |
@@ -214,6 +230,7 @@ repeat: | |||
214 | bad: | 230 | bad: |
215 | write_unlock_irqrestore(&tasklist_lock, flags); | 231 | write_unlock_irqrestore(&tasklist_lock, flags); |
216 | task_unlock(task); | 232 | task_unlock(task); |
233 | mutex_unlock(¤t->cred_exec_mutex); | ||
217 | out: | 234 | out: |
218 | return retval; | 235 | return retval; |
219 | } | 236 | } |