Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-12-07 Thread Kees Cook
On Sat, Dec 5, 2015 at 6:04 PM, Jann Horn  wrote:
> By checking the effective credentials instead of the real UID /
> permitted capabilities, ensure that the calling process actually
> intended to use its credentials.
>
> To ensure that all ptrace checks use the correct caller
> credentials (e.g. in case out-of-tree code or newly added code
> omits the PTRACE_MODE_*CREDS flag), use two new flags and
> require one of them to be set.
>
> The problem was that when a privileged task had temporarily dropped
> its privileges, e.g. by calling setreuid(0, user_uid), with the
> intent to perform following syscalls with the credentials of
> a user, it still passed ptrace access checks that the user would
> not be able to pass.
>
> While an attacker should not be able to convince the privileged
> task to perform a ptrace() syscall, this is a problem because the
> ptrace access check is reused for things in procfs.
>
> In particular, the following somewhat interesting procfs entries
> only rely on ptrace access checks:
>
>  /proc/$pid/stat - uses the check for determining whether pointers
>  should be visible, useful for bypassing ASLR
>  /proc/$pid/maps - also useful for bypassing ASLR
>  /proc/$pid/cwd - useful for gaining access to restricted
>  directories that contain files with lax permissions, e.g. in
>  this scenario:
>  lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
>  drwx-- root root /root
>  drwxr-xr-x root root /root/foobar
>  -rw-r--r-- root root /root/foobar/secret
>
> Therefore, on a system where a root-owned mode 6755 binary
> changes its effective credentials as described and then dumps a
> user-specified file, this could be used by an attacker to reveal
> the memory layout of root's processes or reveal the contents of
> files he is not allowed to access (through /proc/$pid/cwd).
>
> Signed-off-by: Jann Horn 
> ---
>  fs/proc/array.c|  2 +-
>  fs/proc/base.c | 21 +++--
>  fs/proc/namespaces.c   |  4 ++--
>  include/linux/ptrace.h | 24 +++-
>  kernel/events/core.c   |  2 +-
>  kernel/futex.c |  2 +-
>  kernel/futex_compat.c  |  2 +-
>  kernel/kcmp.c  |  4 ++--
>  kernel/ptrace.c| 36 +---
>  mm/process_vm_access.c |  2 +-
>  security/commoncap.c   |  7 ++-
>  11 files changed, 78 insertions(+), 28 deletions(-)
>
> diff --git a/fs/proc/array.c b/fs/proc/array.c
> index d73291f..b6c00ce 100644
> --- a/fs/proc/array.c
> +++ b/fs/proc/array.c
> @@ -395,7 +395,7 @@ static int do_task_stat(struct seq_file *m, struct 
> pid_namespace *ns,
>
> state = *get_task_state(task);
> vsize = eip = esp = 0;
> -   permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
> PTRACE_MODE_NOAUDIT);
> +   permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | 
> PTRACE_MODE_NOAUDIT);
> mm = get_task_mm(task);
> if (mm) {
> vsize = task_vsize(mm);
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index bd3e9e6..c0a2f29 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -403,7 +403,7 @@ static const struct file_operations proc_pid_cmdline_ops 
> = {
>  static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
>  struct pid *pid, struct task_struct *task)
>  {
> -   struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ);
> +   struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
> if (mm && !IS_ERR(mm)) {
> unsigned int nwords = 0;
> do {
> @@ -430,7 +430,8 @@ static int proc_pid_wchan(struct seq_file *m, struct 
> pid_namespace *ns,
>
> wchan = get_wchan(task);
>
> -   if (wchan && ptrace_may_access(task, PTRACE_MODE_READ) && 
> !lookup_symbol_name(wchan, symname))
> +   if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)
> +   && !lookup_symbol_name(wchan, symname))
> seq_printf(m, "%s", symname);
> else
> seq_putc(m, '0');
> @@ -444,7 +445,7 @@ static int lock_trace(struct task_struct *task)
> int err = mutex_lock_killable(>signal->cred_guard_mutex);
> if (err)
> return err;
> -   if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
> +   if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
> mutex_unlock(>signal->cred_guard_mutex);
> return -EPERM;
> }
> @@ -697,7 +698,7 @@ static int proc_fd_access_allowed(struct inode *inode)
>  */
> task = get_proc_task(inode);
> if (task) {
> -   allowed = ptrace_may_access(task, PTRACE_MODE_READ);
> +   allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
> put_task_struct(task);
> }
> return allowed;
> @@ -732,7 +733,7 @@ static bool has_pid_permissions(struct pid_namespace *pid,
>

Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-12-07 Thread Jann Horn
On Mon, Dec 07, 2015 at 12:32:06PM -0800, Kees Cook wrote:
> On Sat, Dec 5, 2015 at 6:04 PM, Jann Horn  wrote:
[...]
> > -   if (ptrace_may_access(task, PTRACE_MODE_READ)) {
> > +   if (ptrace_may_access(task, PTRACE_MODE_READ | 
> > PTRACE_MODE_FSCREDS)) {
> 
> This should maybe use the PTRACE_MODE_READ_FSCREDS macro?

Oh, yes. I don't know how I missed that. :/


> > error = ns_get_path(_path, task, ns_ops);
> > if (!error)
> > nd_jump_link(_path);
> > @@ -63,7 +63,7 @@ static int proc_ns_readlink(struct dentry *dentry, char 
> > __user *buffer, int bufl
> > if (!task)
> > return res;
> >
> > -   if (ptrace_may_access(task, PTRACE_MODE_READ)) {
> > +   if (ptrace_may_access(task, PTRACE_MODE_READ | 
> > PTRACE_MODE_FSCREDS)) {
> 
> same here?

Yes.

signature.asc
Description: Digital signature


Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-12-07 Thread Jann Horn
Whoops. After Kees pointed out my last mistake, I decided to grep around a bit 
to make sure
I didn't miss anything else and noticed that apparently, Yama and Smack aren't 
completely
aware that the ptrace access mode can have flags ORed in? Until now, it was 
just the
NOAUDIT flag for /proc/$pid/stat, but with my patch, that would have been 
broken completely
as far as I can tell. I don't use either of those LSMs and didn't test with 
them.

Can the LSM maintainers have a look at this and say whether this looks okay now?
--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-12-05 Thread Jann Horn
By checking the effective credentials instead of the real UID /
permitted capabilities, ensure that the calling process actually
intended to use its credentials.

To ensure that all ptrace checks use the correct caller
credentials (e.g. in case out-of-tree code or newly added code
omits the PTRACE_MODE_*CREDS flag), use two new flags and
require one of them to be set.

The problem was that when a privileged task had temporarily dropped
its privileges, e.g. by calling setreuid(0, user_uid), with the
intent to perform following syscalls with the credentials of
a user, it still passed ptrace access checks that the user would
not be able to pass.

While an attacker should not be able to convince the privileged
task to perform a ptrace() syscall, this is a problem because the
ptrace access check is reused for things in procfs.

In particular, the following somewhat interesting procfs entries
only rely on ptrace access checks:

 /proc/$pid/stat - uses the check for determining whether pointers
 should be visible, useful for bypassing ASLR
 /proc/$pid/maps - also useful for bypassing ASLR
 /proc/$pid/cwd - useful for gaining access to restricted
 directories that contain files with lax permissions, e.g. in
 this scenario:
 lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
 drwx-- root root /root
 drwxr-xr-x root root /root/foobar
 -rw-r--r-- root root /root/foobar/secret

Therefore, on a system where a root-owned mode 6755 binary
changes its effective credentials as described and then dumps a
user-specified file, this could be used by an attacker to reveal
the memory layout of root's processes or reveal the contents of
files he is not allowed to access (through /proc/$pid/cwd).

Signed-off-by: Jann Horn 
---
 fs/proc/array.c|  2 +-
 fs/proc/base.c | 21 +++--
 fs/proc/namespaces.c   |  4 ++--
 include/linux/ptrace.h | 24 +++-
 kernel/events/core.c   |  2 +-
 kernel/futex.c |  2 +-
 kernel/futex_compat.c  |  2 +-
 kernel/kcmp.c  |  4 ++--
 kernel/ptrace.c| 36 +---
 mm/process_vm_access.c |  2 +-
 security/commoncap.c   |  7 ++-
 11 files changed, 78 insertions(+), 28 deletions(-)

diff --git a/fs/proc/array.c b/fs/proc/array.c
index d73291f..b6c00ce 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -395,7 +395,7 @@ static int do_task_stat(struct seq_file *m, struct 
pid_namespace *ns,
 
state = *get_task_state(task);
vsize = eip = esp = 0;
-   permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
PTRACE_MODE_NOAUDIT);
+   permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | 
PTRACE_MODE_NOAUDIT);
mm = get_task_mm(task);
if (mm) {
vsize = task_vsize(mm);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index bd3e9e6..c0a2f29 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -403,7 +403,7 @@ static const struct file_operations proc_pid_cmdline_ops = {
 static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
 struct pid *pid, struct task_struct *task)
 {
-   struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ);
+   struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
if (mm && !IS_ERR(mm)) {
unsigned int nwords = 0;
do {
@@ -430,7 +430,8 @@ static int proc_pid_wchan(struct seq_file *m, struct 
pid_namespace *ns,
 
wchan = get_wchan(task);
 
-   if (wchan && ptrace_may_access(task, PTRACE_MODE_READ) && 
!lookup_symbol_name(wchan, symname))
+   if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)
+   && !lookup_symbol_name(wchan, symname))
seq_printf(m, "%s", symname);
else
seq_putc(m, '0');
@@ -444,7 +445,7 @@ static int lock_trace(struct task_struct *task)
int err = mutex_lock_killable(>signal->cred_guard_mutex);
if (err)
return err;
-   if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+   if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
mutex_unlock(>signal->cred_guard_mutex);
return -EPERM;
}
@@ -697,7 +698,7 @@ static int proc_fd_access_allowed(struct inode *inode)
 */
task = get_proc_task(inode);
if (task) {
-   allowed = ptrace_may_access(task, PTRACE_MODE_READ);
+   allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
put_task_struct(task);
}
return allowed;
@@ -732,7 +733,7 @@ static bool has_pid_permissions(struct pid_namespace *pid,
return true;
if (in_group_p(pid->pid_gid))
return true;
-   return ptrace_may_access(task, PTRACE_MODE_READ);
+   return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
 }
 
 
@@ -809,7 +810,7 @@ struct mm_struct *proc_mem_open(struct 

Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-11-09 Thread Willy Tarreau
On Mon, Nov 09, 2015 at 12:55:54PM -0800, Andrew Morton wrote:
> > --- a/fs/proc/array.c
> > +++ b/fs/proc/array.c
> > @@ -395,7 +395,8 @@ static int do_task_stat(struct seq_file *m, struct 
> > pid_namespace *ns,
> >  
> > state = *get_task_state(task);
> > vsize = eip = esp = 0;
> > -   permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
> > PTRACE_MODE_NOAUDIT);
> > +   permitted = ptrace_may_access(task,
> > +   PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT | PTRACE_MODE_FSCREDS);
> 
> There's lots of ugliness in the patch to do with fitting code into 80 cols. 
> Can we do
> 
> #define PTRACE_foo (PTRACE_MODE_READ|PTRACE_MODE_FSCREDS)
> 
> to avoid all that?

Or even simply bypass the 80-cols rule. Making code ugly or less easy
to read for sake of an arbitrary rule is often not fun, and that's even
more so when it comes to security fixes that people are expected to
easily understand next time they put their fingers there.

Willy

--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-11-09 Thread Jann Horn
On Mon, Nov 09, 2015 at 12:55:54PM -0800, Andrew Morton wrote:
> On Sun,  8 Nov 2015 13:08:36 +0100 Jann Horn  wrote:
> 
> > By checking the effective credentials instead of the real UID /
> > permitted capabilities, ensure that the calling process actually
> > intended to use its credentials.
> > 
> > To ensure that all ptrace checks use the correct caller
> > credentials (e.g. in case out-of-tree code or newly added code
> > omits the PTRACE_MODE_*CREDS flag), use two new flags and
> > require one of them to be set.
> > 
> > The problem was that when a privileged task had temporarily dropped
> > its privileges, e.g. by calling setreuid(0, user_uid), with the
> > intent to perform following syscalls with the credentials of
> > a user, it still passed ptrace access checks that the user would
> > not be able to pass.
> > 
> > While an attacker should not be able to convince the privileged
> > task to perform a ptrace() syscall, this is a problem because the
> > ptrace access check is reused for things in procfs.
> > 
> > In particular, the following somewhat interesting procfs entries
> > only rely on ptrace access checks:
> > 
> >  /proc/$pid/stat - uses the check for determining whether pointers
> >  should be visible, useful for bypassing ASLR
> >  /proc/$pid/maps - also useful for bypassing ASLR
> >  /proc/$pid/cwd - useful for gaining access to restricted
> >  directories that contain files with lax permissions, e.g. in
> >  this scenario:
> >  lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
> >  drwx-- root root /root
> >  drwxr-xr-x root root /root/foobar
> >  -rw-r--r-- root root /root/foobar/secret
> > 
> > Therefore, on a system where a root-owned mode 6755 binary
> > changes its effective credentials as described and then dumps a
> > user-specified file, this could be used by an attacker to reveal
> > the memory layout of root's processes or reveal the contents of
> > files he is not allowed to access (through /proc/$pid/cwd).
> 
> I'll await reviewer input on this one.  Meanwhile, a bunch of
> minor(ish) things...
> 
> > --- a/fs/proc/array.c
> > +++ b/fs/proc/array.c
> > @@ -395,7 +395,8 @@ static int do_task_stat(struct seq_file *m, struct 
> > pid_namespace *ns,
> >  
> > state = *get_task_state(task);
> > vsize = eip = esp = 0;
> > -   permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
> > PTRACE_MODE_NOAUDIT);
> > +   permitted = ptrace_may_access(task,
> > +   PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT | PTRACE_MODE_FSCREDS);
> 
> There's lots of ugliness in the patch to do with fitting code into 80 cols.

I agree.


> Can we do
> 
> #define PTRACE_foo (PTRACE_MODE_READ|PTRACE_MODE_FSCREDS)
> 
> to avoid all that?

Hm. All combinations of the PTRACE_MODE_*CREDS flags with
PTRACE_MODE_{READ,ATTACH} plus optionally PTRACE_MODE_NOAUDIT
make sense, I think. So your suggestion would be to create
four new #defines
PTRACE_MODE_{READ,ATTACH}_{FSCREDS,REALCREDS} and then let
callers OR in the PTRACE_MODE_NOAUDIT flag if needed?


> > --- a/include/linux/ptrace.h
> > +++ b/include/linux/ptrace.h
> > @@ -57,7 +57,22 @@ extern void exit_ptrace(struct task_struct *tracer, 
> > struct list_head *dead);
> >  #define PTRACE_MODE_READ   0x01
> >  #define PTRACE_MODE_ATTACH 0x02
> >  #define PTRACE_MODE_NOAUDIT0x04
> > -/* Returns true on success, false on denial. */
> > +#define PTRACE_MODE_FSCREDS 0x08
> > +#define PTRACE_MODE_REALCREDS 0x10
> > +/**
> > + * ptrace_may_access - check whether the caller is permitted to access
> > + * a target task.
> > + * @task: target task
> > + * @mode: selects type of access and caller credentials
> > + *
> > + * Returns true on success, false on denial.
> > + *
> > + * One of the flags PTRACE_MODE_FSCREDS and PTRACE_MODE_REALCREDS must
> > + * be set in @mode to specify whether the access was requested through
> > + * a filesystem syscall (should use effective capabilities and fsuid
> > + * of the caller) or through an explicit syscall such as
> > + * process_vm_writev or ptrace (and should use the real credentials).
> > + */
> >  extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
> 
> It is unconventional to put the kernedoc in the header - people have
> been trained to look for it in the .c file.

OK, will fix that. I thought it would be appropriate to put it in the
header since that one-line comment was already there.


> > +++ b/kernel/ptrace.c
> > @@ -219,6 +219,13 @@ static int ptrace_has_cap(struct user_namespace *ns, 
> > unsigned int mode)
> >  static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
> >  {
> > const struct cred *cred = current_cred(), *tcred;
> > +   kuid_t caller_uid;
> > +   kgid_t caller_gid;
> > +
> > +   if (!(mode & PTRACE_MODE_FSCREDS) != !(mode & PTRACE_MODE_REALCREDS)) {
> 
> So setting either one of these and not the other is an error.  How
> come?

Oh. Sorry about that. I only added PTRACE_MODE_REALCREDS 

Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-11-09 Thread Andrew Morton
On Mon, 9 Nov 2015 22:12:09 +0100 Jann Horn  wrote:
> 
> > Can we do
> > 
> > #define PTRACE_foo (PTRACE_MODE_READ|PTRACE_MODE_FSCREDS)
> > 
> > to avoid all that?
> 
> Hm. All combinations of the PTRACE_MODE_*CREDS flags with
> PTRACE_MODE_{READ,ATTACH} plus optionally PTRACE_MODE_NOAUDIT
> make sense, I think. So your suggestion would be to create
> four new #defines
> PTRACE_MODE_{READ,ATTACH}_{FSCREDS,REALCREDS} and then let
> callers OR in the PTRACE_MODE_NOAUDIT flag if needed?

If these flag combinations have an identifiable concept behind them then
sure, it makes sense to capture that via a well-chosen identifier.


--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-11-09 Thread Andrew Morton
On Sun,  8 Nov 2015 13:08:36 +0100 Jann Horn  wrote:

> By checking the effective credentials instead of the real UID /
> permitted capabilities, ensure that the calling process actually
> intended to use its credentials.
> 
> To ensure that all ptrace checks use the correct caller
> credentials (e.g. in case out-of-tree code or newly added code
> omits the PTRACE_MODE_*CREDS flag), use two new flags and
> require one of them to be set.
> 
> The problem was that when a privileged task had temporarily dropped
> its privileges, e.g. by calling setreuid(0, user_uid), with the
> intent to perform following syscalls with the credentials of
> a user, it still passed ptrace access checks that the user would
> not be able to pass.
> 
> While an attacker should not be able to convince the privileged
> task to perform a ptrace() syscall, this is a problem because the
> ptrace access check is reused for things in procfs.
> 
> In particular, the following somewhat interesting procfs entries
> only rely on ptrace access checks:
> 
>  /proc/$pid/stat - uses the check for determining whether pointers
>  should be visible, useful for bypassing ASLR
>  /proc/$pid/maps - also useful for bypassing ASLR
>  /proc/$pid/cwd - useful for gaining access to restricted
>  directories that contain files with lax permissions, e.g. in
>  this scenario:
>  lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
>  drwx-- root root /root
>  drwxr-xr-x root root /root/foobar
>  -rw-r--r-- root root /root/foobar/secret
> 
> Therefore, on a system where a root-owned mode 6755 binary
> changes its effective credentials as described and then dumps a
> user-specified file, this could be used by an attacker to reveal
> the memory layout of root's processes or reveal the contents of
> files he is not allowed to access (through /proc/$pid/cwd).

I'll await reviewer input on this one.  Meanwhile, a bunch of
minor(ish) things...

> --- a/fs/proc/array.c
> +++ b/fs/proc/array.c
> @@ -395,7 +395,8 @@ static int do_task_stat(struct seq_file *m, struct 
> pid_namespace *ns,
>  
>   state = *get_task_state(task);
>   vsize = eip = esp = 0;
> - permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
> PTRACE_MODE_NOAUDIT);
> + permitted = ptrace_may_access(task,
> + PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT | PTRACE_MODE_FSCREDS);

There's lots of ugliness in the patch to do with fitting code into 80 cols. 
Can we do

#define PTRACE_foo (PTRACE_MODE_READ|PTRACE_MODE_FSCREDS)

to avoid all that?

> --- a/include/linux/ptrace.h
> +++ b/include/linux/ptrace.h
> @@ -57,7 +57,22 @@ extern void exit_ptrace(struct task_struct *tracer, struct 
> list_head *dead);
>  #define PTRACE_MODE_READ 0x01
>  #define PTRACE_MODE_ATTACH   0x02
>  #define PTRACE_MODE_NOAUDIT  0x04
> -/* Returns true on success, false on denial. */
> +#define PTRACE_MODE_FSCREDS 0x08
> +#define PTRACE_MODE_REALCREDS 0x10
> +/**
> + * ptrace_may_access - check whether the caller is permitted to access
> + * a target task.
> + * @task: target task
> + * @mode: selects type of access and caller credentials
> + *
> + * Returns true on success, false on denial.
> + *
> + * One of the flags PTRACE_MODE_FSCREDS and PTRACE_MODE_REALCREDS must
> + * be set in @mode to specify whether the access was requested through
> + * a filesystem syscall (should use effective capabilities and fsuid
> + * of the caller) or through an explicit syscall such as
> + * process_vm_writev or ptrace (and should use the real credentials).
> + */
>  extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);

It is unconventional to put the kernedoc in the header - people have
been trained to look for it in the .c file.

> +++ b/kernel/ptrace.c
> @@ -219,6 +219,13 @@ static int ptrace_has_cap(struct user_namespace *ns, 
> unsigned int mode)
>  static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
>  {
>   const struct cred *cred = current_cred(), *tcred;
> + kuid_t caller_uid;
> + kgid_t caller_gid;
> +
> + if (!(mode & PTRACE_MODE_FSCREDS) != !(mode & PTRACE_MODE_REALCREDS)) {

So setting either one of these and not the other is an error.  How
come?

> + WARN(1, "denying ptrace access check without 
> PTRACE_MODE_*CREDS\n");

This warning cannot be triggered by malicious userspace, I trust?
--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ptrace: use fsuid, fsgid, effective creds for fs access checks

2015-11-08 Thread Jann Horn
By checking the effective credentials instead of the real UID /
permitted capabilities, ensure that the calling process actually
intended to use its credentials.

To ensure that all ptrace checks use the correct caller
credentials (e.g. in case out-of-tree code or newly added code
omits the PTRACE_MODE_*CREDS flag), use two new flags and
require one of them to be set.

The problem was that when a privileged task had temporarily dropped
its privileges, e.g. by calling setreuid(0, user_uid), with the
intent to perform following syscalls with the credentials of
a user, it still passed ptrace access checks that the user would
not be able to pass.

While an attacker should not be able to convince the privileged
task to perform a ptrace() syscall, this is a problem because the
ptrace access check is reused for things in procfs.

In particular, the following somewhat interesting procfs entries
only rely on ptrace access checks:

 /proc/$pid/stat - uses the check for determining whether pointers
 should be visible, useful for bypassing ASLR
 /proc/$pid/maps - also useful for bypassing ASLR
 /proc/$pid/cwd - useful for gaining access to restricted
 directories that contain files with lax permissions, e.g. in
 this scenario:
 lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
 drwx-- root root /root
 drwxr-xr-x root root /root/foobar
 -rw-r--r-- root root /root/foobar/secret

Therefore, on a system where a root-owned mode 6755 binary
changes its effective credentials as described and then dumps a
user-specified file, this could be used by an attacker to reveal
the memory layout of root's processes or reveal the contents of
files he is not allowed to access (through /proc/$pid/cwd).

Signed-off-by: Jann Horn 
---
 fs/proc/array.c|  3 ++-
 fs/proc/base.c | 24 ++--
 fs/proc/namespaces.c   |  4 ++--
 include/linux/ptrace.h | 17 -
 kernel/events/core.c   |  2 +-
 kernel/futex.c |  2 +-
 kernel/futex_compat.c  |  2 +-
 kernel/kcmp.c  |  6 --
 kernel/ptrace.c| 37 ++---
 mm/process_vm_access.c |  2 +-
 security/commoncap.c   |  7 ++-
 11 files changed, 78 insertions(+), 28 deletions(-)

diff --git a/fs/proc/array.c b/fs/proc/array.c
index f60f012..00928c6 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -395,7 +395,8 @@ static int do_task_stat(struct seq_file *m, struct 
pid_namespace *ns,
 
state = *get_task_state(task);
vsize = eip = esp = 0;
-   permitted = ptrace_may_access(task, PTRACE_MODE_READ | 
PTRACE_MODE_NOAUDIT);
+   permitted = ptrace_may_access(task,
+   PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT | PTRACE_MODE_FSCREDS);
mm = get_task_mm(task);
if (mm) {
vsize = task_vsize(mm);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b25eee4..d6b9475 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -403,7 +403,8 @@ static const struct file_operations proc_pid_cmdline_ops = {
 static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
 struct pid *pid, struct task_struct *task)
 {
-   struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ);
+   struct mm_struct *mm = mm_access(task,
+   PTRACE_MODE_READ | PTRACE_MODE_FSCREDS);
if (mm && !IS_ERR(mm)) {
unsigned int nwords = 0;
do {
@@ -431,7 +432,8 @@ static int proc_pid_wchan(struct seq_file *m, struct 
pid_namespace *ns,
wchan = get_wchan(task);
 
if (lookup_symbol_name(wchan, symname) < 0) {
-   if (!ptrace_may_access(task, PTRACE_MODE_READ))
+   if (!ptrace_may_access(task,
+   PTRACE_MODE_READ | PTRACE_MODE_FSCREDS))
return 0;
seq_printf(m, "%lu", wchan);
} else {
@@ -447,7 +449,8 @@ static int lock_trace(struct task_struct *task)
int err = mutex_lock_killable(>signal->cred_guard_mutex);
if (err)
return err;
-   if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+   if (!ptrace_may_access(task,
+   PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS)) {
mutex_unlock(>signal->cred_guard_mutex);
return -EPERM;
}
@@ -700,7 +703,8 @@ static int proc_fd_access_allowed(struct inode *inode)
 */
task = get_proc_task(inode);
if (task) {
-   allowed = ptrace_may_access(task, PTRACE_MODE_READ);
+   allowed = ptrace_may_access(task,
+   PTRACE_MODE_READ | PTRACE_MODE_FSCREDS);
put_task_struct(task);
}
return allowed;
@@ -735,7 +739,7 @@ static bool has_pid_permissions(struct pid_namespace *pid,
return true;
if (in_group_p(pid->pid_gid))
return true;
-   return ptrace_may_access(task, PTRACE_MODE_READ);