lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200903151540.00542.mega@retes.hu>
Date:	Sun, 15 Mar 2009 15:40:00 +0100
From:	Gábor Melis <mega@...es.hu>
To:	Oleg Nesterov <oleg@...hat.com>
Cc:	linux-kernel@...r.kernel.org,
	Andrew Morton <akpm@...ux-foundation.org>
Subject: Re: Signal delivery order

On Domingo 15 Marzo 2009, Oleg Nesterov wrote:
> On 03/14, Gábor Melis wrote:
> > The test program triggers sigsegvs from a thread and tests whether
> > the the sigsegv handler is invoked when the sigusr1 handler is
> > already running.
>
> No, this is not what happens with this test case. SIGSEGV can't be
> generated when we run SIGUSR1 handler.
>
> 	void sigsegv_handler(int signal, siginfo_t *info, void *context)
> 	{
> 	     /* The test signal is blocked only in test_handler. */
>
> The comment is not right. We can't be here (in SIGSEGV handler) if
> we are in test_handler.
> 	     if (is_signal_blocked(test_signal)) {
> 		 _exit(27);
> 	     }
>
> If test_signal (SIGUSR1) is blocked, this means it is already
> delivered, and the handler will be invoked when we return from
> sigsegv_handler(), please see below.

SIGUSR1 is delivered, its sigmask is added to the current mask but the 
handler is not yet invoked and in this instant synchronous sigsegv is 
delivered, its handler invoked?

> > A normal kill does
> > not seem to do this.
>
> Yes. Because the task deques the private signals first (sent by
> tkill, or generate by kernel when the test case does "*page_address =
> 1"), then it dequeues the shared signals (sent by kill).
>
> But please note that it is still possible to hit is_signal_blocked()
> even with test_with_kill(), but the probability is very low.
>
> > I would expect that no asynchronously generated signal (and here I
> > include those sent by pthread_kill()) can overtake a sigsegv even
> > if its signum is lower.
>
> Signum doesn't matter. Any unblocked signal can preempt the task,
> whether it runs inside a signal handler or not. This is correct, you
> can use sigaction->sa_mask to specify which signals which should be
> blocked during execution of the signal handler.
>
> OK, let's do a simple test:
>
> 	int is_blocked(int sig)
> 	{
> 		sigset_t set;
> 		sigprocmask(SIG_BLOCK, NULL, &set);
> 		return sigismember(&set, sig);
> 	}
>
> 	void sig_1(int sig)
> 	{
> 		printf("%d %d\n", sig, is_blocked(2));
> 	}
>
> 	void sig_2(int sig)
> 	{
> 		printf("%d %d\n", sig, is_blocked(1));
> 	}
>
> 	int main(void)
> 	{
> 		sigset_t set;
>
> 		signal(1, sig_1);
> 		signal(2, sig_2);
>
> 		sigemptyset(&set);
> 		sigaddset(&set, 1);
> 		sigaddset(&set, 2);
> 		sigprocmask(SIG_BLOCK, &set, NULL);
>
> 		kill(getpid(), 1);
> 		kill(getpid(), 2);
>
> 		sigprocmask(SIG_UNBLOCK, &set, NULL);
>
> 		return 0;
> 	}
>
> output is:
>
> 	2 1
> 	1 0
>
> When sigprocmask(SIG_UNBLOCK) returns, both signals are delivered.
> The kernel deques 1 first, then 2. This means that the handler for
> "2" will be called first.

My mental model that matches what I quickly glean from the sources (from 
kernel/signal.c, arch/x86/kernel/signal_32.c) goes like this:

- signal 1 and signal 2 are generated and made pending
- they are unblocked by sigprocmask
- signal 1 is delivered: signals in its mask (only itself here) are 
blocked its handler is invoked
- barely into sig_1 (the printf didn't get a chance to run), signal 2 is 
delivered its sigmask is added to current one that already includes 
signal 1, sig_2 is invoked
- sig_2 prints "2 1" and returns
- sig_1 reaches the printf printing "1 0"
hes this model.

I can't find how 'handler for "2" will be called first'. Furthermore, if 
it's indeed sig_2 that's invoked first then sig_1's sigmask is added to 
the current mask upon dequeueing???

> But if you change kill(getpid(), 2) to tkill(getpid(), 2)) then the
> output should be:
>
> 	1 1
> 	2 0

Right.

> So, what happens with test_with_pthread_kill() is: the sub-thread
> likely deques both signals, SIGSEGV=11 and SIGUSR1=10 and starts
> the handler for SIGSEGV.
>
> With test_with_kill(), the child dequeues both signals too, but
> runs the handler for SIGUSR1 first, because it was send by kill(),
> not tkill().
>
> If you modify your test-case so that test_signal == SIGIO, then
> I bet test_with_pthread_kill() won't hit is_signal_blocked() too.
> Or you can modify test_with_kill() to use tkill(), in that case
> you should see the same behaviour as with test_with_pthread_kill().
>
> Please don't hesitate to ask more questions.

Thank you,
Gabor

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