Andy Lutomirski 8e15cc3
From 8412c867a501e3a68e55fef6215e86d3ac9f617b Mon Sep 17 00:00:00 2001
Andy Lutomirski 8e15cc3
Message-Id: <8412c867a501e3a68e55fef6215e86d3ac9f617b.1398703637.git.luto@amacapital.net>
Andy Lutomirski 8e15cc3
In-Reply-To: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net>
Andy Lutomirski 8e15cc3
References: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net>
Andy Lutomirski 8e15cc3
From: David Adam <zanchey@ucc.gu.uwa.edu.au>
Andy Lutomirski 8e15cc3
Date: Sun, 20 Apr 2014 17:51:27 +0800
Andy Lutomirski 8e15cc3
Subject: [PATCH 3/4] Check effective credentials of socket peers
Andy Lutomirski 8e15cc3
Andy Lutomirski 8e15cc3
Fix for CVE-2014-2905.
Andy Lutomirski 8e15cc3
Andy Lutomirski 8e15cc3
Code for getpeereid() on non-BSD systems imported from the PostgreSQL
Andy Lutomirski 8e15cc3
project under a BSD-style license.
Andy Lutomirski 8e15cc3
---
Andy Lutomirski 8e15cc3
 configure.ac        |  4 +--
Andy Lutomirski 8e15cc3
 doc_src/license.hdr | 30 +++++++++++++++++++-
Andy Lutomirski 8e15cc3
 env_universal.cpp   |  9 ++++++
Andy Lutomirski 8e15cc3
 fallback.cpp        | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
Andy Lutomirski 8e15cc3
 fallback.h          |  4 +++
Andy Lutomirski 8e15cc3
 fishd.cpp           |  9 +++++-
Andy Lutomirski 8e15cc3
 osx/config.h        |  6 ++++
Andy Lutomirski 8e15cc3
 7 files changed, 137 insertions(+), 5 deletions(-)
Andy Lutomirski 8e15cc3
Andy Lutomirski 8e15cc3
diff --git a/configure.ac b/configure.ac
Andy Lutomirski 8e15cc3
index ea7c592..bdfa5f0 100644
Andy Lutomirski 8e15cc3
--- a/configure.ac
Andy Lutomirski 8e15cc3
+++ b/configure.ac
Andy Lutomirski 8e15cc3
@@ -557,7 +557,7 @@ LIBS=$LIBS_COMMON
Andy Lutomirski 8e15cc3
 # Check presense of various header files
Andy Lutomirski 8e15cc3
 #
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
-AC_CHECK_HEADERS([getopt.h termios.h sys/resource.h term.h ncurses/term.h ncurses.h curses.h stropts.h siginfo.h sys/select.h sys/ioctl.h execinfo.h spawn.h sys/sysctl.h])
Andy Lutomirski 8e15cc3
+AC_CHECK_HEADERS([getopt.h termios.h sys/resource.h term.h ncurses/term.h ncurses.h curses.h stropts.h siginfo.h sys/select.h sys/ioctl.h execinfo.h spawn.h sys/sysctl.h sys/un.h sys/ucred.h ucred.h ])
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 if test x$local_gettext != xno; then
Andy Lutomirski 8e15cc3
   AC_CHECK_HEADERS([libintl.h])
Andy Lutomirski 8e15cc3
@@ -698,7 +698,7 @@ fi
Andy Lutomirski 8e15cc3
 AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
Andy Lutomirski 8e15cc3
 AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
Andy Lutomirski 8e15cc3
 AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg )
Andy Lutomirski 8e15cc3
-AC_CHECK_FUNCS( backtrace backtrace_symbols sysconf getifaddrs )
Andy Lutomirski 8e15cc3
+AC_CHECK_FUNCS( backtrace backtrace_symbols sysconf getifaddrs getpeerucred getpeereid )
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 if test x$local_gettext != xno; then
Andy Lutomirski 8e15cc3
   AC_CHECK_FUNCS( gettext dcgettext )
Andy Lutomirski 8e15cc3
diff --git a/doc_src/license.hdr b/doc_src/license.hdr
Andy Lutomirski 8e15cc3
index 64bab10..f292722 100644
Andy Lutomirski 8e15cc3
--- a/doc_src/license.hdr
Andy Lutomirski 8e15cc3
+++ b/doc_src/license.hdr
Andy Lutomirski 8e15cc3
@@ -1400,6 +1400,34 @@ POSSIBILITY OF SUCH DAMAGES.
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 

Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
-*/
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+

