Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-23 Thread Oleg Nesterov
On 11/22, KOSAKI Motohiro wrote:
>
> >> I have found no problem in this patch. However, I have a very basic 
> >> question.
> >> Why do we need to keep fs->in_exec?
> >
> > To ensure that a sub-thread can't create a new process with the same
> > ->fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
> > is only for security/ code.
>
> But in LSM_UNSAFE_SHARE case, we have no check, right? I'm amazing why
> we don't need anything.

Yes. We rely on security/ code in this case, it can nack this exec if it
looks unsafe.

IOW. If LSM_UNSAFE_SHARE is not set, we promise that this fs has a single
user: the execing thread (it will kill other subthreads which can have the
same fs). That is why we need to cancel any attempt to create another
CLONE_FS process in between.

But let me repeat this is only my speculations, I know nothing about selinux
and selinux_bprm_set_creds() in particular. Although it looks obvious that
potentially exec with the shared ->fs has the additional security problems.

Kosaki, thank you for review!

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-23 Thread Oleg Nesterov
On 11/22, KOSAKI Motohiro wrote:

  I have found no problem in this patch. However, I have a very basic 
  question.
  Why do we need to keep fs-in_exec?
 
  To ensure that a sub-thread can't create a new process with the same
  -fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
  is only for security/ code.

 But in LSM_UNSAFE_SHARE case, we have no check, right? I'm amazing why
 we don't need anything.

Yes. We rely on security/ code in this case, it can nack this exec if it
looks unsafe.

IOW. If LSM_UNSAFE_SHARE is not set, we promise that this fs has a single
user: the execing thread (it will kill other subthreads which can have the
same fs). That is why we need to cancel any attempt to create another
CLONE_FS process in between.

But let me repeat this is only my speculations, I know nothing about selinux
and selinux_bprm_set_creds() in particular. Although it looks obvious that
potentially exec with the shared -fs has the additional security problems.

Kosaki, thank you for review!

Oleg.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread KOSAKI Motohiro
>> I have found no problem in this patch. However, I have a very basic question.
>> Why do we need to keep fs->in_exec?
> 
> To ensure that a sub-thread can't create a new process with the same
> ->fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
> is only for security/ code.

But in LSM_UNSAFE_SHARE case, we have no check, right? I'm amazing why
we don't need anything.


> 
>> If it is correct,
>> can't we move it it to signal->in_exec?
> 
> Yes, perhaps, I am thinking about more cleanups too. But not that this
> will add the subtle change. CLONE_THREAD doesn't require CLONE_FS, so
> copy_fs() can fail even it the caller doesn't share ->fs with the execing
> thread. And we still need fs->lock to set signal->in_exec, this looks
> a bit strange.

Oops. Yes, this is totally odd. Sorry, we need to stop off topic discussion.
Anyway

Acked-by: KOSAKI Motohiro 

> 
>> I am not expert in this area and I may overlook something.
> 
> Neither me ;) So this patch tries to not change the current logic.
> 
> I feel that perhaps we can do more cleanups, but I am not really sure
> and this needs a separate change.



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread Oleg Nesterov
On 11/22, KOSAKI Motohiro wrote:
>
> (11/22/2013 12:54 PM), Oleg Nesterov wrote:
> > fs_struct->in_exec == T means that this ->fs is used by a single
> > process (thread group), and one of the treads does do_execve().
> >
> > To avoid the mt-exec races this code has the following complications:
> >
> > 1. check_unsafe_exec() returns -EBUSY if ->in_exec was
> >already set by another thread.
> >
> > 2. do_execve_common() records "clear_in_exec" to ensure
> >that the error path can only clear ->in_exec if it was
> >set by current.
> >
> > However, after 9b1bf12d5d51 "signals: move cred_guard_mutex from
> > task_struct to signal_struct" we do not need these complications:
> >
> > 1. We can't race with our sub-thread, this is called under
> >per-process ->cred_guard_mutex. And we can't race with
> >another CLONE_FS task, we already checked that this fs
> >is not shared.
> >
> >We can remove the  dead -EAGAIN logic.
> >
> > 2. "out_unmark:" in do_execve_common() is either called
> >under ->cred_guard_mutex, or after de_thread() which
> >kills other threads, so we can't race with sub-thread
> >which could set ->in_exec. And if ->fs is shared with
> >another process ->in_exec should be false anyway.
> >
> >We can clear in_exec unconditionally.
> >
> > This also means that check_unsafe_exec() can be void.
> >
> > Signed-off-by: Oleg Nesterov 
>
> I have found no problem in this patch. However, I have a very basic question.
> Why do we need to keep fs->in_exec?

To ensure that a sub-thread can't create a new process with the same
->fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
is only for security/ code.

