Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1612711 > unrolled thread
| Started by | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| First post | 2017-03-30 10:20 +0200 |
| Last post | 2017-04-04 01:00 +0200 |
| Articles | 15 on this page of 35 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [RFC][PATCH] exec: Don't wait for ptraced threads to be reaped. ebiederm@xmission.com (Eric W. Biederman) - 2017-03-30 10:20 +0200
[RFC][PATCH 0/2] exec: Fixing ptrace'd mulit-threaded hang ebiederm@xmission.com (Eric W. Biederman) - 2017-04-01 07:20 +0200
[RFC][PATCH 1/2] sighand: Count each thread group once in sighand_struct ebiederm@xmission.com (Eric W. Biederman) - 2017-04-01 07:20 +0200
[RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped ebiederm@xmission.com (Eric W. Biederman) - 2017-04-01 07:30 +0200
Re: [RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped Oleg Nesterov <oleg@redhat.com> - 2017-04-02 17:40 +0200
Re: [RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped ebiederm@xmission.com (Eric W. Biederman) - 2017-04-02 21:00 +0200
Re: [RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped Oleg Nesterov <oleg@redhat.com> - 2017-04-03 20:20 +0200
Re: [RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 23:20 +0200
Re: [RFC][PATCH 2/2] exec: If possible don't wait for ptraced threads to be reaped Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:50 +0200
Re: [RFC][PATCH 0/2] exec: Fixing ptrace'd mulit-threaded hang Oleg Nesterov <oleg@redhat.com> - 2017-04-02 17:40 +0200
[RFC][PATCH v2 4/5] exec: If possible don't wait for ptraced threads to be reaped ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:00 +0200
Re: [RFC][PATCH v2 4/5] exec: If possible don't wait for ptraced threads to be reaped Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:20 +0200
[RFC][PATCH v2 1/5] ptrace: Don't wait in PTRACE_O_TRACEEXIT for exec or coredump ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:00 +0200
Re: [RFC][PATCH v2 1/5] ptrace: Don't wait in PTRACE_O_TRACEEXIT for exec or coredump Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:30 +0200
[RFC][PATCH v2 0/5] exec: Fixing ptrace'd mulit-threaded hang ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:00 +0200
[RFC][PATCH v2 3/5] clone: Disallown CLONE_THREAD with a shared sighand_struct ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:00 +0200
Re: [RFC][PATCH v2 3/5] clone: Disallown CLONE_THREAD with a shared sighand_struct Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:30 +0200
Re: [RFC][PATCH v2 3/5] clone: Disallown CLONE_THREAD with a shared sighand_struct ebiederm@xmission.com (Eric W. Biederman) - 2017-04-05 19:50 +0200
Re: [RFC][PATCH v2 3/5] clone: Disallown CLONE_THREAD with a shared sighand_struct Oleg Nesterov <oleg@redhat.com> - 2017-04-05 20:20 +0200
[RFC][PATCH v2 2/5] sighand: Count each thread group once in sighand_struct ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:00 +0200
[RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec ebiederm@xmission.com (Eric W. Biederman) - 2017-04-03 01:10 +0200
Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:20 +0200
Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec ebiederm@xmission.com (Eric W. Biederman) - 2017-04-05 20:30 +0200
Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec Oleg Nesterov <oleg@redhat.com> - 2017-04-06 18:00 +0200
Re: [RFC][PATCH] exec: Don't wait for ptraced threads to be reaped. Oleg Nesterov <oleg@redhat.com> - 2017-04-02 18:20 +0200
Re: [RFC][PATCH] exec: Don't wait for ptraced threads to be reaped. ebiederm@xmission.com (Eric W. Biederman) - 2017-04-02 23:20 +0200
Re: [RFC][PATCH] exec: Don't wait for ptraced threads to be reaped. Oleg Nesterov <oleg@redhat.com> - 2017-04-03 20:40 +0200
scope of cred_guard_mutex. ebiederm@xmission.com (Eric W. Biederman) - 2017-04-04 01:00 +0200
Re: scope of cred_guard_mutex. Oleg Nesterov <oleg@redhat.com> - 2017-04-05 18:10 +0200
Re: scope of cred_guard_mutex. Kees Cook <keescook@chromium.org> - 2017-04-05 18:20 +0200
Re: scope of cred_guard_mutex. ebiederm@xmission.com (Eric W. Biederman) - 2017-04-05 20:10 +0200
Re: scope of cred_guard_mutex. Oleg Nesterov <oleg@redhat.com> - 2017-04-05 20:20 +0200
Re: scope of cred_guard_mutex. Oleg Nesterov <oleg@redhat.com> - 2017-04-06 18:00 +0200
Re: scope of cred_guard_mutex. Kees Cook <keescook@chromium.org> - 2017-04-08 00:10 +0200
Re: [RFC][PATCH] exec: Don't wait for ptraced threads to be reaped. ebiederm@xmission.com (Eric W. Biederman) - 2017-04-04 01:00 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-03 01:10 +0200 |
| Subject | [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec |
| Message-ID | <trWNb-78a-5@gated-at.bofh.it> |
| In reply to | #1614834 |
Add exec_id to signal_struct and compare it at a few choice moments.
I believe this closes the security holes that letting the zombie
threads linger after exec opens up.
The problem is that old threads may have different creds after a setuid
exec, and then formerly shared resources may change. So signal sending
and accesses by proc need to be blocked.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
fs/exec.c | 1 +
include/linux/sched/signal.h | 1 +
kernel/fork.c | 1 +
kernel/ptrace.c | 4 ++++
kernel/signal.c | 7 ++++++-
5 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/exec.c b/fs/exec.c
index 303a114b00ce..730dee8bb2f8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1323,6 +1323,7 @@ void setup_new_exec(struct linux_binprm * bprm)
/* An exec changes our domain. We are no longer part of the thread
group */
current->self_exec_id++;
+ current->signal->exec_id = current->self_exec_id;
flush_signal_handlers(current, 0);
}
EXPORT_SYMBOL(setup_new_exec);
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 2cf446704cd4..63ae951ee330 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -80,6 +80,7 @@ struct signal_struct {
atomic_t live;
int nr_threads;
struct list_head thread_head;
+ u32 exec_id;
wait_queue_head_t wait_chldexit; /* for wait4() */
diff --git a/kernel/fork.c b/kernel/fork.c
index 0632ac1180be..a442fa099842 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1387,6 +1387,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sig->oom_score_adj = current->signal->oom_score_adj;
sig->oom_score_adj_min = current->signal->oom_score_adj_min;
+ sig->exec_id = current->self_exec_id;
mutex_init(&sig->cred_guard_mutex);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 0af928712174..cc6b10b1ffbe 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -277,6 +277,10 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
* or halting the specified task is impossible.
*/
+ /* Don't allow inspecting a thread after exec */
+ if (task->self_exec_id != task->signal->exec_id)
+ return 1;
+
/* Don't let security modules deny introspection */
if (same_thread_group(task, current))
return 0;
diff --git a/kernel/signal.c b/kernel/signal.c
index fd75ba33ee3d..fe8dcdb622f5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -995,6 +995,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
from_ancestor_ns || (info == SEND_SIG_FORCED)))
goto ret;
+ /* Don't allow thread group signals after exec */
+ if (group && (t->signal->exec_id != t->self_exec_id))
+ goto ret;
+
pending = group ? &t->signal->shared_pending : &t->pending;
/*
* Short-circuit ignored signals and support queuing
@@ -1247,7 +1251,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
* must see ->sighand == NULL.
*/
spin_lock(&sighand->siglock);
- if (likely(sighand == tsk->sighand)) {
+ if (likely((sighand == tsk->sighand) &&
+ (tsk->self_exec_id == tsk->signal->exec_id))) {
rcu_read_unlock();
break;
}
--
2.10.1
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-05 18:20 +0200 |
| Subject | Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec |
| Message-ID | <tsVP4-4TK-17@gated-at.bofh.it> |
| In reply to | #1614838 |
On 04/02, Eric W. Biederman wrote:
>
> Add exec_id to signal_struct and compare it at a few choice moments.
I really dislike this change no matter what, sorry.
Firstly, task_struct->*_exec_id should simply die (I already have the
patch), or at least they should be moved into signal_struct simply
because this is per-process thing.
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -995,6 +995,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
> from_ancestor_ns || (info == SEND_SIG_FORCED)))
> goto ret;
>
> + /* Don't allow thread group signals after exec */
> + if (group && (t->signal->exec_id != t->self_exec_id))
> + goto ret;
Hmm. Either we do not need this exec_id check at all, or we should not
take "group" into account; a fatal signal (say SIGKILL) will kill the
whole thread-group.
> @@ -1247,7 +1251,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
> * must see ->sighand == NULL.
> */
> spin_lock(&sighand->siglock);
> - if (likely(sighand == tsk->sighand)) {
> + if (likely((sighand == tsk->sighand) &&
> + (tsk->self_exec_id == tsk->signal->exec_id))) {
Oh, this doesn't look good to me. Yes, with your approach we probably need
this to, say, ensure that posix-cpu-timer can't kill the process after exec,
but I'd rather add the exit_state check into run_posix_timers().
But OK, suppose that we fix the problems with signal-after-exec.
====================================================================
Now lets fix another problem. A mt exec suceeds and apllication does
sys_seccomp(SECCOMP_FILTER_FLAG_TSYNC) which fails because it finds
another (zombie) SECCOMP_MODE_FILTER thread.
And after we fix this problem, what else we will need to fix?
I really think that - whatever we do - there should be no other threads
after exec, even zombies.
Oleg.
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-05 20:30 +0200 |
| Subject | Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec |
| Message-ID | <tsXQS-69Y-7@gated-at.bofh.it> |
| In reply to | #1617107 |
Oleg Nesterov <oleg@redhat.com> writes:
> On 04/02, Eric W. Biederman wrote:
>>
>> Add exec_id to signal_struct and compare it at a few choice moments.
>
> I really dislike this change no matter what, sorry.
>
> Firstly, task_struct->*_exec_id should simply die (I already have the
> patch), or at least they should be moved into signal_struct simply
> because this is per-process thing.
I am quite happy to find a better way to implement this. More than
anything this was my proof of concept that it is possible to close
the security holes created if we allow our zombies to be normal zombies.
>> --- a/kernel/signal.c
>> +++ b/kernel/signal.c
>> @@ -995,6 +995,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
>> from_ancestor_ns || (info == SEND_SIG_FORCED)))
>> goto ret;
>>
>> + /* Don't allow thread group signals after exec */
>> + if (group && (t->signal->exec_id != t->self_exec_id))
>> + goto ret;
>
> Hmm. Either we do not need this exec_id check at all, or we should not
> take "group" into account; a fatal signal (say SIGKILL) will kill the
> whole thread-group.
Wow. Those are crazy semantics for fatal signals. Sending a tkill
should not affect the entire thread group. Oleg I think this is a bug
you introduced and likely requires a separate fix.
I really don't understand the logic in:
commit 5fcd835bf8c2cde06404559b1904e2f1dfcb4567
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date: Wed Apr 30 00:52:55 2008 -0700
signals: use __group_complete_signal() for the specific signals too
Based on Pavel Emelyanov's suggestion.
Rename __group_complete_signal() to complete_signal() and use it to process
the specific signals too. To do this we simply add the "int group" argument.
This allows us to greatly simply the signal-sending code and adds a useful
behaviour change. We can avoid the unneeded wakeups for the private signals
because wants_signal() is more clever than sigismember(blocked), but more
importantly we now take into account the fatal specific signals too.
The latter allows us to kill some subtle checks in handle_stop_signal() and
makes the specific/group signal's behaviour more consistent. For example,
currently sigtimedwait(FATAL_SIGNAL) behaves differently depending on was the
signal sent by kill() or tkill() if the signal was not blocked.
And. This allows us to tweak/fix the behaviour when the specific signal is
sent to the dying/dead ->group_leader.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
>> @@ -1247,7 +1251,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
>> * must see ->sighand == NULL.
>> */
>> spin_lock(&sighand->siglock);
>> - if (likely(sighand == tsk->sighand)) {
>> + if (likely((sighand == tsk->sighand) &&
>> + (tsk->self_exec_id == tsk->signal->exec_id))) {
>
> Oh, this doesn't look good to me. Yes, with your approach we probably need
> this to, say, ensure that posix-cpu-timer can't kill the process after exec,
> but I'd rather add the exit_state check into run_posix_timers().
The entire point of lock_task_sighand is to not operate on
tasks/processes that have exited. The fact it even sighand in there is
deceptive because it is all about siglock and nothing to do with
sighand.
> But OK, suppose that we fix the problems with signal-after-exec.
>
> ====================================================================
> Now lets fix another problem. A mt exec suceeds and apllication does
> sys_seccomp(SECCOMP_FILTER_FLAG_TSYNC) which fails because it finds
> another (zombie) SECCOMP_MODE_FILTER thread.
>
> And after we fix this problem, what else we will need to fix?
>
>
> I really think that - whatever we do - there should be no other threads
> after exec, even zombies.
I see where you are coming from.
I need to stare at this a bit longer. Because you are right. Reusing
the signal_struct and leaving zombies around is very prone to bugs. So
it is not very maintainable.
I suspect the answer here is to simply allocate a new sighand_struct and
a new signal_struct if there we are not single threaded by the time we
get down to the end of de_thread.
However even if it is a case of whack-a-mole semantically
not-blocking-for-zombies looks like the right thing to do and we need to
figure out how to do it maintainably.
Eric
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-06 18:00 +0200 |
| Subject | Re: [RFC][PATCH v2 5/5] signal: Don't allow accessing signal_struct by old threads after exec |
| Message-ID | <tthZh-2Gn-31@gated-at.bofh.it> |
| In reply to | #1617272 |
On 04/05, Eric W. Biederman wrote:
>
> Oleg Nesterov <oleg@redhat.com> writes:
>
> >> --- a/kernel/signal.c
> >> +++ b/kernel/signal.c
> >> @@ -995,6 +995,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
> >> from_ancestor_ns || (info == SEND_SIG_FORCED)))
> >> goto ret;
> >>
> >> + /* Don't allow thread group signals after exec */
> >> + if (group && (t->signal->exec_id != t->self_exec_id))
> >> + goto ret;
> >
> > Hmm. Either we do not need this exec_id check at all, or we should not
> > take "group" into account; a fatal signal (say SIGKILL) will kill the
> > whole thread-group.
>
> Wow. Those are crazy semantics for fatal signals. Sending a tkill
> should not affect the entire thread group.
How so? SIGKILL or any fatal signal should kill the whole process, even if
it was sent by tkill().
> Oleg I think this is a bug
> you introduced and likely requires a separate fix.
>
> I really don't understand the logic in:
>
> commit 5fcd835bf8c2cde06404559b1904e2f1dfcb4567
> Author: Oleg Nesterov <oleg@tv-sign.ru>
> Date: Wed Apr 30 00:52:55 2008 -0700
>
> signals: use __group_complete_signal() for the specific signals too
No. You can even forget about "send" path for the moment. Just suppose that
a thread dequeues SIGKILL sent by tkill(). In this case it will call
do_group_exit() and kill the group anyway. It is not possible to kill an
individual thread, and linux never did this.
Afaics, this commit also fixes the case when SIGKILL can be lost when tkill()
races with the exiting target. Or if the target is a zombie-leader. Exactly
because they obviously can't dequeue SIGKILL.
Plus we want to shutdown the whole thread-group "asap", that is why
complete_signal() sets SIGNAL_GROUP_EXIT and sends SIGKILL to other threads
in the "send" path.
This btw reminds me that we want to do the same with sig_kernel_coredump()
signals too, but this is not simple.
> >> @@ -1247,7 +1251,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
> >> * must see ->sighand == NULL.
> >> */
> >> spin_lock(&sighand->siglock);
> >> - if (likely(sighand == tsk->sighand)) {
> >> + if (likely((sighand == tsk->sighand) &&
> >> + (tsk->self_exec_id == tsk->signal->exec_id))) {
> >
> > Oh, this doesn't look good to me. Yes, with your approach we probably need
> > this to, say, ensure that posix-cpu-timer can't kill the process after exec,
> > but I'd rather add the exit_state check into run_posix_timers().
>
> The entire point of lock_task_sighand is to not operate on
> tasks/processes that have exited.
Well, the entire point of lock_task_sighand() is take ->siglock if possible.
> The fact it even sighand in there is
> deceptive because it is all about siglock and nothing to do with
> sighand.
Not sure I understand what you mean...
Yes, lock_task_sighand() can obviously fail, and yes the failure is used
as an indication that this thread has gone. But a zombie thread controlled
by the parent/debugger has not gone yet.
> > ====================================================================
> > Now lets fix another problem. A mt exec suceeds and apllication does
> > sys_seccomp(SECCOMP_FILTER_FLAG_TSYNC) which fails because it finds
> > another (zombie) SECCOMP_MODE_FILTER thread.
> >
> > And after we fix this problem, what else we will need to fix?
> >
> >
> > I really think that - whatever we do - there should be no other threads
> > after exec, even zombies.
>
> I see where you are coming from.
>
> I need to stare at this a bit longer. Because you are right. Reusing
> the signal_struct and leaving zombies around is very prone to bugs. So
> it is not very maintainable.
Yes, yes, yes. This is what I was arguing with.
> I suspect the answer here is to simply allocate a new sighand_struct and
> a new signal_struct if there we are not single threaded by the time we
> get down to the end of de_thread.
May be. Not sure. Looks very nontrivial.
And I still think that if we do this, we should fix the bug first, then try
to do something like this.
Oleg.
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-02 18:20 +0200 |
| Message-ID | <trQop-2Lx-1@gated-at.bofh.it> |
| In reply to | #1612711 |
On 03/30, Eric W. Biederman wrote: > > Oleg Nesterov <oleg@redhat.com> writes: > > > Very nice. So de_thread() returns as soon as all other threads decrement > > signal->live in do_exit(). Before they do, say, exit_mm(). This is already > > wrong, for example this breaks OOM. Plus a lot more problems afaics, but > > lets ignore this. > > Which means that we need to keep sig->notify_count. Yes, although we need to make it less ugly. > > Note that de_thread() also unshares ->sighand before return. So in the > > case of mt exec it will likely see oldsighand->count != 1 and alloc the > > new sighand_struct and this breaks the locking. > > > > Because the execing thread will use newsighand->siglock to protect its > > signal_struct while the zombie threads will use oldsighand->siglock to > > protect the same signal struct. Yes, tasklist_lock + the fact irq_disable > > implies rcu_lock mostly save us but not entirely, say, a foreign process > > doing __send_signal() can take the right or the wrong lock depending on > > /dev/random. > > Which leads to the question how can we get back tot he 2.4 behavior > of freeing sighand_struct in do_exit? > > At which point as soon as we free sighand_struct if we are the last > to dying thread notify de_thread and everything works. I was thinking about the similar option, see below, but decided that we should not do this at least right now. > For what __ptrace_unlink is doing we should just be able to skip > acquiring of siglock if PF_EXITING is set. We can even remove it from release_task() path, this is simple. > __exit_signal is a little more interesting but half of what it is > doing looks like it was pulled out of do_exit and just needs to > be put back. That is. I think we should actually unhash the exiting sub-thread even if it is traced. IOW, remove it from thread/pid/parent/etc lists and nullify its ->sighand. IMO, whatever we do thread_group_empty(current) should be true after exec. So the exiting sub-trace should look almost a EXIT_DEAD task except it still should report to debugger. But this is dangerous. Say, wait4(upid <= 0) becomes unsafe because task_pid_type(PIDTYPE_PGID) won't work. > Which probably adds up to 4 or 5 small carefully written patches to sort > out that part of the exit path, Perhaps I am wrong, but I think you underestimate the problems, and it is not clear to me if we really want this. ========================================================================= Anyway, Eric, even if we can and want to do this, why we can't do this on top of my fix? I simply fail to understand why you dislike it that much. Yes it is not pretty, I said this many times, but it is safe in that it doesn't really change the current behaviour. I am much more worried about 2/2 you didn't argue with, this patch _can_ break something and this is obviously not good even if PTRACE_EVENT_EXIT was always broken. Oleg.
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-02 23:20 +0200 |
| Message-ID | <trV4J-5Uv-1@gated-at.bofh.it> |
| In reply to | #1614764 |
Oleg Nesterov <oleg@redhat.com> writes: > Perhaps I am wrong, but I think you underestimate the problems, and it is > not clear to me if we really want this. I worked through quite a bit of it and I realized a few fundamental issues. The task struct must remain visible until it is reaped and we use siglock to protect in unhash process to protect that reaping. Further tsk->sighand == NULL winds up being a flag used to tell if release_task has been called. To get an usable count on sighand struct all that needed to be done was to change the reference counting of sighand_struct to count processes and not threads. Which is what I wound up posting. > Anyway, Eric, even if we can and want to do this, why we can't do this on > top of my fix? Because your reduction in scope of cred_guard_mutex is fundamentally broken and unnecessary. > I simply fail to understand why you dislike it that much. Yes it is not > pretty, I said this many times, but it is safe in that it doesn't really > change the current behaviour. No it is not safe. And it promotes wrong thinking which is even more dangerous. I reviewed the code and cred_guard_mutex needs to cover what it covers. > I am much more worried about 2/2 you didn't argue with, this patch _can_ > break something and this is obviously not good even if PTRACE_EVENT_EXIT > was always broken. I don't know who actually useses PTRACE_O_TRACEEXIT so I don't actually know what the implications of changing it are. Let's see... gdb - no upstart - no lldb - yes strace - no It looks like lldb is worth testing with your PTRACE_EVENT_EXIT change to see if anything breaks. I think we can get away with changing the exec case but it does look worth testing. I hadn't realized you hadn't looked to see what was using PTRACE_O_TRACEEXIT to see if any part of userspace cares. Hmm. This is interesting. From the strace documentation: > Tracer cannot assume that ptrace-stopped tracee exists. There are many > scenarios when tracee may die while stopped (such as SIGKILL). > Therefore, tracer must always be prepared to handle ESRCH error on any > ptrace operation. Unfortunately, the same error is returned if tracee > exists but is not ptrace-stopped (for commands which require stopped > tracee), or if it is not traced by process which issued ptrace call. > Tracer needs to keep track of stopped/running state, and interpret > ESRCH as "tracee died unexpectedly" only if it knows that tracee has > been observed to enter ptrace-stop. Note that there is no guarantee > that waitpid(WNOHANG) will reliably report tracee's death status if > ptrace operation returned ESRCH. waitpid(WNOHANG) may return 0 instead. > IOW: tracee may be "not yet fully dead" but already refusing ptrace > ops. If delivering a second SIGKILL to a ptraced stopped processes will make it continue we have a very interesting out.. When we stop in ptrace_stop we stop in TASK_TRACED == (TASK_WAKEKILL|__TASK_TRACED) Delivery of a SIGKILL to that task has queue SIGKILL and call signal_wake_up_state(t, TASK_WAKEKILL). Which becomes wake_up_state(t, TASK_INTERRUPTIBLE | TASK_WAKEKILL) Which wakes up the process. So userspace can absolutely kill a processes in PTRACE_EVENT_EXIT before the tracers find it. Therefore we are only talking a quality of implementation issue if we actually stop and wait for the tracer or not. .... Which brings us to your PTRACE_EVENT_EXIT patch. I think may_ptrace_stop is tested in the wrong place, and is probably buggy. - We should send the signal in all cases except when the ptracing parent does not exist aka (!current->ptrace). The siginfo contains enough information to understand what happened if anyone is listening. - Then we should send the group stop. - Then if we don't want to wait we should: __set_current_state(TASK_RUNNING) - Then we should drop the locks and only call freezable_schedule if we want to wait. That way userspace thinks someone else just sent a SIGKILL and killed the thread before it had a chance to look (which is effectively what we are doing). That sounds idea for both core-dumps and this case. Eric
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-03 20:40 +0200 |
| Message-ID | <tsf3s-24M-23@gated-at.bofh.it> |
| In reply to | #1614818 |
Eric, I see another series from you, but I simply failed to force myself to read it carefully. Because at first glance it makes me really sad, I do dislike it even if it is correct. Yes, yes, sure, I can be wrong. Will try tomorrow. On 04/02, Eric W. Biederman wrote: > > Oleg Nesterov <oleg@redhat.com> writes: > > > Anyway, Eric, even if we can and want to do this, why we can't do this on > > top of my fix? > > Because your reduction in scope of cred_guard_mutex is fundamentally > broken and unnecessary. And you never explained why it is wrong, or I failed to understand you. > > I simply fail to understand why you dislike it that much. Yes it is not > > pretty, I said this many times, but it is safe in that it doesn't really > > change the current behaviour. > > No it is not safe. And it promotes wrong thinking which is even more > dangerous. So please explain why it is not safe and why it is dangerous. Just in case, if you mean flush_signal_handlers() outside of cred_guard_mutex, please explain what I have missed in case you still think this is wrong. > I reviewed the code and cred_guard_mutex needs to cover what it covers. I strongly, strongly disagree. Its scope is unnecessary huge, we should narrow it in any case, even if the current code was not bugy. But this is almost offtopic, lets discuss this separately. > > I am much more worried about 2/2 you didn't argue with, this patch _can_ > > break something and this is obviously not good even if PTRACE_EVENT_EXIT > > was always broken. > > I don't know who actually useses PTRACE_O_TRACEEXIT so I don't actually > know what the implications of changing it are. Let's see... And nobody knows ;) This is the problem, even the clear ptrace bugfix can break something, this happened before and we had to revert the obviously- correct patches; the bug was already used as feature. > If delivering a second SIGKILL ... > So userspace can absolutely kill a processes in PTRACE_EVENT_EXIT > before the tracers find it. > > Therefore we are only talking a quality of implementation issue > if we actually stop and wait for the tracer or not. Oh, this is another story, needs another discussion. We really need some changes in this area, we need to distinguish SIGKILL sent from user-space and (say) from group-exit, and we need to decide when should we stop. But at least I think the tracee should never stop if SIGKILL comes from user space. And yes ptrace_stop() is ugly and wrong, just look at the arch_ptrace_stop_needed() check. The problem, again, is that any fix will be user-visible. Oleg.
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-04 01:00 +0200 |
| Subject | scope of cred_guard_mutex. |
| Message-ID | <tsj74-4Hf-5@gated-at.bofh.it> |
| In reply to | #1615471 |
Oleg Nesterov <oleg@redhat.com> writes:
> On 04/02, Eric W. Biederman wrote:
>>
>> Oleg Nesterov <oleg@redhat.com> writes:
>>
>> > Anyway, Eric, even if we can and want to do this, why we can't do this on
>> > top of my fix?
>>
>> Because your reduction in scope of cred_guard_mutex is fundamentally
>> broken and unnecessary.
>
> And you never explained why it is wrong, or I failed to understand you.
>
>> > I simply fail to understand why you dislike it that much. Yes it is not
>> > pretty, I said this many times, but it is safe in that it doesn't really
>> > change the current behaviour.
>>
>> No it is not safe. And it promotes wrong thinking which is even more
>> dangerous.
>
> So please explain why it is not safe and why it is dangerous.
>
> Just in case, if you mean flush_signal_handlers() outside of cred_guard_mutex,
> please explain what I have missed in case you still think this is wrong.
>> I reviewed the code and cred_guard_mutex needs to cover what it covers.
>
> I strongly, strongly disagree. Its scope is unnecessary huge, we should narrow
> it in any case, even if the current code was not bugy. But this is almost
> offtopic, lets discuss this separately.
You have asked why I have problems with your patch and so I am going to
try to explain. Partly I want to see a clean set of patches that we
can merge into Linus's tree before we make any compromises. Because the
work preparing a clean patchset may inform us of something better. Plus
we need to make something clean and long term maintainable in any event.
Partly I object because your understanding and my understanding of
cred_guard_mutex are very different.
As I read and understand the code the job of cred_guard_mutex is to keep
ptrace (and other threads of the proccess) from interferring in
exec and to ensure old resources are accessed with permission checks
using our original credentials and that new and modified resources are
accessed with permission checks using our new credentials.
I object to your patch in particular because you deliberately mess up
the part of only making old resources available with old creds and
new resources available with new creds. Even if the current permission
checks are a don't care it still remains conceptually wrong. And
conceptually wrong tends code tends towards maintenance problems
and real surprises when someone makes small changes to the code. Which
is what I mean when I say your patch is dangerous.
AKA What I see neededing to be protected looks something like:
mutex_lock();
new_cred = compute_new_cred(tsk);
new_mm = compute_new_mm(tsk);
tsk->mm = new_mm;
tsk->cred = new_cred;
zap_other_threads(tsk);
update_sighand(tsk);
update_signal(tsk);
do_close_on_exec();
update_tsk_fields(tsk);
mutex_unlock();
The only way I can see of reducing the scope of cred_guard_mutex is
performing work in such a way that ptrace and the other threads can't
interfere and then taking the lock. Computing the new mm and the new
credentials are certainly candidates for that kind of treatment.
Eric
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-05 18:10 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <tsVFo-4Pz-11@gated-at.bofh.it> |
| In reply to | #1615604 |
On 04/03, Eric W. Biederman wrote: > > You have asked why I have problems with your patch and so I am going to > try to explain. Partly I want to see a clean set of patches that we > can merge into Linus's tree before we make any compromises. Because the > work preparing a clean patchset may inform us of something better. Plus > we need to make something clean and long term maintainable in any event. > > Partly I object because your understanding and my understanding of > cred_guard_mutex are very different. And I think there is another problem, your understanding and my understanding of "clean" differ too much and it seems that we can not convince each other ;) The last series looks buggy (I'll send more emails later today), but the main problem is that - in my opinion! - your approach is "obviously wrong and much less clean". But yes, yes, I understand that this is my opinion, and I can be wrong. Eric, I think we need more CC's. Linus, probably security list, the more the better. I am going to resend my series with more CC's, then you can nack it and explain what you think we should do. Perhaps someone else will suggest a better solution, or at least review the patches. OK? Oleg.
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2017-04-05 18:20 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <tsVP3-4TK-7@gated-at.bofh.it> |
| In reply to | #1617082 |
On Wed, Apr 5, 2017 at 9:08 AM, Oleg Nesterov <oleg@redhat.com> wrote: > On 04/03, Eric W. Biederman wrote: >> >> You have asked why I have problems with your patch and so I am going to >> try to explain. Partly I want to see a clean set of patches that we >> can merge into Linus's tree before we make any compromises. Because the >> work preparing a clean patchset may inform us of something better. Plus >> we need to make something clean and long term maintainable in any event. >> >> Partly I object because your understanding and my understanding of >> cred_guard_mutex are very different. > > And I think there is another problem, your understanding and my understanding > of "clean" differ too much and it seems that we can not convince each other ;) > > The last series looks buggy (I'll send more emails later today), but the > main problem is that - in my opinion! - your approach is "obviously wrong > and much less clean". But yes, yes, I understand that this is my opinion, > and I can be wrong. > > Eric, I think we need more CC's. Linus, probably security list, the more > the better. > > I am going to resend my series with more CC's, then you can nack it and > explain what you think we should do. Perhaps someone else will suggest > a better solution, or at least review the patches. OK? I've been following along, but it seems like there are a lot of edge cases in these changes. I'll try to meaningfully comment on the coming emails... having code examples of why various things will/won't work go a long way for helping understand what's safe or not... -Kees -- Kees Cook Pixel Security
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-05 20:10 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <tsXxw-63J-15@gated-at.bofh.it> |
| In reply to | #1617082 |
Oleg Nesterov <oleg@redhat.com> writes: > On 04/03, Eric W. Biederman wrote: >> >> You have asked why I have problems with your patch and so I am going to >> try to explain. Partly I want to see a clean set of patches that we >> can merge into Linus's tree before we make any compromises. Because the >> work preparing a clean patchset may inform us of something better. Plus >> we need to make something clean and long term maintainable in any event. >> >> Partly I object because your understanding and my understanding of >> cred_guard_mutex are very different. > > And I think there is another problem, your understanding and my understanding > of "clean" differ too much and it seems that we can not convince each other ;) We have barely begun. You have not shown anyone what your idea of a clean fix actually is. All I have seen from you is a quick hack that is a hack that is back-portable. Focusing on the back port is the wrong order to solve the issue in. We need to solve this in an upstream mergable and maintainable way and then we can worry about backports. From a userspace perspective. I find anything in the kernel blocking on a zombie to be just wrong. A zombie is dead. Waiting for a zombie should in all cases be optional. The system should not break if we don't reap a zombie. You have made a clear case that the zombies need to exist for strace -f to wait on. So since the zombies must exist we should make them follow normal zombie rules. With your change exec still blocks waiting for zombies. Furthermore you have to violate the reasonable rule that: * pre-exec resources are guarded with the pre-exec process cred. * post-exec resources are guarded with the post-exec process cred. So from a userspace perspective I think your semantics are absolutely insane. We also need clean code to implement all of this (which I am still inching towards). But we need to be implementing something that makes sense from a userspace perspective. > The last series looks buggy (I'll send more emails later today), but the > main problem is that - in my opinion! - your approach is "obviously wrong > and much less clean". But yes, yes, I understand that this is my opinion, > and I can be wrong. How is changing fixing the implementation so that we don't block waiting for zombies to be reaped wrong? > Eric, I think we need more CC's. Linus, probably security list, the more > the better. > > I am going to resend my series with more CC's, then you can nack it and > explain what you think we should do. Perhaps someone else will suggest > a better solution, or at least review the patches. OK? I will be happy to look but my primary objectionions to your patch were: - You implemented a hack for backporting rather than fixing things cleanly the first time. - You made comments about cred_guard_mutex and it's scope that when I reviewed the code were false. cred_guard_mutex although probably the wrong locking structure is semantically and fundamentally where it needs to be. We can optimize it but we can't change what is protected to make our lives easier. Eric
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-05 20:20 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <tsXHc-66T-27@gated-at.bofh.it> |
| In reply to | #1617252 |
On 04/05, Eric W. Biederman wrote: > > Oleg Nesterov <oleg@redhat.com> writes: > > - You made comments about cred_guard_mutex and it's scope that when I > reviewed the code were false. Too late for me. I'll try to read other emails from you and reply tomorrow. Oleg.
[toc] | [prev] | [next] | [standalone]
| From | Oleg Nesterov <oleg@redhat.com> |
|---|---|
| Date | 2017-04-06 18:00 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <tthZh-2Gn-23@gated-at.bofh.it> |
| In reply to | #1615604 |
On 04/03, Eric W. Biederman wrote: > > Oleg Nesterov <oleg@redhat.com> writes: > > >> I reviewed the code and cred_guard_mutex needs to cover what it covers. > > > > I strongly, strongly disagree. Its scope is unnecessary huge, we should narrow > > it in any case, even if the current code was not bugy. But this is almost > > offtopic, lets discuss this separately. And let me repeat/clarify. I meant, I see absolutely no reason to do copy_strings() with this mutex held, for example. And note that copy_strings() can use a lot of memory/time, it can trigger oom,swapping, etc. I also think that we can probably do check_unsafe_exec() which in particular sets LSM_UNSAFE_ at bit later, but I am less sure about this and this needs more work. And perhaps more changes like this to narrow the scope of this mutex. And I thought you were already agree with this? > You have asked why I have problems with your patch and so I am going to > try to explain. Partly I want to see a clean set of patches that we > can merge into Linus's tree before we make any compromises. Sure, me too. I do not see a simple and clean fix, your attempts were wrong so far and imo were worse even if they were correct. And this makes me think again that we need to restart this discusion with more CC's. > Partly I object because your understanding and my understanding of > cred_guard_mutex are very different. > > As I read and understand the code the job of cred_guard_mutex is to keep > ptrace (and other threads of the proccess) from interferring in > exec and to ensure old resources are accessed with permission checks > using our original credentials and that new and modified resources are > accessed with permission checks using our new credentials. Yes, this is clear. > I object to your patch in particular because you deliberately mess up > the part of only making old resources available with old creds and > new resources available with new creds. Could you spell please? I don't understand. > AKA What I see neededing to be protected looks something like: > mutex_lock(); > new_cred = compute_new_cred(tsk); > new_mm = compute_new_mm(tsk); > tsk->mm = new_mm; > tsk->cred = new_cred; > zap_other_threads(tsk); > update_sighand(tsk); > update_signal(tsk); > do_close_on_exec(); > update_tsk_fields(tsk); > mutex_unlock(); > > The only way I can see of reducing the scope of cred_guard_mutex is > performing work in such a way that ptrace and the other threads can't > interfere and then taking the lock. Computing the new mm and the new > credentials are certainly candidates for that kind of treatment. OK. And yes, I am not sure this all is optimal, but didn't I say from the very beginning that unlikely we can change this? Now let me quote your next email: On 04/05, Eric W. Biederman wrote: > > We have barely begun. You have not shown anyone what your idea of a > clean fix actually is. All I have seen from you is a quick hack that is > a hack that is back-portable. Yes. I really tried to make a back-portable fix. Otherwise I would start with ->notify_count cleanups. > With your change exec still blocks waiting for zombies. And this is what we currently do. Whether we should do this may be debatable, but why do you blame my patch? > Furthermore you have to violate the reasonable rule that: > * pre-exec resources are guarded with the pre-exec process cred. > * post-exec resources are guarded with the post-exec process cred. For example? > So from a userspace perspective I think your semantics are absolutely > insane. Which semantics were changed by my patch? > - You made comments about cred_guard_mutex and it's scope that when I > reviewed the code were false. Which of my comments was wrong? > We can optimize it And this is what I meant when I said "we should narrow it in any case" > but we can't change what is protected I am not that sure. But a) I did not even try to suggest to change anything in this area right now, and b) I said that unlikely this is possible. Oleg.
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2017-04-08 00:10 +0200 |
| Subject | Re: scope of cred_guard_mutex. |
| Message-ID | <ttKeS-59B-9@gated-at.bofh.it> |
| In reply to | #1618133 |
On Thu, Apr 6, 2017 at 8:55 AM, Oleg Nesterov <oleg@redhat.com> wrote: > And this makes me think again that we need to restart this discusion with > more CC's. I'm a fan of that; I've not been able to follow this thread as it seems to have gone far from the original deadlock problem. :) I've seen issues with ptrace, zombies, and now exec. I'm lost. :P >> Partly I object because your understanding and my understanding of >> cred_guard_mutex are very different. >> >> As I read and understand the code the job of cred_guard_mutex is to keep >> ptrace (and other threads of the proccess) from interferring in >> exec and to ensure old resources are accessed with permission checks >> using our original credentials and that new and modified resources are >> accessed with permission checks using our new credentials. > > Yes, this is clear. Maybe stupid idea: can we get a patch that just adds this kind of documentation somewhere in the source? If we can agree on the purpose of cred_guard_mutex, and get it into the code, that seems like a good step in discussion... -Kees -- Kees Cook Pixel Security
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-04-04 01:00 +0200 |
| Message-ID | <tsj74-4Hf-7@gated-at.bofh.it> |
| In reply to | #1615471 |
Oleg Nesterov <oleg@redhat.com> writes: > Eric, > > I see another series from you, but I simply failed to force myself to read > it carefully. Because at first glance it makes me really sad, I do dislike > it even if it is correct. Yes, yes, sure, I can be wrong. Will try > tomorrow. Yes. I needed to get my thoughts concrete. I missed fixing the race in zap_other_threads. But overall I think things are moving in a good direction. >> >> I don't know who actually useses PTRACE_O_TRACEEXIT so I don't actually >> know what the implications of changing it are. Let's see... > > And nobody knows ;) This is the problem, even the clear ptrace bugfix can > break something, this happened before and we had to revert the obviously- > correct patches; the bug was already used as feature. Yes that is the challenge of changing userspace. Which is why it helps to test as much of a userspace change as possible. Or to get very clever, and figure out how to avoid the userspace change. So I think it is worth knowing the lldb actually uses PTRACE_O_TRACEEXIT. So we can test at least some programs to verify that all is well. I don't see any way around cleaning up PTRACE_O_TRACEEXIT. As we fundamentally have the non-thread-group-leader exec problem. We have to reap that previous leader thread with release_task. Which means we can't stop for a PTRACE_O_TRACEEXIT. >> If delivering a second SIGKILL > ... >> So userspace can absolutely kill a processes in PTRACE_EVENT_EXIT >> before the tracers find it. >> >> Therefore we are only talking a quality of implementation issue >> if we actually stop and wait for the tracer or not. > > Oh, this is another story, needs another discussion. We really need some > changes in this area, we need to distinguish SIGKILL sent from user-space > and (say) from group-exit, and we need to decide when should we stop. > > But at least I think the tracee should never stop if SIGKILL comes from > user space. And yes ptrace_stop() is ugly and wrong, just look at the > arch_ptrace_stop_needed() check. The problem, again, is that any fix will > be user-visible. The only issue I see is that arch_ptrace_stop() may sleep (sparc and ia64 do as they flush the register stack to memory). As the code may sleep it means we can't set TASK_TRACED until after calling arch_ptrace_stop(). My inclination is to just solve that by saying: if (!sigkill_pending(current)) set_current_task(TASK_TRACED); That removes the special case. We have to handle SIGKILL being delivered immediately after set_current_state in any event. And as we are talking about something that happens on rare architecutres I don't see any problem with tweaking that code at all. It is closely enough related I will fold that into the next version of my patch. Eric
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web