License for getpeereid

Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+\c fish contains code imported from the PostgreSQL project under
Andy Lutomirski 8e15cc3
+license, namely the getpeereid fallback function. This code is copyrighted
Andy Lutomirski 8e15cc3
+by:
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+Portions Copyright (c) 1994, The Regents of the University of California
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+Permission to use, copy, modify, and distribute this software and its
Andy Lutomirski 8e15cc3
+documentation for any purpose, without fee, and without a written agreement
Andy Lutomirski 8e15cc3
+is hereby granted, provided that the above copyright notice and this
Andy Lutomirski 8e15cc3
+paragraph and the following two paragraphs appear in all copies.
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
Andy Lutomirski 8e15cc3
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
Andy Lutomirski 8e15cc3
+LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
Andy Lutomirski 8e15cc3
+DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
Andy Lutomirski 8e15cc3
+POSSIBILITY OF SUCH DAMAGE.
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
Andy Lutomirski 8e15cc3
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
Andy Lutomirski 8e15cc3
+AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Andy Lutomirski 8e15cc3
+ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
Andy Lutomirski 8e15cc3
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 \htmlonly  \endhtmlonly
Andy Lutomirski 8e15cc3
+*/
Andy Lutomirski 8e15cc3
diff --git a/env_universal.cpp b/env_universal.cpp
Andy Lutomirski 8e15cc3
index c7d060a..987f88b 100644
Andy Lutomirski 8e15cc3
--- a/env_universal.cpp
Andy Lutomirski 8e15cc3
+++ b/env_universal.cpp
Andy Lutomirski 8e15cc3
@@ -88,6 +88,8 @@ static int try_get_socket_once(void)
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
     wdir = path;
Andy Lutomirski 8e15cc3
     wuname = user;
Andy Lutomirski 8e15cc3
+    uid_t seuid;
Andy Lutomirski 8e15cc3
+    gid_t segid;
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
     if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
Andy Lutomirski 8e15cc3
     {
Andy Lutomirski 8e15cc3
@@ -135,6 +137,13 @@ static int try_get_socket_once(void)
Andy Lutomirski 8e15cc3
         return -1;
Andy Lutomirski 8e15cc3
     }
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
+    if ((getpeereid(s, &seuid, &segid) != 0) || seuid != geteuid())
Andy Lutomirski 8e15cc3
+    {
Andy Lutomirski 8e15cc3
+        debug(1, L"Wrong credentials for socket %s at fd %d", name.c_str(), s);
Andy Lutomirski 8e15cc3
+        close(s);
Andy Lutomirski 8e15cc3
+        return -1;
Andy Lutomirski 8e15cc3
+    }
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
     if ((make_fd_nonblocking(s) != 0) || (fcntl(s, F_SETFD, FD_CLOEXEC) != 0))
