From 34b0311d0eb906bd801cc1e9a329ed211b81496f Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 13 Jan 2012 09:47:01 +0100 Subject: hosted/pcm/alsa: Use alternate signal stack for the async callback. Signals are by default executed on the user stack, i.e. the stack of the currently active thread. This has two problems: 1) The stack size of the current stack is likely insufficient (unless using sigaltstack threads) because our stack sizes are normally below MINSIGSTKSIZE which is needed to deliver a signal. 2) Some of our asm code does nasty tricks with the stack pointer. When a signal comes in during this bad things can happen, e.g. random memory being overwritten or simply a crash. Using a well defined stack fixes this. This is comparable with the separate irq stack on native targets. --- firmware/target/hosted/pcm-alsa.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'firmware') diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index 7daf485f18..02cb34ea5b 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c @@ -27,6 +27,11 @@ * This driver uses the so-called unsafe async callback method and hardcoded device * names. It fails when the audio device is busy by other apps. * + * To make the async callback safer, an alternative stack is installed, since + * it's run from a signal hanlder (which otherwise uses the user stack). If + * tick tasks are run from a signal handler too, please install + * an alternative stack for it too. + * * TODO: Rewrite this to do it properly with multithreading * * Alternatively, a version using polling in a tick task is provided. While @@ -76,6 +81,7 @@ static size_t pcm_size = 0; #ifdef USE_ASYNC_CALLBACK static snd_async_handler_t *ahandler; static pthread_mutex_t pcm_mtx; +static char signal_stack[SIGSTKSZ]; #else static int recursion; #endif @@ -271,12 +277,37 @@ static int async_rw(snd_pcm_t *handle) short *samples; #ifdef USE_ASYNC_CALLBACK + /* assign alternative stack for the signal handlers */ + stack_t ss = { + .ss_sp = signal_stack, + .ss_size = sizeof(signal_stack), + .ss_flags = 0 + }; + struct sigaction sa; + + err = sigaltstack(&ss, NULL); + if (err < 0) + { + DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); + return err; + } + err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL); if (err < 0) { DEBUGF("Unable to register async handler: %s\n", snd_strerror(err)); return err; } + + /* only modify the stack the handler runs on */ + sigaction(SIGIO, NULL, &sa); + sa.sa_flags |= SA_ONSTACK; + err = sigaction(SIGIO, &sa, NULL); + if (err < 0) + { + DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); + return err; + } #endif /* fill buffer with silence to initiate playback without noisy click */ -- cgit v1.2.3