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 | } |