2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* linux/kernel/ptrace.c
|
|
|
|
*
|
|
|
|
* (C) Copyright 1999 Linus Torvalds
|
|
|
|
*
|
|
|
|
* Common interfaces for "ptrace()" which we do not want
|
|
|
|
* to continually duplicate across every architecture.
|
|
|
|
*/
|
|
|
|
|
2006-01-12 04:17:46 +08:00
|
|
|
#include <linux/capability.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/highmem.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/smp_lock.h>
|
|
|
|
#include <linux/ptrace.h>
|
|
|
|
#include <linux/security.h>
|
2005-05-01 23:59:14 +08:00
|
|
|
#include <linux/signal.h>
|
2007-03-21 01:58:35 +08:00
|
|
|
#include <linux/audit.h>
|
2007-10-19 14:40:14 +08:00
|
|
|
#include <linux/pid_namespace.h>
|
2008-02-06 17:36:44 +08:00
|
|
|
#include <linux/syscalls.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <asm/pgtable.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
2008-12-19 22:10:24 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a new task whose father had been ptraced.
|
|
|
|
*
|
|
|
|
* Called from copy_process().
|
|
|
|
*/
|
|
|
|
void ptrace_fork(struct task_struct *child, unsigned long clone_flags)
|
|
|
|
{
|
|
|
|
arch_ptrace_fork(child, clone_flags);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* ptrace a task: make the debugger its new parent and
|
|
|
|
* move it to the ptrace list.
|
|
|
|
*
|
|
|
|
* Must be called with the tasklist lock write-held.
|
|
|
|
*/
|
2006-07-03 15:25:41 +08:00
|
|
|
void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-03-25 09:36:23 +08:00
|
|
|
BUG_ON(!list_empty(&child->ptrace_entry));
|
|
|
|
list_add(&child->ptrace_entry, &new_parent->ptraced);
|
2005-04-17 06:20:36 +08:00
|
|
|
child->parent = new_parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Turn a tracing stop into a normal stop now, since with no tracer there
|
|
|
|
* would be no way to wake it up with SIGCONT or SIGKILL. If there was a
|
|
|
|
* signal sent that would resume the child, but didn't because it was in
|
|
|
|
* TASK_TRACED, resume it now.
|
|
|
|
* Requires that irqs be disabled.
|
|
|
|
*/
|
2008-10-19 11:28:21 +08:00
|
|
|
static void ptrace_untrace(struct task_struct *child)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
spin_lock(&child->sighand->siglock);
|
2007-12-07 00:06:16 +08:00
|
|
|
if (task_is_traced(child)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
if (child->signal->flags & SIGNAL_STOP_STOPPED) {
|
2008-02-06 17:36:13 +08:00
|
|
|
__set_task_state(child, TASK_STOPPED);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
|
|
|
signal_wake_up(child, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock(&child->sighand->siglock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* unptrace a task: move it back to its original parent and
|
|
|
|
* remove it from the ptrace list.
|
|
|
|
*
|
|
|
|
* Must be called with the tasklist lock write-held.
|
|
|
|
*/
|
2006-07-03 15:25:41 +08:00
|
|
|
void __ptrace_unlink(struct task_struct *child)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-02-16 03:50:10 +08:00
|
|
|
BUG_ON(!child->ptrace);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
child->ptrace = 0;
|
2008-03-25 09:36:23 +08:00
|
|
|
child->parent = child->real_parent;
|
|
|
|
list_del_init(&child->ptrace_entry);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-12-19 22:10:24 +08:00
|
|
|
arch_ptrace_untrace(child);
|
2007-12-07 00:06:16 +08:00
|
|
|
if (task_is_traced(child))
|
2006-04-13 07:30:20 +08:00
|
|
|
ptrace_untrace(child);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that we have indeed attached to the thing..
|
|
|
|
*/
|
|
|
|
int ptrace_check_attach(struct task_struct *child, int kill)
|
|
|
|
{
|
|
|
|
int ret = -ESRCH;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We take the read lock around doing both checks to close a
|
|
|
|
* possible race where someone else was tracing our child and
|
|
|
|
* detached between these two checks. After this locked check,
|
|
|
|
* we are sure that this is our traced child and that can only
|
|
|
|
* be changed by us so it's not changing right after this.
|
|
|
|
*/
|
|
|
|
read_lock(&tasklist_lock);
|
2008-02-08 20:19:00 +08:00
|
|
|
if ((child->ptrace & PT_PTRACED) && child->parent == current) {
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = 0;
|
2008-02-08 20:19:00 +08:00
|
|
|
/*
|
|
|
|
* child->sighand can't be NULL, release_task()
|
|
|
|
* does ptrace_unlink() before __exit_signal().
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
spin_lock_irq(&child->sighand->siglock);
|
2008-02-06 17:36:13 +08:00
|
|
|
if (task_is_stopped(child))
|
2005-04-17 06:20:36 +08:00
|
|
|
child->state = TASK_TRACED;
|
2008-02-06 17:36:13 +08:00
|
|
|
else if (!task_is_traced(child) && !kill)
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = -ESRCH;
|
|
|
|
spin_unlock_irq(&child->sighand->siglock);
|
|
|
|
}
|
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
|
2008-02-06 17:36:13 +08:00
|
|
|
if (!ret && !kill)
|
2008-07-26 10:45:58 +08:00
|
|
|
ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* All systems go.. */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Security: split proc ptrace checking into read vs. attach
Enable security modules to distinguish reading of process state via
proc from full ptrace access by renaming ptrace_may_attach to
ptrace_may_access and adding a mode argument indicating whether only
read access or full attach access is requested. This allows security
modules to permit access to reading process state without granting
full ptrace access. The base DAC/capability checking remains unchanged.
Read access to /proc/pid/mem continues to apply a full ptrace attach
check since check_mem_permission() already requires the current task
to already be ptracing the target. The other ptrace checks within
proc for elements like environ, maps, and fds are changed to pass the
read mode instead of attach.
In the SELinux case, we model such reading of process state as a
reading of a proc file labeled with the target process' label. This
enables SELinux policy to permit such reading of process state without
permitting control or manipulation of the target process, as there are
a number of cases where programs probe for such information via proc
but do not need to be able to control the target (e.g. procps,
lsof, PolicyKit, ConsoleKit). At present we have to choose between
allowing full ptrace in policy (more permissive than required/desired)
or breaking functionality (or in some cases just silencing the denials
via dontaudit rules but this can hide genuine attacks).
This version of the patch incorporates comments from Casey Schaufler
(change/replace existing ptrace_may_attach interface, pass access
mode), and Chris Wright (provide greater consistency in the checking).
Note that like their predecessors __ptrace_may_attach and
ptrace_may_attach, the __ptrace_may_access and ptrace_may_access
interfaces use different return value conventions from each other (0
or -errno vs. 1 or 0). I retained this difference to avoid any
changes to the caller logic but made the difference clearer by
changing the latter interface to return a bool rather than an int and
by adding a comment about it to ptrace.h for any future callers.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-05-19 20:32:49 +08:00
|
|
|
int __ptrace_may_access(struct task_struct *task, unsigned int mode)
|
2005-09-07 06:18:24 +08:00
|
|
|
{
|
2008-11-14 07:39:19 +08:00
|
|
|
const struct cred *cred = current_cred(), *tcred;
|
2008-11-14 07:39:16 +08:00
|
|
|
|
2006-06-26 15:25:59 +08:00
|
|
|
/* 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;
|
2008-11-14 07:39:19 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
tcred = __task_cred(task);
|
|
|
|
if ((cred->uid != tcred->euid ||
|
|
|
|
cred->uid != tcred->suid ||
|
|
|
|
cred->uid != tcred->uid ||
|
|
|
|
cred->gid != tcred->egid ||
|
|
|
|
cred->gid != tcred->sgid ||
|
|
|
|
cred->gid != tcred->gid) &&
|
|
|
|
!capable(CAP_SYS_PTRACE)) {
|
|
|
|
rcu_read_unlock();
|
2005-09-07 06:18:24 +08:00
|
|
|
return -EPERM;
|
2008-11-14 07:39:19 +08:00
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
2005-09-07 06:18:24 +08:00
|
|
|
smp_rmb();
|
2006-06-26 15:25:59 +08:00
|
|
|
if (task->mm)
|
2007-07-19 16:48:27 +08:00
|
|
|
dumpable = get_dumpable(task->mm);
|
2006-06-26 15:25:59 +08:00
|
|
|
if (!dumpable && !capable(CAP_SYS_PTRACE))
|
2005-09-07 06:18:24 +08:00
|
|
|
return -EPERM;
|
|
|
|
|
security: Fix setting of PF_SUPERPRIV by __capable()
Fix the setting of PF_SUPERPRIV by __capable() as it could corrupt the flags
the target process if that is not the current process and it is trying to
change its own flags in a different way at the same time.
__capable() is using neither atomic ops nor locking to protect t->flags. This
patch removes __capable() and introduces has_capability() that doesn't set
PF_SUPERPRIV on the process being queried.
This patch further splits security_ptrace() in two:
(1) security_ptrace_may_access(). This passes judgement on whether one
process may access another only (PTRACE_MODE_ATTACH for ptrace() and
PTRACE_MODE_READ for /proc), and takes a pointer to the child process.
current is the parent.
(2) security_ptrace_traceme(). This passes judgement on PTRACE_TRACEME only,
and takes only a pointer to the parent process. current is the child.
In Smack and commoncap, this uses has_capability() to determine whether
the parent will be permitted to use PTRACE_ATTACH if normal checks fail.
This does not set PF_SUPERPRIV.
Two of the instances of __capable() actually only act on current, and so have
been changed to calls to capable().
Of the places that were using __capable():
(1) The OOM killer calls __capable() thrice when weighing the killability of a
process. All of these now use has_capability().
(2) cap_ptrace() and smack_ptrace() were using __capable() to check to see
whether the parent was allowed to trace any process. As mentioned above,
these have been split. For PTRACE_ATTACH and /proc, capable() is now
used, and for PTRACE_TRACEME, has_capability() is used.
(3) cap_safe_nice() only ever saw current, so now uses capable().
(4) smack_setprocattr() rejected accesses to tasks other than current just
after calling __capable(), so the order of these two tests have been
switched and capable() is used instead.
(5) In smack_file_send_sigiotask(), we need to allow privileged processes to
receive SIGIO on files they're manipulating.
(6) In smack_task_wait(), we let a process wait for a privileged process,
whether or not the process doing the waiting is privileged.
I've tested this with the LTP SELinux and syscalls testscripts.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Acked-by: Andrew G. Morgan <morgan@kernel.org>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: James Morris <jmorris@namei.org>
2008-08-14 18:37:28 +08:00
|
|
|
return security_ptrace_may_access(task, mode);
|
2005-09-07 06:18:24 +08:00
|
|
|
}
|
|
|
|
|
Security: split proc ptrace checking into read vs. attach
Enable security modules to distinguish reading of process state via
proc from full ptrace access by renaming ptrace_may_attach to
ptrace_may_access and adding a mode argument indicating whether only
read access or full attach access is requested. This allows security
modules to permit access to reading process state without granting
full ptrace access. The base DAC/capability checking remains unchanged.
Read access to /proc/pid/mem continues to apply a full ptrace attach
check since check_mem_permission() already requires the current task
to already be ptracing the target. The other ptrace checks within
proc for elements like environ, maps, and fds are changed to pass the
read mode instead of attach.
In the SELinux case, we model such reading of process state as a
reading of a proc file labeled with the target process' label. This
enables SELinux policy to permit such reading of process state without
permitting control or manipulation of the target process, as there are
a number of cases where programs probe for such information via proc
but do not need to be able to control the target (e.g. procps,
lsof, PolicyKit, ConsoleKit). At present we have to choose between
allowing full ptrace in policy (more permissive than required/desired)
or breaking functionality (or in some cases just silencing the denials
via dontaudit rules but this can hide genuine attacks).
This version of the patch incorporates comments from Casey Schaufler
(change/replace existing ptrace_may_attach interface, pass access
mode), and Chris Wright (provide greater consistency in the checking).
Note that like their predecessors __ptrace_may_attach and
ptrace_may_attach, the __ptrace_may_access and ptrace_may_access
interfaces use different return value conventions from each other (0
or -errno vs. 1 or 0). I retained this difference to avoid any
changes to the caller logic but made the difference clearer by
changing the latter interface to return a bool rather than an int and
by adding a comment about it to ptrace.h for any future callers.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-05-19 20:32:49 +08:00
|
|
|
bool ptrace_may_access(struct task_struct *task, unsigned int mode)
|
2005-09-07 06:18:24 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
task_lock(task);
|
Security: split proc ptrace checking into read vs. attach
Enable security modules to distinguish reading of process state via
proc from full ptrace access by renaming ptrace_may_attach to
ptrace_may_access and adding a mode argument indicating whether only
read access or full attach access is requested. This allows security
modules to permit access to reading process state without granting
full ptrace access. The base DAC/capability checking remains unchanged.
Read access to /proc/pid/mem continues to apply a full ptrace attach
check since check_mem_permission() already requires the current task
to already be ptracing the target. The other ptrace checks within
proc for elements like environ, maps, and fds are changed to pass the
read mode instead of attach.
In the SELinux case, we model such reading of process state as a
reading of a proc file labeled with the target process' label. This
enables SELinux policy to permit such reading of process state without
permitting control or manipulation of the target process, as there are
a number of cases where programs probe for such information via proc
but do not need to be able to control the target (e.g. procps,
lsof, PolicyKit, ConsoleKit). At present we have to choose between
allowing full ptrace in policy (more permissive than required/desired)
or breaking functionality (or in some cases just silencing the denials
via dontaudit rules but this can hide genuine attacks).
This version of the patch incorporates comments from Casey Schaufler
(change/replace existing ptrace_may_attach interface, pass access
mode), and Chris Wright (provide greater consistency in the checking).
Note that like their predecessors __ptrace_may_attach and
ptrace_may_attach, the __ptrace_may_access and ptrace_may_access
interfaces use different return value conventions from each other (0
or -errno vs. 1 or 0). I retained this difference to avoid any
changes to the caller logic but made the difference clearer by
changing the latter interface to return a bool rather than an int and
by adding a comment about it to ptrace.h for any future callers.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-05-19 20:32:49 +08:00
|
|
|
err = __ptrace_may_access(task, mode);
|
2005-09-07 06:18:24 +08:00
|
|
|
task_unlock(task);
|
Security: split proc ptrace checking into read vs. attach
Enable security modules to distinguish reading of process state via
proc from full ptrace access by renaming ptrace_may_attach to
ptrace_may_access and adding a mode argument indicating whether only
read access or full attach access is requested. This allows security
modules to permit access to reading process state without granting
full ptrace access. The base DAC/capability checking remains unchanged.
Read access to /proc/pid/mem continues to apply a full ptrace attach
check since check_mem_permission() already requires the current task
to already be ptracing the target. The other ptrace checks within
proc for elements like environ, maps, and fds are changed to pass the
read mode instead of attach.
In the SELinux case, we model such reading of process state as a
reading of a proc file labeled with the target process' label. This
enables SELinux policy to permit such reading of process state without
permitting control or manipulation of the target process, as there are
a number of cases where programs probe for such information via proc
but do not need to be able to control the target (e.g. procps,
lsof, PolicyKit, ConsoleKit). At present we have to choose between
allowing full ptrace in policy (more permissive than required/desired)
or breaking functionality (or in some cases just silencing the denials
via dontaudit rules but this can hide genuine attacks).
This version of the patch incorporates comments from Casey Schaufler
(change/replace existing ptrace_may_attach interface, pass access
mode), and Chris Wright (provide greater consistency in the checking).
Note that like their predecessors __ptrace_may_attach and
ptrace_may_attach, the __ptrace_may_access and ptrace_may_access
interfaces use different return value conventions from each other (0
or -errno vs. 1 or 0). I retained this difference to avoid any
changes to the caller logic but made the difference clearer by
changing the latter interface to return a bool rather than an int and
by adding a comment about it to ptrace.h for any future callers.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-05-19 20:32:49 +08:00
|
|
|
return (!err ? true : false);
|
2005-09-07 06:18:24 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int ptrace_attach(struct task_struct *task)
|
|
|
|
{
|
|
|
|
int retval;
|
2007-07-16 14:39:26 +08:00
|
|
|
unsigned long flags;
|
2006-05-08 01:49:33 +08:00
|
|
|
|
2007-03-21 01:58:35 +08:00
|
|
|
audit_ptrace(task);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
retval = -EPERM;
|
2007-10-19 14:40:18 +08:00
|
|
|
if (same_thread_group(task, current))
|
2006-05-08 01:49:33 +08:00
|
|
|
goto out;
|
|
|
|
|
CRED: Inaugurate COW credentials
Inaugurate copy-on-write credentials management. This uses RCU to manage the
credentials pointer in the task_struct with respect to accesses by other tasks.
A process may only modify its own credentials, and so does not need locking to
access or modify its own credentials.
A mutex (cred_replace_mutex) is added to the task_struct to control the effect
of PTRACE_ATTACHED on credential calculations, particularly with respect to
execve().
With this patch, the contents of an active credentials struct may not be
changed directly; rather a new set of credentials must be prepared, modified
and committed using something like the following sequence of events:
struct cred *new = prepare_creds();
int ret = blah(new);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
There are some exceptions to this rule: the keyrings pointed to by the active
credentials may be instantiated - keyrings violate the COW rule as managing
COW keyrings is tricky, given that it is possible for a task to directly alter
the keys in a keyring in use by another task.
To help enforce this, various pointers to sets of credentials, such as those in
the task_struct, are declared const. The purpose of this is compile-time
discouragement of altering credentials through those pointers. Once a set of
credentials has been made public through one of these pointers, it may not be
modified, except under special circumstances:
(1) Its reference count may incremented and decremented.
(2) The keyrings to which it points may be modified, but not replaced.
The only safe way to modify anything else is to create a replacement and commit
using the functions described in Documentation/credentials.txt (which will be
added by a later patch).
This patch and the preceding patches have been tested with the LTP SELinux
testsuite.
This patch makes several logical sets of alteration:
(1) execve().
This now prepares and commits credentials in various places in the
security code rather than altering the current creds directly.
(2) Temporary credential overrides.
do_coredump() and sys_faccessat() now prepare their own credentials and
temporarily override the ones currently on the acting thread, whilst
preventing interference from other threads by holding cred_replace_mutex
on the thread being dumped.
This will be replaced in a future patch by something that hands down the
credentials directly to the functions being called, rather than altering
the task's objective credentials.
(3) LSM interface.
A number of functions have been changed, added or removed:
(*) security_capset_check(), ->capset_check()
(*) security_capset_set(), ->capset_set()
Removed in favour of security_capset().
(*) security_capset(), ->capset()
New. This is passed a pointer to the new creds, a pointer to the old
creds and the proposed capability sets. It should fill in the new
creds or return an error. All pointers, barring the pointer to the
new creds, are now const.
(*) security_bprm_apply_creds(), ->bprm_apply_creds()
Changed; now returns a value, which will cause the process to be
killed if it's an error.
(*) security_task_alloc(), ->task_alloc_security()
Removed in favour of security_prepare_creds().
(*) security_cred_free(), ->cred_free()
New. Free security data attached to cred->security.
(*) security_prepare_creds(), ->cred_prepare()
New. Duplicate any security data attached to cred->security.
(*) security_commit_creds(), ->cred_commit()
New. Apply any security effects for the upcoming installation of new
security by commit_creds().
(*) security_task_post_setuid(), ->task_post_setuid()
Removed in favour of security_task_fix_setuid().
(*) security_task_fix_setuid(), ->task_fix_setuid()
Fix up the proposed new credentials for setuid(). This is used by
cap_set_fix_setuid() to implicitly adjust capabilities in line with
setuid() changes. Changes are made to the new credentials, rather
than the task itself as in security_task_post_setuid().
(*) security_task_reparent_to_init(), ->task_reparent_to_init()
Removed. Instead the task being reparented to init is referred
directly to init's credentials.
NOTE! This results in the loss of some state: SELinux's osid no
longer records the sid of the thread that forked it.
(*) security_key_alloc(), ->key_alloc()
(*) security_key_permission(), ->key_permission()
Changed. These now take cred pointers rather than task pointers to
refer to the security context.
(4) sys_capset().
This has been simplified and uses less locking. The LSM functions it
calls have been merged.
(5) reparent_to_kthreadd().
This gives the current thread the same credentials as init by simply using
commit_thread() to point that way.
(6) __sigqueue_alloc() and switch_uid()
__sigqueue_alloc() can't stop the target task from changing its creds
beneath it, so this function gets a reference to the currently applicable
user_struct which it then passes into the sigqueue struct it returns if
successful.
switch_uid() is now called from commit_creds(), and possibly should be
folded into that. commit_creds() should take care of protecting
__sigqueue_alloc().
(7) [sg]et[ug]id() and co and [sg]et_current_groups.
The set functions now all use prepare_creds(), commit_creds() and
abort_creds() to build and check a new set of credentials before applying
it.
security_task_set[ug]id() is called inside the prepared section. This
guarantees that nothing else will affect the creds until we've finished.
The calling of set_dumpable() has been moved into commit_creds().
Much of the functionality of set_user() has been moved into
commit_creds().
The get functions all simply access the data directly.
(8) security_task_prctl() and cap_task_prctl().
security_task_prctl() has been modified to return -ENOSYS if it doesn't
want to handle a function, or otherwise return the return value directly
rather than through an argument.
Additionally, cap_task_prctl() now prepares a new set of credentials, even
if it doesn't end up using it.
(9) Keyrings.
A number of changes have been made to the keyrings code:
(a) switch_uid_keyring(), copy_keys(), exit_keys() and suid_keys() have
all been dropped and built in to the credentials functions directly.
They may want separating out again later.
(b) key_alloc() and search_process_keyrings() now take a cred pointer
rather than a task pointer to specify the security context.
(c) copy_creds() gives a new thread within the same thread group a new
thread keyring if its parent had one, otherwise it discards the thread
keyring.
(d) The authorisation key now points directly to the credentials to extend
the search into rather pointing to the task that carries them.
(e) Installing thread, process or session keyrings causes a new set of
credentials to be created, even though it's not strictly necessary for
process or session keyrings (they're shared).
(10) Usermode helper.
The usermode helper code now carries a cred struct pointer in its
subprocess_info struct instead of a new session keyring pointer. This set
of credentials is derived from init_cred and installed on the new process
after it has been cloned.
call_usermodehelper_setup() allocates the new credentials and
call_usermodehelper_freeinfo() discards them if they haven't been used. A
special cred function (prepare_usermodeinfo_creds()) is provided
specifically for call_usermodehelper_setup() to call.
call_usermodehelper_setkeys() adjusts the credentials to sport the
supplied keyring as the new session keyring.
(11) SELinux.
SELinux has a number of changes, in addition to those to support the LSM
interface changes mentioned above:
(a) selinux_setprocattr() no longer does its check for whether the
current ptracer can access processes with the new SID inside the lock
that covers getting the ptracer's SID. Whilst this lock ensures that
the check is done with the ptracer pinned, the result is only valid
until the lock is released, so there's no point doing it inside the
lock.
(12) is_single_threaded().
This function has been extracted from selinux_setprocattr() and put into
a file of its own in the lib/ directory as join_session_keyring() now
wants to use it too.
The code in SELinux just checked to see whether a task shared mm_structs
with other tasks (CLONE_VM), but that isn't good enough. We really want
to know if they're part of the same thread group (CLONE_THREAD).
(13) nfsd.
The NFS server daemon now has to use the COW credentials to set the
credentials it is going to use. It really needs to pass the credentials
down to the functions it calls, but it can't do that until other patches
in this series have been applied.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-11-14 07:39:23 +08:00
|
|
|
/* Protect exec's credential calculations against our interference;
|
|
|
|
* SUID, SGID and LSM creds get determined differently under ptrace.
|
|
|
|
*/
|
|
|
|
retval = mutex_lock_interruptible(¤t->cred_exec_mutex);
|
|
|
|
if (retval < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
retval = -EPERM;
|
2006-05-12 02:08:49 +08:00
|
|
|
repeat:
|
|
|
|
/*
|
|
|
|
* Nasty, nasty.
|
|
|
|
*
|
|
|
|
* We want to hold both the task-lock and the
|
|
|
|
* tasklist_lock for writing at the same time.
|
|
|
|
* But that's against the rules (tasklist_lock
|
|
|
|
* is taken for reading by interrupts on other
|
|
|
|
* cpu's that may have task_lock).
|
|
|
|
*/
|
2006-05-08 01:49:33 +08:00
|
|
|
task_lock(task);
|
2007-07-16 14:39:26 +08:00
|
|
|
if (!write_trylock_irqsave(&tasklist_lock, flags)) {
|
2006-05-12 02:08:49 +08:00
|
|
|
task_unlock(task);
|
|
|
|
do {
|
|
|
|
cpu_relax();
|
|
|
|
} while (!write_can_lock(&tasklist_lock));
|
|
|
|
goto repeat;
|
|
|
|
}
|
2006-05-08 01:49:33 +08:00
|
|
|
|
2006-06-26 15:25:59 +08:00
|
|
|
if (!task->mm)
|
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
/* the same process cannot be attached many times */
|
|
|
|
if (task->ptrace & PT_PTRACED)
|
|
|
|
goto bad;
|
Security: split proc ptrace checking into read vs. attach
Enable security modules to distinguish reading of process state via
proc from full ptrace access by renaming ptrace_may_attach to
ptrace_may_access and adding a mode argument indicating whether only
read access or full attach access is requested. This allows security
modules to permit access to reading process state without granting
full ptrace access. The base DAC/capability checking remains unchanged.
Read access to /proc/pid/mem continues to apply a full ptrace attach
check since check_mem_permission() already requires the current task
to already be ptracing the target. The other ptrace checks within
proc for elements like environ, maps, and fds are changed to pass the
read mode instead of attach.
In the SELinux case, we model such reading of process state as a
reading of a proc file labeled with the target process' label. This
enables SELinux policy to permit such reading of process state without
permitting control or manipulation of the target process, as there are
a number of cases where programs probe for such information via proc
but do not need to be able to control the target (e.g. procps,
lsof, PolicyKit, ConsoleKit). At present we have to choose between
allowing full ptrace in policy (more permissive than required/desired)
or breaking functionality (or in some cases just silencing the denials
via dontaudit rules but this can hide genuine attacks).
This version of the patch incorporates comments from Casey Schaufler
(change/replace existing ptrace_may_attach interface, pass access
mode), and Chris Wright (provide greater consistency in the checking).
Note that like their predecessors __ptrace_may_attach and
ptrace_may_attach, the __ptrace_may_access and ptrace_may_access
interfaces use different return value conventions from each other (0
or -errno vs. 1 or 0). I retained this difference to avoid any
changes to the caller logic but made the difference clearer by
changing the latter interface to return a bool rather than an int and
by adding a comment about it to ptrace.h for any future callers.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-05-19 20:32:49 +08:00
|
|
|
retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (retval)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/* Go */
|
2008-02-08 20:18:58 +08:00
|
|
|
task->ptrace |= PT_PTRACED;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (capable(CAP_SYS_PTRACE))
|
|
|
|
task->ptrace |= PT_PTRACE_CAP;
|
|
|
|
|
|
|
|
__ptrace_link(task, current);
|
|
|
|
|
2008-04-30 15:53:14 +08:00
|
|
|
send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
2007-07-16 14:39:26 +08:00
|
|
|
write_unlock_irqrestore(&tasklist_lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
task_unlock(task);
|
CRED: Inaugurate COW credentials
Inaugurate copy-on-write credentials management. This uses RCU to manage the
credentials pointer in the task_struct with respect to accesses by other tasks.
A process may only modify its own credentials, and so does not need locking to
access or modify its own credentials.
A mutex (cred_replace_mutex) is added to the task_struct to control the effect
of PTRACE_ATTACHED on credential calculations, particularly with respect to
execve().
With this patch, the contents of an active credentials struct may not be
changed directly; rather a new set of credentials must be prepared, modified
and committed using something like the following sequence of events:
struct cred *new = prepare_creds();
int ret = blah(new);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
There are some exceptions to this rule: the keyrings pointed to by the active
credentials may be instantiated - keyrings violate the COW rule as managing
COW keyrings is tricky, given that it is possible for a task to directly alter
the keys in a keyring in use by another task.
To help enforce this, various pointers to sets of credentials, such as those in
the task_struct, are declared const. The purpose of this is compile-time
discouragement of altering credentials through those pointers. Once a set of
credentials has been made public through one of these pointers, it may not be
modified, except under special circumstances:
(1) Its reference count may incremented and decremented.
(2) The keyrings to which it points may be modified, but not replaced.
The only safe way to modify anything else is to create a replacement and commit
using the functions described in Documentation/credentials.txt (which will be
added by a later patch).
This patch and the preceding patches have been tested with the LTP SELinux
testsuite.
This patch makes several logical sets of alteration:
(1) execve().
This now prepares and commits credentials in various places in the
security code rather than altering the current creds directly.
(2) Temporary credential overrides.
do_coredump() and sys_faccessat() now prepare their own credentials and
temporarily override the ones currently on the acting thread, whilst
preventing interference from other threads by holding cred_replace_mutex
on the thread being dumped.
This will be replaced in a future patch by something that hands down the
credentials directly to the functions being called, rather than altering
the task's objective credentials.
(3) LSM interface.
A number of functions have been changed, added or removed:
(*) security_capset_check(), ->capset_check()
(*) security_capset_set(), ->capset_set()
Removed in favour of security_capset().
(*) security_capset(), ->capset()
New. This is passed a pointer to the new creds, a pointer to the old
creds and the proposed capability sets. It should fill in the new
creds or return an error. All pointers, barring the pointer to the
new creds, are now const.
(*) security_bprm_apply_creds(), ->bprm_apply_creds()
Changed; now returns a value, which will cause the process to be
killed if it's an error.
(*) security_task_alloc(), ->task_alloc_security()
Removed in favour of security_prepare_creds().
(*) security_cred_free(), ->cred_free()
New. Free security data attached to cred->security.
(*) security_prepare_creds(), ->cred_prepare()
New. Duplicate any security data attached to cred->security.
(*) security_commit_creds(), ->cred_commit()
New. Apply any security effects for the upcoming installation of new
security by commit_creds().
(*) security_task_post_setuid(), ->task_post_setuid()
Removed in favour of security_task_fix_setuid().
(*) security_task_fix_setuid(), ->task_fix_setuid()
Fix up the proposed new credentials for setuid(). This is used by
cap_set_fix_setuid() to implicitly adjust capabilities in line with
setuid() changes. Changes are made to the new credentials, rather
than the task itself as in security_task_post_setuid().
(*) security_task_reparent_to_init(), ->task_reparent_to_init()
Removed. Instead the task being reparented to init is referred
directly to init's credentials.
NOTE! This results in the loss of some state: SELinux's osid no
longer records the sid of the thread that forked it.
(*) security_key_alloc(), ->key_alloc()
(*) security_key_permission(), ->key_permission()
Changed. These now take cred pointers rather than task pointers to
refer to the security context.
(4) sys_capset().
This has been simplified and uses less locking. The LSM functions it
calls have been merged.
(5) reparent_to_kthreadd().
This gives the current thread the same credentials as init by simply using
commit_thread() to point that way.
(6) __sigqueue_alloc() and switch_uid()
__sigqueue_alloc() can't stop the target task from changing its creds
beneath it, so this function gets a reference to the currently applicable
user_struct which it then passes into the sigqueue struct it returns if
successful.
switch_uid() is now called from commit_creds(), and possibly should be
folded into that. commit_creds() should take care of protecting
__sigqueue_alloc().
(7) [sg]et[ug]id() and co and [sg]et_current_groups.
The set functions now all use prepare_creds(), commit_creds() and
abort_creds() to build and check a new set of credentials before applying
it.
security_task_set[ug]id() is called inside the prepared section. This
guarantees that nothing else will affect the creds until we've finished.
The calling of set_dumpable() has been moved into commit_creds().
Much of the functionality of set_user() has been moved into
commit_creds().
The get functions all simply access the data directly.
(8) security_task_prctl() and cap_task_prctl().
security_task_prctl() has been modified to return -ENOSYS if it doesn't
want to handle a function, or otherwise return the return value directly
rather than through an argument.
Additionally, cap_task_prctl() now prepares a new set of credentials, even
if it doesn't end up using it.
(9) Keyrings.
A number of changes have been made to the keyrings code:
(a) switch_uid_keyring(), copy_keys(), exit_keys() and suid_keys() have
all been dropped and built in to the credentials functions directly.
They may want separating out again later.
(b) key_alloc() and search_process_keyrings() now take a cred pointer
rather than a task pointer to specify the security context.
(c) copy_creds() gives a new thread within the same thread group a new
thread keyring if its parent had one, otherwise it discards the thread
keyring.
(d) The authorisation key now points directly to the credentials to extend
the search into rather pointing to the task that carries them.
(e) Installing thread, process or session keyrings causes a new set of
credentials to be created, even though it's not strictly necessary for
process or session keyrings (they're shared).
(10) Usermode helper.
The usermode helper code now carries a cred struct pointer in its
subprocess_info struct instead of a new session keyring pointer. This set
of credentials is derived from init_cred and installed on the new process
after it has been cloned.
call_usermodehelper_setup() allocates the new credentials and
call_usermodehelper_freeinfo() discards them if they haven't been used. A
special cred function (prepare_usermodeinfo_creds()) is provided
specifically for call_usermodehelper_setup() to call.
call_usermodehelper_setkeys() adjusts the credentials to sport the
supplied keyring as the new session keyring.
(11) SELinux.
SELinux has a number of changes, in addition to those to support the LSM
interface changes mentioned above:
(a) selinux_setprocattr() no longer does its check for whether the
current ptracer can access processes with the new SID inside the lock
that covers getting the ptracer's SID. Whilst this lock ensures that
the check is done with the ptracer pinned, the result is only valid
until the lock is released, so there's no point doing it inside the
lock.
(12) is_single_threaded().
This function has been extracted from selinux_setprocattr() and put into
a file of its own in the lib/ directory as join_session_keyring() now
wants to use it too.
The code in SELinux just checked to see whether a task shared mm_structs
with other tasks (CLONE_VM), but that isn't good enough. We really want
to know if they're part of the same thread group (CLONE_THREAD).
(13) nfsd.
The NFS server daemon now has to use the COW credentials to set the
credentials it is going to use. It really needs to pass the credentials
down to the functions it calls, but it can't do that until other patches
in this series have been applied.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
Signed-off-by: James Morris <jmorris@namei.org>
2008-11-14 07:39:23 +08:00
|
|
|
mutex_unlock(¤t->cred_exec_mutex);
|
2006-05-08 01:49:33 +08:00
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2006-06-26 15:26:07 +08:00
|
|
|
static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
|
2006-02-16 03:50:10 +08:00
|
|
|
{
|
|
|
|
child->exit_code = data;
|
|
|
|
/* .. re-parent .. */
|
|
|
|
__ptrace_unlink(child);
|
|
|
|
/* .. and wake it up. */
|
|
|
|
if (child->exit_state != EXIT_ZOMBIE)
|
|
|
|
wake_up_process(child);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int ptrace_detach(struct task_struct *child, unsigned int data)
|
|
|
|
{
|
2005-05-01 23:59:14 +08:00
|
|
|
if (!valid_signal(data))
|
2006-02-16 03:50:10 +08:00
|
|
|
return -EIO;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Architecture-specific hardware disable .. */
|
|
|
|
ptrace_disable(child);
|
2007-09-05 18:05:56 +08:00
|
|
|
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
write_lock_irq(&tasklist_lock);
|
2006-06-26 15:26:07 +08:00
|
|
|
/* protect against de_thread()->release_task() */
|
2006-02-16 03:50:10 +08:00
|
|
|
if (child->ptrace)
|
|
|
|
__ptrace_detach(child, data);
|
2005-04-17 06:20:36 +08:00
|
|
|
write_unlock_irq(&tasklist_lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
|
|
|
|
{
|
|
|
|
int copied = 0;
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
char buf[128];
|
|
|
|
int this_len, retval;
|
|
|
|
|
|
|
|
this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
|
|
|
|
retval = access_process_vm(tsk, src, buf, this_len, 0);
|
|
|
|
if (!retval) {
|
|
|
|
if (copied)
|
|
|
|
break;
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
if (copy_to_user(dst, buf, retval))
|
|
|
|
return -EFAULT;
|
|
|
|
copied += retval;
|
|
|
|
src += retval;
|
|
|
|
dst += retval;
|
|
|
|
len -= retval;
|
|
|
|
}
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
|
|
|
|
{
|
|
|
|
int copied = 0;
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
char buf[128];
|
|
|
|
int this_len, retval;
|
|
|
|
|
|
|
|
this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
|
|
|
|
if (copy_from_user(buf, src, this_len))
|
|
|
|
return -EFAULT;
|
|
|
|
retval = access_process_vm(tsk, dst, buf, this_len, 1);
|
|
|
|
if (!retval) {
|
|
|
|
if (copied)
|
|
|
|
break;
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
copied += retval;
|
|
|
|
src += retval;
|
|
|
|
dst += retval;
|
|
|
|
len -= retval;
|
|
|
|
}
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ptrace_setoptions(struct task_struct *child, long data)
|
|
|
|
{
|
|
|
|
child->ptrace &= ~PT_TRACE_MASK;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACESYSGOOD)
|
|
|
|
child->ptrace |= PT_TRACESYSGOOD;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACEFORK)
|
|
|
|
child->ptrace |= PT_TRACE_FORK;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACEVFORK)
|
|
|
|
child->ptrace |= PT_TRACE_VFORK;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACECLONE)
|
|
|
|
child->ptrace |= PT_TRACE_CLONE;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACEEXEC)
|
|
|
|
child->ptrace |= PT_TRACE_EXEC;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACEVFORKDONE)
|
|
|
|
child->ptrace |= PT_TRACE_VFORK_DONE;
|
|
|
|
|
|
|
|
if (data & PTRACE_O_TRACEEXIT)
|
|
|
|
child->ptrace |= PT_TRACE_EXIT;
|
|
|
|
|
|
|
|
return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
|
|
|
|
}
|
|
|
|
|
2008-04-21 04:10:12 +08:00
|
|
|
static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int error = -ESRCH;
|
|
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
|
|
|
if (likely(child->sighand != NULL)) {
|
|
|
|
error = -EINVAL;
|
|
|
|
spin_lock_irq(&child->sighand->siglock);
|
|
|
|
if (likely(child->last_siginfo != NULL)) {
|
2008-04-21 04:10:12 +08:00
|
|
|
*info = *child->last_siginfo;
|
2005-04-17 06:20:36 +08:00
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(&child->sighand->siglock);
|
|
|
|
}
|
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-04-21 04:10:12 +08:00
|
|
|
static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int error = -ESRCH;
|
|
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
|
|
|
if (likely(child->sighand != NULL)) {
|
|
|
|
error = -EINVAL;
|
|
|
|
spin_lock_irq(&child->sighand->siglock);
|
|
|
|
if (likely(child->last_siginfo != NULL)) {
|
2008-04-21 04:10:12 +08:00
|
|
|
*child->last_siginfo = *info;
|
2005-04-17 06:20:36 +08:00
|
|
|
error = 0;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(&child->sighand->siglock);
|
|
|
|
}
|
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2008-01-30 20:30:51 +08:00
|
|
|
|
|
|
|
#ifdef PTRACE_SINGLESTEP
|
|
|
|
#define is_singlestep(request) ((request) == PTRACE_SINGLESTEP)
|
|
|
|
#else
|
|
|
|
#define is_singlestep(request) 0
|
|
|
|
#endif
|
|
|
|
|
2008-01-30 20:30:53 +08:00
|
|
|
#ifdef PTRACE_SINGLEBLOCK
|
|
|
|
#define is_singleblock(request) ((request) == PTRACE_SINGLEBLOCK)
|
|
|
|
#else
|
|
|
|
#define is_singleblock(request) 0
|
|
|
|
#endif
|
|
|
|
|
2008-01-30 20:30:51 +08:00
|
|
|
#ifdef PTRACE_SYSEMU
|
|
|
|
#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP)
|
|
|
|
#else
|
|
|
|
#define is_sysemu_singlestep(request) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int ptrace_resume(struct task_struct *child, long request, long data)
|
|
|
|
{
|
|
|
|
if (!valid_signal(data))
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (request == PTRACE_SYSCALL)
|
|
|
|
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
|
|
|
else
|
|
|
|
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
|
|
|
|
|
|
|
#ifdef TIF_SYSCALL_EMU
|
|
|
|
if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP)
|
|
|
|
set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
|
|
|
|
else
|
|
|
|
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
|
|
|
|
#endif
|
|
|
|
|
2008-01-30 20:30:53 +08:00
|
|
|
if (is_singleblock(request)) {
|
|
|
|
if (unlikely(!arch_has_block_step()))
|
|
|
|
return -EIO;
|
|
|
|
user_enable_block_step(child);
|
|
|
|
} else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
|
2008-01-30 20:30:51 +08:00
|
|
|
if (unlikely(!arch_has_single_step()))
|
|
|
|
return -EIO;
|
|
|
|
user_enable_single_step(child);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
user_disable_single_step(child);
|
|
|
|
|
|
|
|
child->exit_code = data;
|
|
|
|
wake_up_process(child);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int ptrace_request(struct task_struct *child, long request,
|
|
|
|
long addr, long data)
|
|
|
|
{
|
|
|
|
int ret = -EIO;
|
2008-04-21 04:10:12 +08:00
|
|
|
siginfo_t siginfo;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
switch (request) {
|
2008-01-30 20:31:47 +08:00
|
|
|
case PTRACE_PEEKTEXT:
|
|
|
|
case PTRACE_PEEKDATA:
|
|
|
|
return generic_ptrace_peekdata(child, addr, data);
|
|
|
|
case PTRACE_POKETEXT:
|
|
|
|
case PTRACE_POKEDATA:
|
|
|
|
return generic_ptrace_pokedata(child, addr, data);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef PTRACE_OLDSETOPTIONS
|
|
|
|
case PTRACE_OLDSETOPTIONS:
|
|
|
|
#endif
|
|
|
|
case PTRACE_SETOPTIONS:
|
|
|
|
ret = ptrace_setoptions(child, data);
|
|
|
|
break;
|
|
|
|
case PTRACE_GETEVENTMSG:
|
|
|
|
ret = put_user(child->ptrace_message, (unsigned long __user *) data);
|
|
|
|
break;
|
2008-04-21 04:10:12 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case PTRACE_GETSIGINFO:
|
2008-04-21 04:10:12 +08:00
|
|
|
ret = ptrace_getsiginfo(child, &siginfo);
|
|
|
|
if (!ret)
|
|
|
|
ret = copy_siginfo_to_user((siginfo_t __user *) data,
|
|
|
|
&siginfo);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2008-04-21 04:10:12 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case PTRACE_SETSIGINFO:
|
2008-04-21 04:10:12 +08:00
|
|
|
if (copy_from_user(&siginfo, (siginfo_t __user *) data,
|
|
|
|
sizeof siginfo))
|
|
|
|
ret = -EFAULT;
|
|
|
|
else
|
|
|
|
ret = ptrace_setsiginfo(child, &siginfo);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2008-04-21 04:10:12 +08:00
|
|
|
|
2007-10-16 16:23:45 +08:00
|
|
|
case PTRACE_DETACH: /* detach a process that was attached. */
|
|
|
|
ret = ptrace_detach(child, data);
|
|
|
|
break;
|
2008-01-30 20:30:51 +08:00
|
|
|
|
|
|
|
#ifdef PTRACE_SINGLESTEP
|
|
|
|
case PTRACE_SINGLESTEP:
|
|
|
|
#endif
|
2008-01-30 20:30:53 +08:00
|
|
|
#ifdef PTRACE_SINGLEBLOCK
|
|
|
|
case PTRACE_SINGLEBLOCK:
|
|
|
|
#endif
|
2008-01-30 20:30:51 +08:00
|
|
|
#ifdef PTRACE_SYSEMU
|
|
|
|
case PTRACE_SYSEMU:
|
|
|
|
case PTRACE_SYSEMU_SINGLESTEP:
|
|
|
|
#endif
|
|
|
|
case PTRACE_SYSCALL:
|
|
|
|
case PTRACE_CONT:
|
|
|
|
return ptrace_resume(child, request, data);
|
|
|
|
|
|
|
|
case PTRACE_KILL:
|
|
|
|
if (child->exit_state) /* already dead */
|
|
|
|
return 0;
|
|
|
|
return ptrace_resume(child, request, SIGKILL);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2005-11-07 16:59:47 +08:00
|
|
|
|
2006-01-08 17:02:33 +08:00
|
|
|
/**
|
|
|
|
* ptrace_traceme -- helper for PTRACE_TRACEME
|
|
|
|
*
|
|
|
|
* Performs checks and sets PT_PTRACED.
|
|
|
|
* Should be used by all ptrace implementations for PTRACE_TRACEME.
|
|
|
|
*/
|
|
|
|
int ptrace_traceme(void)
|
2005-11-07 16:59:47 +08:00
|
|
|
{
|
2006-05-08 01:49:33 +08:00
|
|
|
int ret = -EPERM;
|
2005-11-07 16:59:47 +08:00
|
|
|
|
|
|
|
/*
|
2006-01-08 17:02:33 +08:00
|
|
|
* Are we already being traced?
|
|
|
|
*/
|
2008-03-25 09:36:23 +08:00
|
|
|
repeat:
|
2006-05-08 01:49:33 +08:00
|
|
|
task_lock(current);
|
|
|
|
if (!(current->ptrace & PT_PTRACED)) {
|
2008-03-25 09:36:23 +08:00
|
|
|
/*
|
|
|
|
* See ptrace_attach() comments about the locking here.
|
|
|
|
*/
|
|
|
|
unsigned long flags;
|
|
|
|
if (!write_trylock_irqsave(&tasklist_lock, flags)) {
|
|
|
|
task_unlock(current);
|
|
|
|
do {
|
|
|
|
cpu_relax();
|
|
|
|
} while (!write_can_lock(&tasklist_lock));
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
security: Fix setting of PF_SUPERPRIV by __capable()
Fix the setting of PF_SUPERPRIV by __capable() as it could corrupt the flags
the target process if that is not the current process and it is trying to
change its own flags in a different way at the same time.
__capable() is using neither atomic ops nor locking to protect t->flags. This
patch removes __capable() and introduces has_capability() that doesn't set
PF_SUPERPRIV on the process being queried.
This patch further splits security_ptrace() in two:
(1) security_ptrace_may_access(). This passes judgement on whether one
process may access another only (PTRACE_MODE_ATTACH for ptrace() and
PTRACE_MODE_READ for /proc), and takes a pointer to the child process.
current is the parent.
(2) security_ptrace_traceme(). This passes judgement on PTRACE_TRACEME only,
and takes only a pointer to the parent process. current is the child.
In Smack and commoncap, this uses has_capability() to determine whether
the parent will be permitted to use PTRACE_ATTACH if normal checks fail.
This does not set PF_SUPERPRIV.
Two of the instances of __capable() actually only act on current, and so have
been changed to calls to capable().
Of the places that were using __capable():
(1) The OOM killer calls __capable() thrice when weighing the killability of a
process. All of these now use has_capability().
(2) cap_ptrace() and smack_ptrace() were using __capable() to check to see
whether the parent was allowed to trace any process. As mentioned above,
these have been split. For PTRACE_ATTACH and /proc, capable() is now
used, and for PTRACE_TRACEME, has_capability() is used.
(3) cap_safe_nice() only ever saw current, so now uses capable().
(4) smack_setprocattr() rejected accesses to tasks other than current just
after calling __capable(), so the order of these two tests have been
switched and capable() is used instead.
(5) In smack_file_send_sigiotask(), we need to allow privileged processes to
receive SIGIO on files they're manipulating.
(6) In smack_task_wait(), we let a process wait for a privileged process,
whether or not the process doing the waiting is privileged.
I've tested this with the LTP SELinux and syscalls testscripts.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Acked-by: Andrew G. Morgan <morgan@kernel.org>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: James Morris <jmorris@namei.org>
2008-08-14 18:37:28 +08:00
|
|
|
ret = security_ptrace_traceme(current->parent);
|
2008-03-25 09:36:23 +08:00
|
|
|
|
2006-05-08 01:49:33 +08:00
|
|
|
/*
|
|
|
|
* Set the ptrace bit in the process ptrace flags.
|
2008-03-25 09:36:23 +08:00
|
|
|
* Then link us on our parent's ptraced list.
|
2006-05-08 01:49:33 +08:00
|
|
|
*/
|
2008-03-25 09:36:23 +08:00
|
|
|
if (!ret) {
|
2006-05-08 01:49:33 +08:00
|
|
|
current->ptrace |= PT_PTRACED;
|
2008-03-25 09:36:23 +08:00
|
|
|
__ptrace_link(current, current->real_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
write_unlock_irqrestore(&tasklist_lock, flags);
|
2006-05-08 01:49:33 +08:00
|
|
|
}
|
|
|
|
task_unlock(current);
|
|
|
|
return ret;
|
2006-01-08 17:02:33 +08:00
|
|
|
}
|
2005-11-07 16:59:47 +08:00
|
|
|
|
2006-01-08 17:02:33 +08:00
|
|
|
/**
|
|
|
|
* ptrace_get_task_struct -- grab a task struct reference for ptrace
|
|
|
|
* @pid: process id to grab a task_struct reference of
|
|
|
|
*
|
|
|
|
* This function is a helper for ptrace implementations. It checks
|
|
|
|
* permissions and then grabs a task struct for use of the actual
|
|
|
|
* ptrace implementation.
|
|
|
|
*
|
|
|
|
* Returns the task_struct for @pid or an ERR_PTR() on failure.
|
|
|
|
*/
|
|
|
|
struct task_struct *ptrace_get_task_struct(pid_t pid)
|
|
|
|
{
|
|
|
|
struct task_struct *child;
|
2005-11-07 16:59:47 +08:00
|
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
2007-10-19 14:40:16 +08:00
|
|
|
child = find_task_by_vpid(pid);
|
2005-11-07 16:59:47 +08:00
|
|
|
if (child)
|
|
|
|
get_task_struct(child);
|
2006-09-29 17:00:07 +08:00
|
|
|
|
2005-11-07 16:59:47 +08:00
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
if (!child)
|
2006-01-08 17:02:33 +08:00
|
|
|
return ERR_PTR(-ESRCH);
|
|
|
|
return child;
|
2005-11-07 16:59:47 +08:00
|
|
|
}
|
|
|
|
|
2007-10-16 16:26:37 +08:00
|
|
|
#ifndef arch_ptrace_attach
|
|
|
|
#define arch_ptrace_attach(child) do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
2005-11-07 16:59:47 +08:00
|
|
|
asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
|
|
|
|
{
|
|
|
|
struct task_struct *child;
|
|
|
|
long ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This lock_kernel fixes a subtle race with suid exec
|
|
|
|
*/
|
|
|
|
lock_kernel();
|
2006-01-08 17:02:33 +08:00
|
|
|
if (request == PTRACE_TRACEME) {
|
|
|
|
ret = ptrace_traceme();
|
2007-11-27 20:02:40 +08:00
|
|
|
if (!ret)
|
|
|
|
arch_ptrace_attach(current);
|
2005-11-07 16:59:47 +08:00
|
|
|
goto out;
|
2006-01-08 17:02:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
child = ptrace_get_task_struct(pid);
|
|
|
|
if (IS_ERR(child)) {
|
|
|
|
ret = PTR_ERR(child);
|
|
|
|
goto out;
|
|
|
|
}
|
2005-11-07 16:59:47 +08:00
|
|
|
|
|
|
|
if (request == PTRACE_ATTACH) {
|
|
|
|
ret = ptrace_attach(child);
|
2007-10-16 16:26:37 +08:00
|
|
|
/*
|
|
|
|
* Some architectures need to do book-keeping after
|
|
|
|
* a ptrace attach.
|
|
|
|
*/
|
|
|
|
if (!ret)
|
|
|
|
arch_ptrace_attach(child);
|
2005-11-14 08:06:33 +08:00
|
|
|
goto out_put_task_struct;
|
2005-11-07 16:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = ptrace_check_attach(child, request == PTRACE_KILL);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_put_task_struct;
|
|
|
|
|
|
|
|
ret = arch_ptrace(child, request, addr, data);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out_put_task_struct;
|
|
|
|
|
|
|
|
out_put_task_struct:
|
|
|
|
put_task_struct(child);
|
|
|
|
out:
|
|
|
|
unlock_kernel();
|
|
|
|
return ret;
|
|
|
|
}
|
2007-07-17 19:03:43 +08:00
|
|
|
|
|
|
|
int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
|
|
|
|
{
|
|
|
|
unsigned long tmp;
|
|
|
|
int copied;
|
|
|
|
|
|
|
|
copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0);
|
|
|
|
if (copied != sizeof(tmp))
|
|
|
|
return -EIO;
|
|
|
|
return put_user(tmp, (unsigned long __user *)data);
|
|
|
|
}
|
2007-07-17 19:03:44 +08:00
|
|
|
|
|
|
|
int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
|
|
|
|
{
|
|
|
|
int copied;
|
|
|
|
|
|
|
|
copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);
|
|
|
|
return (copied == sizeof(data)) ? 0 : -EIO;
|
|
|
|
}
|
2008-01-30 20:31:47 +08:00
|
|
|
|
2008-11-25 15:10:03 +08:00
|
|
|
#if defined CONFIG_COMPAT
|
2008-01-30 20:31:47 +08:00
|
|
|
#include <linux/compat.h>
|
|
|
|
|
|
|
|
int compat_ptrace_request(struct task_struct *child, compat_long_t request,
|
|
|
|
compat_ulong_t addr, compat_ulong_t data)
|
|
|
|
{
|
|
|
|
compat_ulong_t __user *datap = compat_ptr(data);
|
|
|
|
compat_ulong_t word;
|
2008-04-21 04:10:12 +08:00
|
|
|
siginfo_t siginfo;
|
2008-01-30 20:31:47 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
switch (request) {
|
|
|
|
case PTRACE_PEEKTEXT:
|
|
|
|
case PTRACE_PEEKDATA:
|
|
|
|
ret = access_process_vm(child, addr, &word, sizeof(word), 0);
|
|
|
|
if (ret != sizeof(word))
|
|
|
|
ret = -EIO;
|
|
|
|
else
|
|
|
|
ret = put_user(word, datap);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PTRACE_POKETEXT:
|
|
|
|
case PTRACE_POKEDATA:
|
|
|
|
ret = access_process_vm(child, addr, &data, sizeof(data), 1);
|
|
|
|
ret = (ret != sizeof(data) ? -EIO : 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PTRACE_GETEVENTMSG:
|
|
|
|
ret = put_user((compat_ulong_t) child->ptrace_message, datap);
|
|
|
|
break;
|
|
|
|
|
2008-04-21 04:10:12 +08:00
|
|
|
case PTRACE_GETSIGINFO:
|
|
|
|
ret = ptrace_getsiginfo(child, &siginfo);
|
|
|
|
if (!ret)
|
|
|
|
ret = copy_siginfo_to_user32(
|
|
|
|
(struct compat_siginfo __user *) datap,
|
|
|
|
&siginfo);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PTRACE_SETSIGINFO:
|
|
|
|
memset(&siginfo, 0, sizeof siginfo);
|
|
|
|
if (copy_siginfo_from_user32(
|
|
|
|
&siginfo, (struct compat_siginfo __user *) datap))
|
|
|
|
ret = -EFAULT;
|
|
|
|
else
|
|
|
|
ret = ptrace_setsiginfo(child, &siginfo);
|
|
|
|
break;
|
|
|
|
|
2008-01-30 20:31:47 +08:00
|
|
|
default:
|
|
|
|
ret = ptrace_request(child, request, addr, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2008-01-30 20:31:48 +08:00
|
|
|
|
|
|
|
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
|
|
|
|
compat_long_t addr, compat_long_t data)
|
|
|
|
{
|
|
|
|
struct task_struct *child;
|
|
|
|
long ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This lock_kernel fixes a subtle race with suid exec
|
|
|
|
*/
|
|
|
|
lock_kernel();
|
|
|
|
if (request == PTRACE_TRACEME) {
|
|
|
|
ret = ptrace_traceme();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
child = ptrace_get_task_struct(pid);
|
|
|
|
if (IS_ERR(child)) {
|
|
|
|
ret = PTR_ERR(child);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (request == PTRACE_ATTACH) {
|
|
|
|
ret = ptrace_attach(child);
|
|
|
|
/*
|
|
|
|
* Some architectures need to do book-keeping after
|
|
|
|
* a ptrace attach.
|
|
|
|
*/
|
|
|
|
if (!ret)
|
|
|
|
arch_ptrace_attach(child);
|
|
|
|
goto out_put_task_struct;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ptrace_check_attach(child, request == PTRACE_KILL);
|
|
|
|
if (!ret)
|
|
|
|
ret = compat_arch_ptrace(child, request, addr, data);
|
|
|
|
|
|
|
|
out_put_task_struct:
|
|
|
|
put_task_struct(child);
|
|
|
|
out:
|
|
|
|
unlock_kernel();
|
|
|
|
return ret;
|
|
|
|
}
|
2008-11-25 15:10:03 +08:00
|
|
|
#endif /* CONFIG_COMPAT */
|