Andy Lutomirski 8e15cc3
     {
Andy Lutomirski 8e15cc3
         wperror(L"fcntl");
Andy Lutomirski 8e15cc3
diff --git a/fallback.cpp b/fallback.cpp
Andy Lutomirski 8e15cc3
index 5e4b3e1..34db397 100644
Andy Lutomirski 8e15cc3
--- a/fallback.cpp
Andy Lutomirski 8e15cc3
+++ b/fallback.cpp
Andy Lutomirski 8e15cc3
@@ -15,8 +15,9 @@
Andy Lutomirski 8e15cc3
 #include <stdio.h>
Andy Lutomirski 8e15cc3
 #include <unistd.h>
Andy Lutomirski 8e15cc3
 #include <sys/types.h>
Andy Lutomirski 8e15cc3
+#include <sys/socket.h>
Andy Lutomirski 8e15cc3
 #include <sys/stat.h>
Andy Lutomirski 8e15cc3
-#include <unistd.h>
Andy Lutomirski 8e15cc3
+#include <sys/param.h>
Andy Lutomirski 8e15cc3
 #include <errno.h>
Andy Lutomirski 8e15cc3
 #include <fcntl.h>
Andy Lutomirski 8e15cc3
 #include <wchar.h>
Andy Lutomirski 8e15cc3
@@ -1521,3 +1522,80 @@ static int mk_wcswidth(const wchar_t *pwcs, size_t n)
Andy Lutomirski 8e15cc3
 }
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 #endif // HAVE_BROKEN_WCWIDTH
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+#ifndef HAVE_GETPEEREID
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+/*-------------------------------------------------------------------------
Andy Lutomirski 8e15cc3
+ *
Andy Lutomirski 8e15cc3
+ * getpeereid.c
Andy Lutomirski 8e15cc3
+ *		get peer userid for UNIX-domain socket connection
Andy Lutomirski 8e15cc3
+ *
Andy Lutomirski 8e15cc3
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
Andy Lutomirski 8e15cc3
+ *
Andy Lutomirski 8e15cc3
+ *
Andy Lutomirski 8e15cc3
+ * IDENTIFICATION
Andy Lutomirski 8e15cc3
+ *	  src/port/getpeereid.c
Andy Lutomirski 8e15cc3
+ *
Andy Lutomirski 8e15cc3
+ *-------------------------------------------------------------------------
Andy Lutomirski 8e15cc3
+ */
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+#ifdef HAVE_SYS_UN_H
Andy Lutomirski 8e15cc3
+#include <sys/un.h>
Andy Lutomirski 8e15cc3
+#endif
Andy Lutomirski 8e15cc3
+#ifdef HAVE_UCRED_H
Andy Lutomirski 8e15cc3
+#include <ucred.h>
Andy Lutomirski 8e15cc3
+#endif
Andy Lutomirski 8e15cc3
+#ifdef HAVE_SYS_UCRED_H
Andy Lutomirski 8e15cc3
+#include <sys/ucred.h>
Andy Lutomirski 8e15cc3
+#endif
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+/*
Andy Lutomirski 8e15cc3
+ * BSD-style getpeereid() for platforms that lack it.
Andy Lutomirski 8e15cc3
+ */
Andy Lutomirski 8e15cc3
+int getpeereid(int sock, uid_t *uid, gid_t *gid)
Andy Lutomirski 8e15cc3
+{
Andy Lutomirski 8e15cc3
+#if defined(SO_PEERCRED)
Andy Lutomirski 8e15cc3
+	/* Linux: use getsockopt(SO_PEERCRED) */
Andy Lutomirski 8e15cc3
+	struct ucred peercred;
Andy Lutomirski 8e15cc3
+	socklen_t so_len = sizeof(peercred);
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+	if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
Andy Lutomirski 8e15cc3
+		so_len != sizeof(peercred))
Andy Lutomirski 8e15cc3
+		return -1;
Andy Lutomirski 8e15cc3
+	*uid = peercred.uid;
Andy Lutomirski 8e15cc3
+	*gid = peercred.gid;
Andy Lutomirski 8e15cc3
+	return 0;
Andy Lutomirski 8e15cc3
+#elif defined(LOCAL_PEERCRED)
Andy Lutomirski 8e15cc3
+	/* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */
Andy Lutomirski 8e15cc3
+	struct xucred peercred;
Andy Lutomirski 8e15cc3
+	socklen_t * so_len = sizeof(peercred);
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+	if (getsockopt(sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 ||
Andy Lutomirski 8e15cc3
+		so_len != sizeof(peercred) ||
Andy Lutomirski 8e15cc3
+		peercred.cr_version != XUCRED_VERSION)
Andy Lutomirski 8e15cc3
+		return -1;
Andy Lutomirski 8e15cc3
+	*uid = peercred.cr_uid;
Andy Lutomirski 8e15cc3
+	*gid = peercred.cr_gid;
Andy Lutomirski 8e15cc3
+	return 0;
Andy Lutomirski 8e15cc3
+#elif defined(HAVE_GETPEERUCRED)
Andy Lutomirski 8e15cc3
+	/* Solaris: use getpeerucred() */
Andy Lutomirski 8e15cc3
+	ucred_t    *ucred;
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+	ucred = NULL;				/* must be initialized to NULL */
Andy Lutomirski 8e15cc3
+	if (getpeerucred(sock, &ucred) == -1)
Andy Lutomirski 8e15cc3
+		return -1;
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+	*uid = ucred_geteuid(ucred);
Andy Lutomirski 8e15cc3
+	*gid = ucred_getegid(ucred);
Andy Lutomirski 8e15cc3
+	ucred_free(ucred);
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+	if (*uid == (uid_t) (-1) || *gid == (gid_t) (-1))
Andy Lutomirski 8e15cc3
+		return -1;
Andy Lutomirski 8e15cc3
+	return 0;
Andy Lutomirski 8e15cc3
+#else
Andy Lutomirski 8e15cc3
+	/* No implementation available on this platform */
Andy Lutomirski 8e15cc3
+	errno = ENOSYS;
Andy Lutomirski 8e15cc3
+	return -1;
Andy Lutomirski 8e15cc3
+#endif
Andy Lutomirski 8e15cc3
+}
Andy Lutomirski 8e15cc3
+#endif // HAVE_GETPEEREID
Andy Lutomirski 8e15cc3
diff --git a/fallback.h b/fallback.h
Andy Lutomirski 8e15cc3
index eba91be..6898ea5 100644
Andy Lutomirski 8e15cc3
--- a/fallback.h
Andy Lutomirski 8e15cc3
+++ b/fallback.h
Andy Lutomirski 8e15cc3
@@ -482,3 +482,7 @@ double nan(char *tagp);
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
 #endif
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+#ifndef HAVE_GETPEEREID
Andy Lutomirski 8e15cc3
+int getpeereid(int sock, uid_t *uid, gid_t *gid);
Andy Lutomirski 8e15cc3
+#endif
Andy Lutomirski 8e15cc3
diff --git a/fishd.cpp b/fishd.cpp
Andy Lutomirski 8e15cc3
index edb79c2..1e09524 100644
Andy Lutomirski 8e15cc3
--- a/fishd.cpp
Andy Lutomirski 8e15cc3
+++ b/fishd.cpp
Andy Lutomirski 8e15cc3
@@ -880,6 +880,8 @@ int main(int argc, char ** argv)
Andy Lutomirski 8e15cc3
     int child_socket;