> If it is correct,
> can't we move it it to signal->in_exec?

Yes, perhaps, I am thinking about more cleanups too. But not that this
will add the subtle change. CLONE_THREAD doesn't require CLONE_FS, so
copy_fs() can fail even it the caller doesn't share ->fs with the execing
thread. And we still need fs->lock to set signal->in_exec, this looks
a bit strange.

> I am not expert in this area and I may overlook something.

Neither me ;) So this patch tries to not change the current logic.

I feel that perhaps we can do more cleanups, but I am not really sure
and this needs a separate change.

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread KOSAKI Motohiro
(11/22/2013 12:54 PM), Oleg Nesterov wrote:
> fs_struct->in_exec == T means that this ->fs is used by a single
> process (thread group), and one of the treads does do_execve().
> 
> To avoid the mt-exec races this code has the following complications:
> 
>   1. check_unsafe_exec() returns -EBUSY if ->in_exec was
>  already set by another thread.
> 
>   2. do_execve_common() records "clear_in_exec" to ensure
>  that the error path can only clear ->in_exec if it was
>  set by current.
> 
> However, after 9b1bf12d5d51 "signals: move cred_guard_mutex from
> task_struct to signal_struct" we do not need these complications:
> 
>   1. We can't race with our sub-thread, this is called under
>  per-process ->cred_guard_mutex. And we can't race with
>  another CLONE_FS task, we already checked that this fs
>  is not shared.
> 
>  We can remove the  dead -EAGAIN logic.
> 
>   2. "out_unmark:" in do_execve_common() is either called
>  under ->cred_guard_mutex, or after de_thread() which
>  kills other threads, so we can't race with sub-thread
>  which could set ->in_exec. And if ->fs is shared with
>  another process ->in_exec should be false anyway.
> 
>  We can clear in_exec unconditionally.
> 
> This also means that check_unsafe_exec() can be void.
> 
> Signed-off-by: Oleg Nesterov 

I have found no problem in this patch. However, I have a very basic question.
Why do we need to keep fs->in_exec? If I understand correctly, it is needed for
retrieving fork() and exec() race in the same process. If it is correct,
can't we move it it to signal->in_exec? It seems to match 
signal->cred_guard_mutex
and _I_ can easily understand what the code want.

In the other words, currently we have no protection against making new thread 
when
p->fs is shared w/ another process and I have no idea why multi process sharing 
influence
multi thread behavior.

I am not expert in this area and I may overlook something. Please correct me if 
I am silly.


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread Oleg Nesterov
fs_struct->in_exec == T means that this ->fs is used by a single
process (thread group), and one of the treads does do_execve().

To avoid the mt-exec races this code has the following complications:

1. check_unsafe_exec() returns -EBUSY if ->in_exec was
   already set by another thread.

2. do_execve_common() records "clear_in_exec" to ensure
   that the error path can only clear ->in_exec if it was
   set by current.

However, after 9b1bf12d5d51 "signals: move cred_guard_mutex from
task_struct to signal_struct" we do not need these complications:

1. We can't race with our sub-thread, this is called under
   per-process ->cred_guard_mutex. And we can't race with
   another CLONE_FS task, we already checked that this fs
   is not shared.

   We can remove the  dead -EAGAIN logic.

2. "out_unmark:" in do_execve_common() is either called
   under ->cred_guard_mutex, or after de_thread() which
   kills other threads, so we can't race with sub-thread
   which could set ->in_exec. And if ->fs is shared with
   another process ->in_exec should be false anyway.

   We can clear in_exec unconditionally.

This also means that check_unsafe_exec() can be void.

Signed-off-by: Oleg Nesterov 
---
 fs/exec.c |   29 -
 1 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 0cd9c25..60eb5c5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1225,11 +1225,10 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold ->cred_guard_mutex to protect against
  *   PTRACE_ATTACH
  */
-static int check_unsafe_exec(struct linux_binprm *bprm)
+static void check_unsafe_exec(struct linux_binprm *bprm)
 {
struct task_struct *p = current, *t;
unsigned n_fs;
-   int res = 0;
 
if (p->ptrace) {
if (p->ptrace & PT_PTRACE_CAP)
@@ -1255,22 +1254,15 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
}
rcu_read_unlock();
 
-   if (p->fs->users > n_fs) {
+   if (p->fs->users > n_fs)
bprm->unsafe |= LSM_UNSAFE_SHARE;
-   } else {
-   res = -EAGAIN;
-   if (!p->fs->in_exec) {
-   p->fs->in_exec = 1;
-   res = 1;
-   }
-   }
+   else
+   p->fs->in_exec = 1;
spin_unlock(>fs->lock);
-
-   return res;
 }
 
