{
struct task_struct *task;
int allowed = 0;
- /* Allow access to a task's file descriptors if either we may
- * use ptrace attach to the process and find out that
- * information, or if the task cannot possibly be ptraced
- * allow access if we have the proper capability.
+ /* Allow access to a task's file descriptors if it is us or we
+ * may use ptrace attach to the process and find out that
+ * information.
*/
task = get_proc_task(inode);
- if (task == current)
- allowed = 1;
- if (task && !allowed) {
- int alive;
-
- task_lock(task);
- alive = !!task->mm;
- task_unlock(task);
- if (alive)
- /* For a living task obey ptrace_may_attach */
- allowed = ptrace_may_attach(task);
- else
- /* For a special task simply check the capability */
- allowed = capable(CAP_SYS_PTRACE);
- }
- if (task)
+ if (task) {
+ allowed = ptrace_may_attach(task);
put_task_struct(task);
+ }
return allowed;
}
static int may_attach(struct task_struct *task)
{
- if (!task->mm)
- return -EPERM;
+ /* May we inspect the given task?
+ * This check is used both for attaching with ptrace
+ * and for allowing access to sensitive information in /proc.
+ *
+ * ptrace_attach denies several cases that /proc allows
+ * because setting up the necessary parent/child relationship
+ * or halting the specified task is impossible.
+ */
+ int dumpable = 0;
+ /* Don't let security modules deny introspection */
+ if (task == current)
+ return 0;
if (((current->uid != task->euid) ||
(current->uid != task->suid) ||
(current->uid != task->uid) ||
(current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
return -EPERM;
smp_rmb();
- if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+ if (task->mm)
+ dumpable = task->mm->dumpable;
+ if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
return security_ptrace(current, task);
goto repeat;
}
+ if (!task->mm)
+ goto bad;
/* the same process cannot be attached many times */
if (task->ptrace & PT_PTRACED)
goto bad;