mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Gábor Melis" <mega@retes.hu>
To: Oleg Nesterov <oleg@redhat.com>
Cc: linux-kernel@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>
Subject: Re: Signal delivery order
Date: Sun, 15 Mar 2009 23:06:52 +0100	[thread overview]
Message-ID: <200903152306.53031.mega@retes.hu> (raw)
In-Reply-To: <20090315172926.GA21095@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 2098 bytes --]

On Domingo 15 Marzo 2009, Oleg Nesterov wrote:
> On 03/15, Gábor Melis wrote:
> > On Domingo 15 Marzo 2009, Oleg Nesterov wrote:
> > > 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?
>
> Can't understand the question. Could you reiterate?

No need, my question was answered below.

> > > 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
>
> yes.
>
> the kernel changes ip (instruction pointer) to sig_1.
>
> > its handler is invoked
>
> no.
>
> We never return to user-space with a pending signal. We dequeue
> signal 2 too, and change ip to sig_2.
>
> Now, since there are no more pending signals, we return to the user
> space, and start sig_2().

I see. I guess in addition to changing the ip, the stack frobbing magic 
arranges that sig_2 returns to sig_1 or some code that calls sig_1.

From the point of view of sig_2 it seems that sig_1 is already invoked 
because it has its sigmask in effect and the ip in the ucontext of 
sig_2 points to sig_1 as the attached signal-test.c shows:

sig_1=80485a7
sig_2=80485ed
2 1
eip: 80485a7
1 0
eip: b7fab424

The revised signal-delivery-order.c (also attached) outputs:

test_handler=8048727
sigsegv_handler=804872c
eip: 8048727
esp: b7d94cb8

which shows that sigsegv_handler also has incorrect eip in the context.

[-- Attachment #2: signal-delivery-order.c --]
[-- Type: text/x-csrc, Size: 2195 bytes --]

#include <signal.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ucontext.h>
#include <unistd.h>

int test_signal;
int *page_address;
pthread_t tid;

int is_signal_blocked(int signum)
{
    sigset_t set;
    pthread_sigmask(SIG_BLOCK, 0, &set);
    return (sigismember(&set, signum));
}

void *eip(struct ucontext *context)
{
    return (void *)context->uc_mcontext.gregs[14];
}

void test_handler(int signal, siginfo_t *info, void *context)
{
}

void sigsegv_handler(int signal, siginfo_t *info, void *context)
{
    /* The test signal is blocked only in test_handler. */
    if (is_signal_blocked(test_signal)) {
        printf("eip: %x\n", eip(context));
        _exit(27);
    }
    mprotect(page_address, 4096, PROT_READ | PROT_WRITE);
}

void *make_faults(void *arg)
{
    while (1) {
        mprotect(page_address, 4096, PROT_NONE);
        *page_address = 1;
    }
}

void *reserve_page(void)
{
    int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
    void *actual = mmap(0, 4096, PROT_NONE, flags, -1, 0);
    if (actual == MAP_FAILED) {
        perror("mmap");
        return 0;
    }
    return actual;
}

void install_handlers(void)
{
    struct sigaction sa;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = test_handler;
    sigaction(test_signal, &sa, 0);
    sa.sa_sigaction = sigsegv_handler;
    sigaction(SIGSEGV, &sa, 0);
}

void test_with_pthread_kill()
{
    page_address = (int *)reserve_page();
    install_handlers();
    if (pthread_create(&tid, 0, make_faults, 0) < 0)
        perror("pthread_create");
    while(1) {
        pthread_kill(tid, test_signal);
    }
}

void test_with_kill()
{
    pid_t pid = fork();
    if (pid == 0) {
        page_address = (int *)reserve_page();
        install_handlers();
        make_faults(0);
    } else {
        while (1) {
            kill(pid, test_signal);
        }
    }
}

int main(void)
{
    test_signal = SIGUSR1;
    printf("test_handler=%x\n", test_handler);
    printf("sigsegv_handler=%x\n", sigsegv_handler);
    test_with_pthread_kill();
    /* Forking and kill()ing works as expected: */
    /* test_with_kill(); */
}

[-- Attachment #3: signal-test.c --]
[-- Type: text/x-csrc, Size: 1180 bytes --]

#include <syscall.h>
#include <signal.h>
#include <stdio.h>
#include <ucontext.h>

int is_blocked(int sig)
{
    sigset_t set;
    sigprocmask(SIG_BLOCK, NULL, &set);
    return sigismember(&set, sig);
}

void *eip(struct ucontext *context)
{
    return (void *)context->uc_mcontext.gregs[14];
}

void sig_1(int sig, siginfo_t *info, struct ucontext *context)
{
    printf("%d %d\n", sig, is_blocked(2));
    printf("eip: %x\n", eip(context));
}

void sig_2(int sig, siginfo_t *info, struct ucontext *context)
{
    printf("%d %d\n", sig, is_blocked(1));
    printf("eip: %x\n", eip(context));
}

int tkill(int tid, int sig)
{
    syscall(SYS_tkill, tid, sig);
}

int main(void)
{
    sigset_t set;

    struct sigaction sa;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = sig_1;
    sigaction(1, &sa, 0);
    sa.sa_sigaction = sig_2;
    sigaction(2, &sa, 0);

    sigemptyset(&set);
    sigaddset(&set, 1);
    sigaddset(&set, 2);
    printf("sig_1=%x\n", sig_1);
    printf("sig_2=%x\n", sig_2);
    sigprocmask(SIG_BLOCK, &set, NULL);

    kill(getpid(), 1);
    kill(getpid(), 2);

    sigprocmask(SIG_UNBLOCK, &set, NULL);

    return 0;
}

  reply	other threads:[~2009-03-15 22:07 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-03-14 16:50 Gábor Melis
2009-03-15  9:44 ` Oleg Nesterov
2009-03-15 14:40   ` Gábor Melis
2009-03-15 17:29     ` Oleg Nesterov
2009-03-15 22:06       ` Gábor Melis [this message]
2009-03-16  0:28         ` Oleg Nesterov
2009-03-16  8:34           ` Gábor Melis
2009-03-16 21:13             ` Oleg Nesterov
2009-03-16 22:56               ` Chris Friesen
2009-03-17  4:13                 ` Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order) Oleg Nesterov
2009-03-17  4:25                   ` Oleg Nesterov
2009-03-17  8:23                   ` Gábor Melis
2009-03-17  9:25                     ` Oleg Nesterov
2009-03-17 10:20                       ` Gábor Melis
2009-03-17 10:43                         ` Oleg Nesterov
2009-03-17 15:56                     ` Linus Torvalds
2009-03-17 19:20                       ` Q: SEGSEGV && uc_mcontext->ip David Miller
2009-03-18  9:58                       ` Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order) Gábor Melis
2009-03-18  7:59                   ` Roland McGrath
2009-03-18  9:02                     ` RT signal queue overflow (Was: Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order)) Gábor Melis
2009-03-18 14:52                       ` Linus Torvalds
2009-03-18 15:23                         ` Gábor Melis

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=200903152306.53031.mega@retes.hu \
    --to=mega@retes.hu \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oleg@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome