From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48753) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VgCyq-0003lV-Pr for qemu-devel@nongnu.org; Tue, 12 Nov 2013 07:22:16 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VgCyk-0002nf-Oi for qemu-devel@nongnu.org; Tue, 12 Nov 2013 07:22:04 -0500 Received: from mx1.redhat.com ([209.132.183.28]:56806) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VgCyk-0002nb-F9 for qemu-devel@nongnu.org; Tue, 12 Nov 2013 07:21:58 -0500 Message-ID: <52821E08.8030508@redhat.com> Date: Tue, 12 Nov 2013 13:24:40 +0100 From: Laszlo Ersek MIME-Version: 1.0 References: <52810AEA.5020806@redhat.com> In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] audit needed for signal handlers List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Max Filippov Cc: "qemu-devel@nongnu.org" On 11/11/13 19:03, Max Filippov wrote: > On Mon, Nov 11, 2013 at 8:50 PM, Eric Blake wrote: >> Quick - identify the bug in this code (from ui/curses.c): >> >> static void curses_winch_handler(int signum) >> { >> struct winsize { >> unsigned short ws_row; >> unsigned short ws_col; >> unsigned short ws_xpixel; /* unused */ >> unsigned short ws_ypixel; /* unused */ >> } ws; >> >> /* terminal size changed */ >> if (ioctl(1, TIOCGWINSZ, &ws) == -1) > > An unsafe function is called in a signal. See man 7 signal, > section 'Async-signal-safe functions'. This should be avoided. > >> return; >> >> resize_term(ws.ws_row, ws.ws_col); >> curses_calc_pad(); >> invalidate = 1; >> >> /* some systems require this */ >> signal(SIGWINCH, curses_winch_handler); >> } >> >> Here's a hint: ioctl() can clobber errno. > > I believe it cannot, at least in linux, as technically the signal > handler is always called in a new thread, specifically created > to only handle that signal, and errno should be thread-local. That's incorrect (*). The handler runs on a new *stack frame*, but inside the same thread. You can specify an alternate stack for signal handlers to run on in advance (see SA_ONSTACK / sigaltstack()), in which case the new stack frame will be "allocated" there. Otherwise the system will just use the normal stack. The handler indeed runs like an "unexpected", "out-of-the-blue" normal function call. It is actually pretty vital that the handler is run by the specific thread that the signal has been delivered to. (*) Example code (not a correct/portable program due to the race on "errno", but it does disprove the idea that errno is "protected" on Linux): #define _XOPEN_SOURCE 600 #include #include #include #include static void ringring(int signum) { errno = -12; } int main(void) { sigaction(SIGALRM, &(struct sigaction){ .sa_handler = &ringring }, NULL); alarm(1); errno = 0; /* pause() would clobber errno */ while (errno == 0) ; printf("%d\n", errno); return 0; } Thanks Laszlo