From nobody Wed Feb 11 05:02:16 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 77B8D1B4122 for ; Thu, 19 Dec 2024 19:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734637590; cv=none; b=XbMuGS4lxKIBG30Y72gFfck/YC7HWA1+CbYugxGI7xsIe+m9pvFDZUd2IEnr05koJ3cKXO+3LhmwCuGY5bKfgcxCJei3DBHt3Zyz0OexVgSP+4fT1oKOPNnnOk5vCi+DAm7oVNCIDpdaQ8gIqqjc6wKbxJOv/u6vv/EJl3mXJsw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734637590; c=relaxed/simple; bh=wYjqBBhuAqhNRBs2zicoztlyqktrbhfzOgp5CmasN6A=; h=From:To:Cc:Subject:In-Reply-To:References:Date:Message-ID: MIME-Version:Content-Type; b=ZzWHanGS+cz5HRXPVggOI429YmV8hOhqZCesOFZP9Ho95HTHmW+YF6qgITQgO1EE2317EG1mCFY9L4faQxQyXA7NXs3oZXASp52Sns6YTnHhiLXZVxNyOoNU5YMpF/PiJs/JVgbsd40ZBXIdGfEjIAezHUZAiJA/3cGR4EsCd5Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=aNz3o7Xl; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=ie0Zn/s/; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="aNz3o7Xl"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="ie0Zn/s/" From: Thomas Gleixner DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1734637586; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=rz2wP16RP6lmF2hTRObZb66gyt296Oks7yIKyIPulWA=; b=aNz3o7XloVvXkn61CN7BR/DQZsmrG+KOGI/eOqWvr0oqQeGHzf3bjTMHu3mzVOzgAMapL3 vTXY1X2e0XLb8BGJqDTpVplk6INHKJ+0BfEnGw6uR9l8hJkYqmRveebA1W+DlrwqSVF86z WG/BoNfFuAFSE5dbY/QFS2KD02DGpI5NbV9HNBCUrGRKFhoQwcMvMupeOAtv9yeBZ/Lnar slhiDBtL7nmeyp/xEsTfRzpK0k7c/PC2YZKuKIrwIe74rGE9PQoGB9v+UBup2qX1dg/4uF n7DUUve3jMMxNBSLFVvqAVdQasc2scGfYEz5mlz4KXbn9MDd/Qq/mkZozkUz6Q== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1734637586; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=rz2wP16RP6lmF2hTRObZb66gyt296Oks7yIKyIPulWA=; b=ie0Zn/s/7kJfP7UesifAFr/+v3oJVk4AxfBz65y3dBpVr2gePzexLMYU9gXTVAWpeMH2Va +Esd17OJ/BjnnADQ== To: syzbot , anna-maria@linutronix.de, frederic@kernel.org, linux-kernel@vger.kernel.org, peterz@infradead.org, syzkaller-bugs@googlegroups.com Cc: Eric Biederman , Oleg Nesterov Subject: [PATCH] signal/posixtimers: Handle ignore/blocked sequences correctly In-Reply-To: <6761b16e.050a0220.29fcd0.006d.GAE@google.com> References: <6761b16e.050a0220.29fcd0.006d.GAE@google.com> Date: Thu, 19 Dec 2024 20:46:25 +0100 Message-ID: <87ikrf78xa.ffs@tglx> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" syzbot triggered the warning in posixtimer_send_sigqueue(), which warns about a non-ignored signal being already queued on the ignored list: WARNING: ... at kernel/signal.c:2050 posixtimer_send_sigqueue The warning is actually bogus, as the following valid sequence can trigger it: signal($SIG, SIGIGN); timer_settime(...); // arm periodic timer timer fires, signal is ignored and queued on ignored list sigprocmask(SIG_BLOCK, ...); // block the signal timer_settime(...); // re-arm periodic timer timer fires, signal is not ignored because it is blocked ---> Warning triggers as signal is on the ignored list Ideally timer_settime() should remove the signal, but that's racy and incomplete vs. other scenarios and requires a full re-evaluation of the pending signal list. Instead of adding more complexity, handle it gracefully by removing the warning and requeueing the signal to the pending list. If the signal gets unblocked and is still ignored, it's going back to the ignore list. If a handler was installed before unblocking, it's going to be delivered. There is a related scenario to trigger the complementary warning in the signal ignored path, which does not expect the signal to be on the pending list when it is ignored. WARNING: ... at kernel/signal.c:2014 posixtimer_send_sigqueue That can be triggered even before the above change via: task1 task2 signal($SIG, SIGIGN); sigprocmask(SIG_BLOCK, ...); timer_create(); // Signal target is task2 timer_settime(...); // arm periodic timer timer fires, signal is not ignored because it is blocked and queued on the pending list of task2 syscall() // Sets the pending flag sigprocmask(SIG_UNBLOCK, ...); -> preemption, task2 does not make it back to exit to userspace and therefore cannot dequeue the signal before: timer_settime(...); // re-arm periodic timer timer fires, signal is ignored ---> Warning triggers as signal is on task2's pending list and the thread group is not exiting Consequently, remove that warning too and just keep the signal on the pending list. If the signal is dequeued by task2 and still ignored, it will be moved to the ignored list. If a handler gets installed before the dequeue, then it will be delivered in the same way as a signal, which is on the ignored list when SIGIGN is lifted and therefore moved back to the pending list. Fixes: df7a996b4dab ("signal: Queue ignored posixtimers on ignore list") Reported-by: syzbot+3c2e3cc60665d71de2f7@syzkaller.appspotmail.com Signed-off-by: Thomas Gleixner Closes: https://lore.kernel.org/all/6761b16e.050a0220.29fcd0.006d.GAE@googl= e.com --- kernel/signal.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2007,11 +2007,23 @@ void posixtimer_send_sigqueue(struct k_i =20 if (!list_empty(&q->list)) { /* - * If task group is exiting with the signal already pending, - * wait for __exit_signal() to do its job. Otherwise if - * ignored, it's not supposed to be queued. Try to survive. + * The signal was ignored and blocked. The timer + * expiry queued it because blocked signals are + * queued independent of the ignored state. + * + * The unblocking set SIGPENDING, but the signal + * was not yet dequeued from the pending list, + * which would have put it back on the ignore list. + * So prepare_signal() sees unblocked and ignored, + * which ends up here. Leave it queued like a + * regular signal. + * + * The same happens when the task group is exiting + * and the signal is already queued. + * prepare_signal() treats SIGNAL_GROUP_EXIT as + * ignored independent of its queued state. This + * gets cleaned up in __exit_signal(). */ - WARN_ON_ONCE(!(t->signal->flags & SIGNAL_GROUP_EXIT)); goto out; } =20 @@ -2046,17 +2058,25 @@ void posixtimer_send_sigqueue(struct k_i goto out; } =20 - /* This should never happen and leaks a reference count */ - if (WARN_ON_ONCE(!hlist_unhashed(&tmr->ignored_list))) - hlist_del_init(&tmr->ignored_list); - if (unlikely(!list_empty(&q->list))) { /* This holds a reference count already */ result =3D TRACE_SIGNAL_ALREADY_PENDING; goto out; } =20 - posixtimer_sigqueue_getref(q); + /* + * If the signal is on the ignore list, it got blocked after it was + * ignored earlier. But nothing lifted the ignore. Move it back to + * the pending list to be consistent with the regular signal + * handling. If it gets unblocked, it will be ignored again unless + * a handler has been installed before unblocking. If it's not on + * the ignore list acquire a reference count. + */ + if (likely(hlist_unhashed(&tmr->ignored_list))) + posixtimer_sigqueue_getref(q); + else + hlist_del_init(&tmr->ignored_list); + posixtimer_queue_sigqueue(q, t, tmr->it_pid_type); result =3D TRACE_SIGNAL_DELIVERED; out: