Bug#823754: dbus execs nonconsenting programs with SIGPIPE ignored

2016-05-08 Thread Ian Jackson
Package: dbus
Version: 1.10.8-1

While investigating #823460 "lightdm: SIGPIPE ignored in session" in
developed a libc patch which logs a message whenever any new program
starts up an with unusual setup for SIGPIPE.

The logfile contains entries like this:

  2016-04-08 12:15:12 UTC:/sbin/wpa_supplicant[3350] execd oddly
  (parent /usr/bin/dbus-daemon[3349]): Broken pipe: SIG_IGN

It is a bug to execute a program with SIGPIPE ignored without its
consent.  (Or to put it another way, it is not part of the
specification of programs in general, on a unix system, that they will
function correctly if run with anomalous signal configuration.)

In this case I see quite a few programs in the log being executed with
SIGPIPE set to SIG_IGN.  For many of thexe programs I don't really
know whether the consent.  But I think I know that wpa_supplicant
doesn't; and I doubt that nm-dispatcher or the various systemd-*
programs document that this is permitted or expected.

In practice the fallout from this bug is likely to be modest because
many of these programs are daemons of one kind or another anyway, and
few of them tend to do their work with a lot of pipes etc.

But one possible consequence is that daemons or other long-lived
service processes might fail to terminate when their socket peer goes
away, and instead might end up spinning on the cpu.

I will attach the glibc patch I used, and an extract from the log it
wrote.

Ian.


-- System Information:
Debian Release: stretch/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.5.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.utf-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: sysvinit (via /sbin/init)

Versions of packages dbus depends on:
ii  adduser  3.114
ii  init-system-helpers  1.29
ii  libapparmor1 2.10-4
ii  libaudit11:2.4.5-1+b1
ii  libc62.22-7
ii  libcap-ng0   0.7.7-1+b1
ii  libdbus-1-3  1.10.8-1
ii  libexpat12.1.1-1
ii  libselinux1  2.5-1
ii  libsystemd0  229-5
ii  lsb-base 9.20160110

dbus recommends no packages.

Versions of packages dbus suggests:
ii  dbus-x11  1.10.8-1

Versions of packages dbus is related to:
ii  dbus-x11  1.10.8-1
ii  systemd   229-5
pn  systemd-sysv  

-- no debconf information
diff --git a/csu/init-first.c b/csu/init-first.c
index b3bacdd..751fc5a 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -39,6 +39,92 @@ int __libc_argc attribute_hidden;
 char **__libc_argv attribute_hidden;
 
 
