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 4c8bcd7dd8e0..ca2df68faf76 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -115,6 +115,8 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
| 115 | 115 | ||
| 116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
| 117 | { | 117 | { |
| 118 | const struct cred *cred = current_cred(), *tcred; | ||
| 119 | |||
| 118 | /* May we inspect the given task? | 120 | /* May we inspect the given task? |
| 119 | * This check is used both for attaching with ptrace | 121 | * This check is used both for attaching with ptrace |
| 120 | * and for allowing access to sensitive information in /proc. | 122 | * and for allowing access to sensitive information in /proc. |
| @@ -127,13 +129,19 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
| 127 | /* Don't let security modules deny introspection */ | 129 | /* Don't let security modules deny introspection */ |
| 128 | if (task == current) | 130 | if (task == current) |
| 129 | return 0; | 131 | return 0; |
| 130 | if (((current->uid != task->euid) || | 132 | rcu_read_lock(); |
| 131 | (current->uid != task->suid) || | 133 | tcred = __task_cred(task); |
| 132 | (current->uid != task->uid) || | 134 | if ((cred->uid != tcred->euid || |
| 133 | (current->gid != task->egid) || | 135 | cred->uid != tcred->suid || |
| 134 | (current->gid != task->sgid) || | 136 | cred->uid != tcred->uid || |
| 135 | (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) | 137 | cred->gid != tcred->egid || |
| 138 | cred->gid != tcred->sgid || | ||
| 139 | cred->gid != tcred->gid) && | ||
| 140 | !capable(CAP_SYS_PTRACE)) { | ||
| 141 | rcu_read_unlock(); | ||
| 136 | return -EPERM; | 142 | return -EPERM; |
| 143 | } | ||
| 144 | rcu_read_unlock(); | ||
| 137 | smp_rmb(); | 145 | smp_rmb(); |
| 138 | if (task->mm) | 146 | if (task->mm) |
| 139 | dumpable = get_dumpable(task->mm); | 147 | dumpable = get_dumpable(task->mm); |
| @@ -163,6 +171,14 @@ int ptrace_attach(struct task_struct *task) | |||
| 163 | if (same_thread_group(task, current)) | 171 | if (same_thread_group(task, current)) |
| 164 | goto out; | 172 | goto out; |
| 165 | 173 | ||
| 174 | /* Protect exec's credential calculations against our interference; | ||
| 175 | * SUID, SGID and LSM creds get determined differently under ptrace. | ||
| 176 | */ | ||
| 177 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
| 178 | if (retval < 0) | ||
| 179 | goto out; | ||
| 180 | |||
| 181 | retval = -EPERM; | ||
| 166 | repeat: | 182 | repeat: |
| 167 | /* | 183 | /* |
| 168 | * Nasty, nasty. | 184 | * Nasty, nasty. |
| @@ -202,6 +218,7 @@ repeat: | |||
| 202 | bad: | 218 | bad: |
| 203 | write_unlock_irqrestore(&tasklist_lock, flags); | 219 | write_unlock_irqrestore(&tasklist_lock, flags); |
| 204 | task_unlock(task); | 220 | task_unlock(task); |
| 221 | mutex_unlock(¤t->cred_exec_mutex); | ||
| 205 | out: | 222 | out: |
| 206 | return retval; | 223 | return retval; |
| 207 | } | 224 | } |