Andy Lutomirski 8e15cc3
     struct sockaddr_un remote;
Andy Lutomirski 8e15cc3
     socklen_t t;
Andy Lutomirski 8e15cc3
+    uid_t sock_euid;
Andy Lutomirski 8e15cc3
+    gid_t sock_egid;
Andy Lutomirski 8e15cc3
     int max_fd;
Andy Lutomirski 8e15cc3
     int update_count=0;
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
@@ -1000,7 +1002,12 @@ int main(int argc, char ** argv)
Andy Lutomirski 8e15cc3
             {
Andy Lutomirski 8e15cc3
                 debug(4, L"Connected with new child on fd %d", child_socket);
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
-                if (make_fd_nonblocking(child_socket) != 0)
Andy Lutomirski 8e15cc3
+                if (((getpeereid(child_socket, &sock_euid, &sock_egid) != 0) || sock_euid != geteuid()))
Andy Lutomirski 8e15cc3
+                {
Andy Lutomirski 8e15cc3
+                    debug(1, L"Wrong credentials for child on fd %d", child_socket);
Andy Lutomirski 8e15cc3
+                    close(child_socket);
Andy Lutomirski 8e15cc3
+                }
Andy Lutomirski 8e15cc3
+                else if (make_fd_nonblocking(child_socket) != 0)
Andy Lutomirski 8e15cc3
                 {
Andy Lutomirski 8e15cc3
                     wperror(L"fcntl");
Andy Lutomirski 8e15cc3
                     close(child_socket);
Andy Lutomirski 8e15cc3
diff --git a/osx/config.h b/osx/config.h
Andy Lutomirski 8e15cc3
index 4968a78..bc058ae 100644
Andy Lutomirski 8e15cc3
--- a/osx/config.h
Andy Lutomirski 8e15cc3
+++ b/osx/config.h
Andy Lutomirski 8e15cc3
@@ -40,6 +40,12 @@
Andy Lutomirski 8e15cc3
 /* Define to 1 if you have the <getopt.h> header file. */
Andy Lutomirski 8e15cc3
 #define HAVE_GETOPT_H 1
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
+/* Define to 1 if you have the `getpeereid' function. */
Andy Lutomirski 8e15cc3
+#define HAVE_GETPEEREID 1
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
+/* Define to 1 if you have the `getpeerucred' function. */
Andy Lutomirski 8e15cc3
+/* #undef HAVE_GETPEERUCRED */
Andy Lutomirski 8e15cc3
+
Andy Lutomirski 8e15cc3
 /* Define to 1 if you have the `gettext' function. */
Andy Lutomirski 8e15cc3
 /* #undef HAVE_GETTEXT */
Andy Lutomirski 8e15cc3
 
Andy Lutomirski 8e15cc3
-- 
Andy Lutomirski 8e15cc3
1.9.0
Andy Lutomirski 8e15cc3