-/* 
- * Fill the binprm structure from the inode. 
+/*
+ * Fill the binprm structure from the inode.
  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
  *
  * This may be called multiple times for binary chains (scripts for example).
@@ -1461,7 +1453,6 @@ static int do_execve_common(const char *filename,
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
-   bool clear_in_exec;
int retval;
 
/*
@@ -1493,10 +1484,7 @@ static int do_execve_common(const char *filename,
if (retval)
goto out_free;
 
-   retval = check_unsafe_exec(bprm);
-   if (retval < 0)
-   goto out_free;
-   clear_in_exec = retval;
+   check_unsafe_exec(bprm);
current->in_execve = 1;
 
file = open_exec(filename);
@@ -1565,8 +1553,7 @@ out_file:
}
 
 out_unmark:
-   if (clear_in_exec)
-   current->fs->in_exec = 0;
+   current->fs->in_exec = 0;
current->in_execve = 0;
 
 out_free:
-- 
1.5.5.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread Oleg Nesterov
fs_struct-in_exec == T means that this -fs is used by a single
process (thread group), and one of the treads does do_execve().

To avoid the mt-exec races this code has the following complications:

1. check_unsafe_exec() returns -EBUSY if -in_exec was
   already set by another thread.

2. do_execve_common() records clear_in_exec to ensure
   that the error path can only clear -in_exec if it was
   set by current.

However, after 9b1bf12d5d51 signals: move cred_guard_mutex from
task_struct to signal_struct we do not need these complications:

1. We can't race with our sub-thread, this is called under
   per-process -cred_guard_mutex. And we can't race with
   another CLONE_FS task, we already checked that this fs
   is not shared.

   We can remove the  dead -EAGAIN logic.

2. out_unmark: in do_execve_common() is either called
   under -cred_guard_mutex, or after de_thread() which
   kills other threads, so we can't race with sub-thread
   which could set -in_exec. And if -fs is shared with
   another process -in_exec should be false anyway.

   We can clear in_exec unconditionally.

This also means that check_unsafe_exec() can be void.

Signed-off-by: Oleg Nesterov o...@redhat.com
---
 fs/exec.c |   29 -
 1 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 0cd9c25..60eb5c5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1225,11 +1225,10 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold -cred_guard_mutex to protect against
  *   PTRACE_ATTACH
  */
-static int check_unsafe_exec(struct linux_binprm *bprm)
+static void check_unsafe_exec(struct linux_binprm *bprm)
 {
struct task_struct *p = current, *t;
unsigned n_fs;
-   int res = 0;
 
if (p-ptrace) {
if (p-ptrace  PT_PTRACE_CAP)
@@ -1255,22 +1254,15 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
}
rcu_read_unlock();
 
-   if (p-fs-users  n_fs) {
+   if (p-fs-users  n_fs)
bprm-unsafe |= LSM_UNSAFE_SHARE;
-   } else {
-   res = -EAGAIN;
-   if (!p-fs-in_exec) {
-   p-fs-in_exec = 1;
-   res = 1;
-   }
-   }
+   else
+   p-fs-in_exec = 1;
spin_unlock(p-fs-lock);
-
-   return res;
 }
 
