From: Oleg Nesterov <oleg@redhat.com>
To: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: serge@hallyn.com,
syzbot <syzbot+a9ac39bf55329e206219@syzkaller.appspotmail.com>,
jmorris@namei.org, keescook@chromium.org,
linux-kernel@vger.kernel.org,
linux-security-module@vger.kernel.org,
syzkaller-bugs@googlegroups.com
Subject: Re: KASAN: use-after-free Read in task_is_descendant
Date: Thu, 25 Oct 2018 17:55:04 +0200 [thread overview]
Message-ID: <20181025155503.GF3725@redhat.com> (raw)
In-Reply-To: <d11bc954-5a30-e6bd-1668-866a187e0aac@i-love.sakura.ne.jp>
On 10/25, Tetsuo Handa wrote:
>
> On 2018/10/25 21:17, Oleg Nesterov wrote:
> >>> And yes, task_is_descendant() can hit the dead child, if nothing else it can
> >>> be killed. This can explain the kasan report.
> >>
> >> The kasan is reporting that child->real_parent (or maybe child->real_parent->real_parent
> >> or child->real_parent->real_parent->real_parent ...) was pointing to already freed memory,
> >> isn't it?
> >
> > Yes. and you know, I am all confused. I no longer can understand you :/
>
> Why don't we need to check every time like shown below?
> Why checking only once is sufficient?
Why do you think it is not sufficient?
Again, I can be easily wrong, rcu is not simple, but so far I think we need
a single check at the start.
> --- a/security/yama/yama_lsm.c
> +++ b/security/yama/yama_lsm.c
> @@ -285,7 +285,7 @@ static int task_is_descendant(struct task_struct *parent,
> rcu_read_lock();
> if (!thread_group_leader(parent))
> parent = rcu_dereference(parent->group_leader);
> - while (walker->pid > 0) {
> + while (pid_alive(walker) && walker->pid > 0) {
OK. To simplify, ets suppose that task_is_descendant() is called with tasklist
lock held. And lets suppose that all tasks are single-threaded.
Then we obviously need a single check at the start, we need to ensure that the
child was not removed from its ->real_parent->children list. The latter means
that if ->real_parent exits, the child will be re-parented and its ->real_parent
will be updated.
So we could do
read_lock(tasklist);
if (list_empty(child->sibling))
// it is dead, removed from ->children list, we can't trust
// child->real_parent
return -EWHATEVER;
task_is_descendant(current, child);
But note that we can safely use pid_alive(child) instead, detach_pid() and
list_del_init(&p->sibling) happen "at the same time" since we hold tasklist.
(And btw, I suggested several times to rename it, or add another helper with
a better name. Note also that we could check, say, ->sighand != NULL with
the same effect.)
Now. Why do you think rcu_read_lock() differs in that we need to check
pid_alive() at every step?
Suppose that one of the grand parents exits, and it is going to be freed. Again,
to (over)simplify the things, lets suppose that release_task() does
synchronize_rcu();
free_task(p);
at the end. Now, can
rcu_read_lock();
if (pid_alive(child)) {
while (child->pid)
child = child->real_parent;
}
rcu_read_unlock();
hit the already freed ->real_parent ? Say, the freed child->real_parent->real_parent.
Lets denote P1 = child->real_parent, P2 = P1->real_parent. Can P2 be already freed?
This is only possible if synchronize_rcu() above was called before rcu_read_lock(),
see the last sentence below.
If P1->real_parent is still P2, then P1 has already exited too. And we still observe
that child->real_parent == P1, this too is only possible if child has exited, so we
must see pid_alive() == F.
Why must we see pid_alive() == F without tasklist? It must be true, release_task()
is serialized by tasklist_lock, but why we can't get the stale value under
rcu_read_lock() ?
Because our rcu read-lock critical section extends beyond the return from
synchronize_rcu(), and thus we must have a full memory barrier _between_
that synchronize_rcu() and our rcu_read_lock(). We must see all memory updates,
including thread_pid = NULL which makes pid_alive() == F.
Do you see any hole?
Oleg.
next prev parent reply other threads:[~2018-10-25 15:55 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-21 7:10 KASAN: use-after-free Read in task_is_descendant syzbot
2018-10-21 7:12 ` Tetsuo Handa
2018-10-22 9:54 ` Oleg Nesterov
2018-10-22 10:06 ` Tetsuo Handa
2018-10-22 13:46 ` Oleg Nesterov
2018-10-25 2:15 ` Tetsuo Handa
2018-10-25 11:13 ` Oleg Nesterov
2018-10-25 11:36 ` Kees Cook
2018-10-25 12:05 ` Oleg Nesterov
2018-10-25 11:47 ` Tetsuo Handa
2018-10-25 12:17 ` Oleg Nesterov
2018-10-25 13:01 ` Oleg Nesterov
2018-10-26 16:09 ` Kees Cook
2018-10-29 12:23 ` Oleg Nesterov
2018-10-29 15:05 ` yama: unsafe usage of ptrace_relation->tracer Oleg Nesterov
2019-01-10 11:05 ` Tetsuo Handa
2019-01-10 18:47 ` Kees Cook
2019-01-16 17:40 ` Oleg Nesterov
2018-10-25 13:14 ` KASAN: use-after-free Read in task_is_descendant Tetsuo Handa
2018-10-25 15:55 ` Oleg Nesterov [this message]
2018-10-25 16:25 ` Oleg Nesterov
2018-10-26 12:23 ` Tetsuo Handa
2018-10-26 13:04 ` Oleg Nesterov
2018-10-26 13:51 ` Tetsuo Handa
2018-10-26 14:39 ` Oleg Nesterov
2018-10-26 15:04 ` Tetsuo Handa
2018-10-26 15:22 ` Oleg Nesterov
2018-10-25 8:19 ` Kees Cook
2018-10-25 11:52 ` Oleg Nesterov
2018-11-10 3:25 ` syzbot
2018-11-10 11:46 ` syzbot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181025155503.GF3725@redhat.com \
--to=oleg@redhat.com \
--cc=jmorris@namei.org \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=penguin-kernel@i-love.sakura.ne.jp \
--cc=serge@hallyn.com \
--cc=syzbot+a9ac39bf55329e206219@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.