Re: [PATCH 6/9] signal: Always call do_notify_parent_cldstop with siglock held

From: Peter Zijlstra
Date: Thu Apr 28 2022 - 13:45:15 EST


On Wed, Apr 27, 2022 at 09:47:10AM -0500, Eric W. Biederman wrote:

> Hmm. If we have the following process tree.
>
> A
> \
> B
> \
> C
>
> Process A, B, and C are all in the same process group.
> Process A and B are setup to receive SIGCHILD when
> their process stops.
>
> Process C traces process A.
>
> When a sigstop is delivered to the group we can have:
>
> Process B takes siglock(B) siglock(A) to notify the real_parent
> Process C takes siglock(C) siglock(B) to notify the real_parent
> Process A takes siglock(A) siglock(C) to notify the tracer
>
> If they all take their local lock at the same time there is
> a deadlock.
>
> I don't think the restriction that you can never ptrace anyone
> up the process tree is going to fly. So it looks like I am back to the
> drawing board for this one.

I've not had time to fully appreciate the nested locking here, but if it
is possible to rework things to always take both locks at the same time,
then it would be possible to impose an arbitrary lock order on things
and break the cycle that way.

That is, simply order the locks by their heap address or something:

static void double_siglock_irq(struct sighand *sh1, struct sighand2 *sh2)
{
if (sh1 > sh2)
swap(sh1, sh2)

spin_lock_irq(&sh1->siglock);
spin_lock_nested(&sh2->siglock, SINGLE_DEPTH_NESTING);
}