+#include 
+#include 
+#include 
+#include 
+
+static void
+__libc_check_sigpipe (const char *argv0)
+{
+  static const int sigs[] = { SIGPIPE, SIGTERM, SIGALRM, 9 };
+  const int *sigp;
+  int sig;
+  struct sigaction sa;
+  sigset_t mask;
+  int r;
+  const char *oddity;
+
+  sig = 0;
+  r = sigprocmask(SIG_UNBLOCK, 0, &mask);
+  if (r) { oddity = strerror(errno); goto bad; }
+
+  for (sigp = sigs; (sig = *sigp); sigp++) {
+r = sigaction(SIGPIPE, 0, &sa);
+if (r) { oddity = strerror(errno); goto bad; }
+if (sa.sa_handler == SIG_IGN) { oddity = "SIG_IGN"; goto bad; }
+if (sigismember(&mask, sig)) { oddity = "blocked"; goto bad; }
+  }
+  return;
+
+ bad:;
+  int logfd = -1;
+  FILE *logf = 0;
+
+  logfd = open("/var/log/exec-sigignblock.log", O_APPEND|O_WRONLY);
+  if (logfd < 0)
+if (errno == ENOENT || errno == EACCES || errno == EPERM)
+  return;
+
+  logf = fdopen(logfd, "a");
+  if (!logf) goto fail;
+  logfd = -1; /* eaten by fdopen */
+
+  unsigned long ourpid = getpid();
+  unsigned long ppid = getppid();
+  char parentbuf[100];
+
+  snprintf(parentbuf, sizeof(parentbuf), "/proc/%lu/exe", ppid);
+  r = readlink(parentbuf, parentbuf, sizeof(parentbuf)-1);
+  if (r < 0) {
+const char *m = strerror(errno);
+strncpy(parentbuf, m, sizeof(parentbuf)-1);
+parentbuf[sizeof(parentbuf)-1] = 0;
+  } else if (r == 0) {
+strcpy(parentbuf, "\"\"");
+  } else {
+parentbuf[r] = 0;
+  }
+
+  time_t now;
+  now = time(NULL);
+  if (now == (time_t)-1) { errno = EIO; goto fail; }
+
+  struct tm *gmt = gmtime(&now);
+  if (!gmt) goto fail;
+
+  r = fprintf(logf, "%04d-%02d-%02d %02d:%02d:%02d UTC:"
+	  "%s[%lu] execd oddly (parent %s[%lu]): %s: %s\n",
+	  gmt->tm_year+1900, gmt->tm_mon, gmt->tm_mday,
+	  gmt->tm_hour, gmt->tm_min, gmt->tm_sec,
+	  argv0, ourpid,
+	  parentbuf, ppid,
+	  sig ? strsignal(sig) : "sigprocmask", oddity);
+  if (r < 0) goto fail;
+
+  r = fclose(logf);
+  logf = 0;
+  if (r) goto fail;
+
+  return;
+
+ fail:
+  perror("__libc_check_sigpipe report oddity");
+  if (logf) fclose(logf);
+  if (logfd>=0) close(logfd);
+  return;
+}
+
 void
 __libc_init_first (int argc, char **argv, char **envp)
 {
@@ -96,6 +182,8 @@ _init (int argc, char **argv, char **envp)
 #if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS
   __libc_global_ctors ();
 #endif
+

Bug#823754: dbus execs nonconsenting programs with SIGPIPE ignored

2016-05-08 Thread Simon McVittie
On Sun, 08 May 2016 at 15:44:17 +0100, Ian Jackson wrote:
> It is a bug to execute a program with SIGPIPE ignored without its
> consent.  (Or to put it another way, it is not part of the
> specification of programs in general, on a unix system, that they will
> function correctly if run with anomalous signal configuration.)

The anecdotal evidence is that programs in general do not necessarily
function correctly if SIGPIPE is *not* ignored, either; one major problem
with SIGPIPE is that it is also sent when disconnected from a TCP or
AF_UNIX socket (unless the relatively recent MSG_NOSIGNAL flag is used on
every read and every write), and that's hardly ever what the author of the
networking code expected or intended. dbus-daemon did start activatable
services with SIGPIPE unignored at one point, and it broke services
in practice: see .
(You'll notice that I used basically the same arguments there that you
are using here, and was overruled.)

systemd also starts services with SIGPIPE ignored by default (there is
an IgnoreSIGPIPE=false option which unit files can use if desired, see
systemd.exec(5)).

libdbus also used to ignore SIGPIPE unconditionally when used. This one
was clearly a bug, because libraries shouldn't alter global state, but
immediately exiting from the default SIGPIPE handler when disconnected
from the bus (with no opportunity for cleanup) was considered to be a
worse bug. We now use MSG_NOSIGNAL if supported, and only ignore SIGPIPE
globally if there is no MSG_NOSIGNAL.

I'm not sure whether this is wontfix or "not a bug", but either way
it's unlikely to change. Would you feel better about it if the D-Bus
Specification specifically said that activatable services on Unix
are started with SIGPIPE ignored?

S



Bug#823754: dbus execs nonconsenting programs with SIGPIPE ignored

2016-05-08 Thread Ian Jackson
Simon McVittie writes ("Re: Bug#823754: dbus execs nonconsenting programs with 
SIGPIPE ignored"):
> I'm not sure whether this is wontfix or "not a bug", but either way
> it's unlikely to change. Would you feel better about it if the D-Bus
> Specification specifically said that activatable services on Unix
> are started with SIGPIPE ignored?

Yes, I would - please see my later followup.

Ian.