-/* 
- * Fill the binprm structure from the inode. 
+/*
+ * Fill the binprm structure from the inode.
  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
  *
  * This may be called multiple times for binary chains (scripts for example).
@@ -1461,7 +1453,6 @@ static int do_execve_common(const char *filename,
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
-   bool clear_in_exec;
int retval;
 
/*
@@ -1493,10 +1484,7 @@ static int do_execve_common(const char *filename,
if (retval)
goto out_free;
 
-   retval = check_unsafe_exec(bprm);
-   if (retval  0)
-   goto out_free;
-   clear_in_exec = retval;
+   check_unsafe_exec(bprm);
current-in_execve = 1;
 
file = open_exec(filename);
@@ -1565,8 +1553,7 @@ out_file:
}
 
 out_unmark:
-   if (clear_in_exec)
-   current-fs-in_exec = 0;
+   current-fs-in_exec = 0;
current-in_execve = 0;
 
 out_free:
-- 
1.5.5.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread KOSAKI Motohiro
(11/22/2013 12:54 PM), Oleg Nesterov wrote:
 fs_struct-in_exec == T means that this -fs is used by a single
 process (thread group), and one of the treads does do_execve().
 
 To avoid the mt-exec races this code has the following complications:
 
   1. check_unsafe_exec() returns -EBUSY if -in_exec was
  already set by another thread.
 
   2. do_execve_common() records clear_in_exec to ensure
  that the error path can only clear -in_exec if it was
  set by current.
 
 However, after 9b1bf12d5d51 signals: move cred_guard_mutex from
 task_struct to signal_struct we do not need these complications:
 
   1. We can't race with our sub-thread, this is called under
  per-process -cred_guard_mutex. And we can't race with
  another CLONE_FS task, we already checked that this fs
  is not shared.
 
  We can remove the  dead -EAGAIN logic.
 
   2. out_unmark: in do_execve_common() is either called
  under -cred_guard_mutex, or after de_thread() which
  kills other threads, so we can't race with sub-thread
  which could set -in_exec. And if -fs is shared with
  another process -in_exec should be false anyway.
 
  We can clear in_exec unconditionally.
 
 This also means that check_unsafe_exec() can be void.
 
 Signed-off-by: Oleg Nesterov o...@redhat.com

I have found no problem in this patch. However, I have a very basic question.
Why do we need to keep fs-in_exec? If I understand correctly, it is needed for
retrieving fork() and exec() race in the same process. If it is correct,
can't we move it it to signal-in_exec? It seems to match 
signal-cred_guard_mutex
and _I_ can easily understand what the code want.

In the other words, currently we have no protection against making new thread 
when
p-fs is shared w/ another process and I have no idea why multi process sharing 
influence
multi thread behavior.

I am not expert in this area and I may overlook something. Please correct me if 
I am silly.


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread Oleg Nesterov
On 11/22, KOSAKI Motohiro wrote:

 (11/22/2013 12:54 PM), Oleg Nesterov wrote:
  fs_struct-in_exec == T means that this -fs is used by a single
  process (thread group), and one of the treads does do_execve().
 
  To avoid the mt-exec races this code has the following complications:
 
  1. check_unsafe_exec() returns -EBUSY if -in_exec was
 already set by another thread.
 
  2. do_execve_common() records clear_in_exec to ensure
 that the error path can only clear -in_exec if it was
 set by current.
 
  However, after 9b1bf12d5d51 signals: move cred_guard_mutex from
  task_struct to signal_struct we do not need these complications:
 
  1. We can't race with our sub-thread, this is called under
 per-process -cred_guard_mutex. And we can't race with
 another CLONE_FS task, we already checked that this fs
 is not shared.
 
 We can remove the  dead -EAGAIN logic.
 
  2. out_unmark: in do_execve_common() is either called
 under -cred_guard_mutex, or after de_thread() which
 kills other threads, so we can't race with sub-thread
 which could set -in_exec. And if -fs is shared with
 another process -in_exec should be false anyway.
 
 We can clear in_exec unconditionally.
 
  This also means that check_unsafe_exec() can be void.
 
  Signed-off-by: Oleg Nesterov o...@redhat.com

 I have found no problem in this patch. However, I have a very basic question.
 Why do we need to keep fs-in_exec?

To ensure that a sub-thread can't create a new process with the same
-fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
is only for security/ code.

 If it is correct,
 can't we move it it to signal-in_exec?

Yes, perhaps, I am thinking about more cleanups too. But not that this
will add the subtle change. CLONE_THREAD doesn't require CLONE_FS, so
copy_fs() can fail even it the caller doesn't share -fs with the execing
thread. And we still need fs-lock to set signal-in_exec, this looks
a bit strange.

 I am not expert in this area and I may overlook something.

Neither me ;) So this patch tries to not change the current logic.

I feel that perhaps we can do more cleanups, but I am not really sure
and this needs a separate change.

Oleg.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

2013-11-22 Thread KOSAKI Motohiro
 I have found no problem in this patch. However, I have a very basic question.
 Why do we need to keep fs-in_exec?
 
 To ensure that a sub-thread can't create a new process with the same
 -fs while we are doing exec without LSM_UNSAFE_SHARE, I guess. This
 is only for security/ code.

But in LSM_UNSAFE_SHARE case, we have no check, right? I'm amazing why
we don't need anything.


 
 If it is correct,
 can't we move it it to signal-in_exec?
 
 Yes, perhaps, I am thinking about more cleanups too. But not that this
 will add the subtle change. CLONE_THREAD doesn't require CLONE_FS, so
 copy_fs() can fail even it the caller doesn't share -fs with the execing
 thread. And we still need fs-lock to set signal-in_exec, this looks
 a bit strange.

Oops. Yes, this is totally odd. Sorry, we need to stop off topic discussion.
Anyway

Acked-by: KOSAKI Motohiro kosaki.motoh...@jp.fujitsu.com

 
 I am not expert in this area and I may overlook something.
 
 Neither me ;) So this patch tries to not change the current logic.
 
 I feel that perhaps we can do more cleanups, but I am not really sure
 and this needs a separate change.



--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/