Package: gnupg-agent Version: 2.0.9-3 Severity: critical gnupg-agent somehow manages to change the SigBlk mask causing all child processes that are spawned part of the X session to have the SigBlk mask set causing real-time signals to be blocked. This breaks all applications spawned in that X session that rely on real-time signals.
As this breaks unrelated software I set the severity to critical. Here the summary of my full investigation: About 2 months ago I started to suffer from an issue that first looked like a bug in Mono's threading implementation. The test-case to reproduce it looks like this: Attachment: test-thread-abort.cs Compile: mcs test-thread-abort.cs Run: mono test-thread-abort.exe My output: thread.Start() Worker(): thread started Worker(): working... 0 Worker(): working... 1 Worker(): working... 2 Worker(): working... 3 Worker(): working... 4 thread.Abort() press enter to quit! Worker(): working... 5 Worker(): working... 6 Worker(): working... 7 Worker(): working... 8 Worker(): working... 9 Worker(): working... 10 Worker(): working... 11 Worker(): working... 12 (continuing forever -> killed using ^C) The expected output: thread.Start() Worker(): thread started Worker(): working... 0 Worker(): working... 1 Worker(): working... 2 Worker(): working... 3 Worker(): working... 4 thread.Abort() press enter to quit! Worker(): thread aborted! Worker(): thread ended The thread was never aborted and thus forever continued on my system. After more investigation in Mono's threading implementation I found that it uses real-time signals to control the threads. A strace then showed that the signal (SIGRT1) was send but never received.... This made me really curious. So I wrote a C test-case for this issue, which looks like this: Attachment: test-signal.c Compile: gcc test-signal.c -o test-signal Run: ./test-signal My Output: SIGRTMIN: 34 sigismember(): 1 SIGRTMIN is blocked, trying to unblock...done. sigismember(): 0 SIGRT_1 received SIGRT_2 received SIGQUIT received The expected output: SIGRTMIN: 34 sigismember(): 0 SIGRT_1 received SIGRT_2 received SIGQUIT received And that proved the signal (SIGRT) is indeed already blocked when the application is started. Then I found out / learned that blocking signals is a feature and the SigBlk mask is inherited to child processes. So something was setting this mask, and I could not find out what it was till today. I reinstalled my system (1 week ago) after I could not find the exact cause of this issue (after 3 continuous days of investigation) and today it started to happen again, after I was sponsoring a package upload, for which I had to install pscd and gnupg-agent to get my crypto card working again (after the reinstall). Then I disabled the gpg-agent in my ~/.gnupg/gpg.conf, restarted my X session and viola SigBlk mask is back to normal and all my lovely applications work again like they should. Enabling the gpg-agent in ~/.gnupg/gpg.conf again brings the issue back. I noticed the gpg-agent is started in /etc/X11/Xsession.d/90gpg-agent, but I no have no idea how it manages to change (or rather inherits) the SigBlk mask of other processes spawned in the X session.... Here also a little detection script I wrote to identify processes with that set SigBlk mask (it also finds some "false-positives" as some apps really need that mask, but not _all_ processes launched under the X session!) Attachment: proc-sigblk.sh: My output: Name: x-session-manag Pid: 21699 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: dbus-launch Pid: 21757 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: dbus-daemon Pid: 21758 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: seahorse-agent Pid: 21764 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-settings- Pid: 21769 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: metacity Pid: 21781 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-panel Pid: 21782 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: nautilus Pid: 21783 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-screensav Pid: 21786 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-vfs-daemo Pid: 21795 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: bluetooth-apple Pid: 21798 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-do Pid: 21799 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: update-notifier Pid: 21803 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-do Pid: 21804 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: system-config-p Pid: 21811 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: kerneloops-appl Pid: 21815 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-volume-ma Pid: 21817 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: nm-applet Pid: 21819 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-power-man Pid: 21827 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: multiload-apple Pid: 21849 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: mixer_applet2 Pid: 21852 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gweather-applet Pid: 21855 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: locate Pid: 21862 Uid: 1000 1000 1000 1000 Gid: 1000 105 105 105 Name: locate Pid: 21863 Uid: 1000 1000 1000 1000 Gid: 1000 105 105 105 Name: mapping-daemon Pid: 21866 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-terminal Pid: 21868 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: gnome-pty-helpe Pid: 21871 Uid: 1000 1000 1000 1000 Gid: 1000 43 43 43 Name: bonobo-activati Pid: 3878 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 Name: egrep Pid: 22046 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 The expected output: (none or a very small set of applications like gconfd-2 or some gnome applets) -- Regards, Mirco 'meebey' Bauer PGP-Key ID: 0xEEF946C8 FOSS Developer [EMAIL PROTECTED] http://www.meebey.net/ PEAR Developer [EMAIL PROTECTED] http://pear.php.net/ Debian Developer [EMAIL PROTECTED] http://www.debian.org/
#include <stdio.h> #include <signal.h> void sigint_handler(void); void sigquit_handler(void); void sigrt1_handler(void); void sigrt2_handler(void); void sigrt3_handler(void); void sigpwr_handler(void); main() { printf("SIGRTMIN: %i\n", SIGRTMIN); sigset_t set, old_set, new_set; int ismember; if (sigprocmask(SIG_SETMASK, NULL, &old_set) != 0) printf("sigprocmask() failed!\n"); ismember = sigismember(&old_set, SIGRTMIN); printf("sigismember(): %i\n", ismember); if (ismember) { printf("SIGRTMIN is blocked, trying to unblock..."); sigemptyset(&new_set); sigaddset(&new_set, SIGRTMIN); sigaddset(&new_set, SIGRTMIN+1); if (sigprocmask(SIG_UNBLOCK, &new_set, NULL) != 0) { printf("failed!\n"); exit(1); } printf("done.\n"); sigemptyset(&set); ismember = sigismember(&set, SIGRTMIN); printf("sigismember(): %i\n", ismember); } signal(SIGINT, sigint_handler); signal(SIGQUIT, sigquit_handler); signal(SIGRTMIN, sigrt1_handler); signal(SIGRTMIN+1, sigrt2_handler); signal(SIGRTMIN+2, sigrt3_handler); signal(SIGPWR, sigpwr_handler); kill(getpid(), SIGRTMIN); kill(getpid(), SIGRTMIN+1); kill(getpid(), SIGQUIT); for(;;); /* infinite loop */ } void sigint_handler(void) { signal(SIGINT, sigint_handler); /* NOTE some versions of UNIX will reset signal to default after each call. So for portability reset signal each time */ printf("SIGINT received\n"); } void sigquit_handler(void) { printf("SIGQUIT received\n"); exit(0); /* normal exit status */ } void sigrt1_handler(void) { printf("SIGRT_1 received\n"); } void sigrt2_handler(void) { printf("SIGRT_2 received\n"); } void sigrt3_handler(void) { printf("SIGRT_3 received\n"); } void sigpwr_handler(void) { printf("SIGPWR received\n"); }
using System; using System.Threading; using System.Runtime.InteropServices; class MainClass { static int loopCount; static void Main() { Thread thread = new Thread(new ThreadStart(Worker)); Console.WriteLine("thread.Start()"); thread.IsBackground = true; thread.Start(); // give the thread some time to spawn Thread.Sleep(5000); Console.WriteLine("thread.Abort()"); thread.Abort(); Console.WriteLine("press enter to quit!"); Console.ReadLine(); } static void Worker() { Console.WriteLine("Worker(): thread started"); try { while (true) { Console.WriteLine("Worker(): working... " + loopCount++); Thread.Sleep(1000); } } catch (ThreadAbortException) { Thread.ResetAbort(); Console.WriteLine("Worker(): thread aborted!"); } Console.WriteLine("Worker(): thread ended"); } }
proc-sigblk.sh
Description: application/shellscript