Re: [PATCH] futex: fix a race condition between REQUEUE_PI and task death

From: Thomas Gleixner
Date: Sat Oct 25 2014 - 15:30:10 EST


On Thu, 23 Oct 2014, Brian Silverman wrote:

First of all. Nice catch!

> pi_state_free and exit_pi_state_list both clean up futex_pi_state's.
> exit_pi_state_list takes the hb lock first, and most callers of
> pi_state_free do too. requeue_pi didn't, which causes lots of problems.

"causes lots of problems" is not really a good explanation of the root
cause. That wants a proper description of the race, i.e.

CPU 0 CPU 1
... ....

I'm surely someone who is familiar with that code, but it took me
quite some time to understand whats going on. The casual reader will
just go into brain spiral mode and give up.

> +/**
> + * Must be called with the hb lock held.
> + */

Having that comment is nice, but there is nothing which enforces
it. So we really should add another argument to that function,
i.e. struct futex_hash_bucket *hb and verify that the lock is held at
least when lockdep is enabled.

> static void free_pi_state(struct futex_pi_state *pi_state)

> @@ -1558,6 +1552,14 @@ retry_private:
> ret = get_futex_value_locked(&curval, uaddr1);
>
> if (unlikely(ret)) {
> + if (flags & FLAGS_SHARED && pi_state != NULL) {

Why is this dependend on "flags & FLAGS_SHARED"? The shared/private
property has nothing to do with that at all, but I might be missing
something.

> + /*
> + * We will have to lookup the pi_state again, so
> + * free this one to keep the accounting correct.
> + */
> + free_pi_state(pi_state);
> + pi_state = NULL;

Instead of copying the same code over and over, we should change
free_pi_state() to handle being called with a NULL pointer.

Thanks,

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