From e87d1a63bdef0ae08f2d94d67fd8daa8fbb63fb4 Mon Sep 17 00:00:00 2001
From: Shea Levy <shea@shealevy.com>
Date: Mon, 18 Mar 2013 11:13:53 -0400
Subject: [PATCH] killUser: Don't let the child kill itself on Apple

The kill(2) in Apple's libc follows POSIX semantics, which means that
kill(-1, SIGKILL) will kill the calling process too. Since nix has no
way to distinguish between the process successfully killing everything
and the process being killed by a rogue builder in that case, it can't
safely conclude that killUser was successful.

Luckily, the actual kill syscall takes a parameter that determines
whether POSIX semantics are followed, so we can call that syscall
directly and avoid the issue on Apple.

Signed-off-by: Shea Levy <shea@shealevy.com>
---
 src/libutil/util.cc | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index dad5f624b..bc07a84f4 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -12,6 +12,10 @@
 #include <fcntl.h>
 #include <limits.h>
 
+#ifdef __APPLE__
+#include <sys/syscall.h>
+#endif
+
 #include "util.hh"
 
 
@@ -851,7 +855,16 @@ void killUser(uid_t uid)
                 throw SysError("setting uid");
 
             while (true) {
+#ifdef __APPLE__
+                /* OSX's kill syscall takes a third parameter that, among other
+                   things, determines if kill(-1, signo) affects the calling
+                   process. In the OSX libc, it's set to true, which means
+                   "follow POSIX", which we don't want here
+                 */
+                if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
+#else
                 if (kill(-1, SIGKILL) == 0) break;
+#endif
                 if (errno == ESRCH) break; /* no more processes */
                 if (errno != EINTR)
                     throw SysError(format("cannot kill processes for uid `%1%'") % uid);