[gnome-keyring] Linux capabilities to overcome limits on locked memory.



commit bc2d1d3789368779e6a39bff6ca841188edef6c7
Author: Yaron Sheffer <yaronf gmx com>
Date:   Tue Nov 2 22:10:37 2010 +0200

    Linux capabilities to overcome limits on locked memory.
    
    Implement review comments, mostly style.
    
    Signed-off-by: Stef Walter <stef memberwebs com>

 configure.in            |   18 +++++++-
 daemon/Makefile.am      |   10 ++++
 daemon/gkd-capability.c |  119 +++++++++++++++++++++++++++++++++++++++++++++++
 daemon/gkd-capability.h |   27 +++++++++++
 daemon/gkd-main.c       |    7 +++
 5 files changed, 180 insertions(+), 1 deletions(-)
---
diff --git a/configure.in b/configure.in
index ba95fe3..a950934 100644
--- a/configure.in
+++ b/configure.in
@@ -430,6 +430,21 @@ if test "$ASN1PARSER" = "no" ; then
 	AC_MSG_ERROR([asn1Parser tool is not installed, try libtasn1 or a related package])
 fi
 
+# -------------------------------------------------------------------
+# libcap2
+#
+
+AC_CHECK_LIB([cap], [cap_get_proc], have_libcap="yes", have_libcap="no")
+
+if test $have_libcap = yes; then
+   AC_DEFINE(HAVE_LIBCAP, 1, [Have libcap2 package, libcap library])
+   DAEMON_LIBS="$DAEMON_LIBS -lcap"
+else
+   AC_MSG_WARN([libcap2 (or development headers) is not installed])
+fi
+
+libcap_status=$have_libcap
+
 # --------------------------------------------------------------------
 # Debug mode
 
@@ -705,7 +720,8 @@ ui/tests/Makefile
 
 echo
 echo "OPTIONAL DEPENDENCIES"
-echo "  PAM:           $pam_status"
+echo "  PAM:                  $pam_status"
+echo "  Linux capabilities:   $libcap_status"
 echo
 echo "CONFIGURATION"
 echo "  SSH Agent:            $ssh_status"
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 296eba5..fcb7c18 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -27,6 +27,7 @@ INCLUDES=	\
 gnome_keyring_daemon_SOURCES = \
 	gkd-glue.c gkd-glue.h \
 	gkd-main.c gkd-main.h \
+	gkd-capability.c gkd-capability.h \
 	gkd-pkcs11.c gkd-pkcs11.h \
 	gkd-util.c gkd-util.h
 
@@ -78,4 +79,13 @@ CLEANFILES = \
 	$(service_DATA) \
 	$(desktop_DATA)
 
+# The daemon is installed as setuid so as to obtain specialized
+# capabilities, then immediately drops permissions. In other words,
+# it does *not* run as setuid.
+# If installing as non-root, chown+chmod will not succeed but
+# the build will continue.
+install-exec-hook:
+	chown root $(bindir)/gnome-keyring-daemon || true
+	chmod u+s $(bindir)/gnome-keyring-daemon || true
+
 @INTLTOOL_DESKTOP_RULE@
diff --git a/daemon/gkd-capability.c b/daemon/gkd-capability.c
new file mode 100644
index 0000000..4ca0db1
--- /dev/null
+++ b/daemon/gkd-capability.c
@@ -0,0 +1,119 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkd-capability.c - the security-critical initial phase of the daemon
+ *
+ * Copyright (C) 2010 Yaron Sheffer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Yaron Sheffer <yaronf gmx com>
+ * Author: Stef Walter <stef thewalter net>
+ */
+
+#include "config.h"
+
+#include "gkd-capability.h"
+
+#ifdef HAVE_LIBCAP
+#include <sys/capability.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+/* Security note: this portion of the code is extremely sensitive.
+ * DO NOT add any other include files.
+ */
+
+/*
+ * No logging, no gettext
+ */
+static void
+early_error (const char *err_string)
+{
+	fprintf (stderr, "gnome-keyring-daemon: %s\n", err_string);
+}
+
+static void
+drop_privileges (void)
+{
+	uid_t orig_uid;
+	gid_t orig_gid;
+
+	orig_uid = getuid ();
+	orig_gid = getgid ();
+
+	/* This is permanent, you cannot go back to root */
+	setgid (orig_gid);
+	setuid (orig_uid);
+
+	/*
+	 * Check that the switch was ok
+	 * We do not allow programs to run without the drop being
+	 * successful as this would possibly run the program
+	 * using root-privs, when that is not what we want
+	 */
+	if ((getegid () != orig_gid) || (geteuid () != orig_uid)) {
+		early_error ("failed to drop privileges, aborting");
+		exit (1);
+	}
+}
+
+/*
+ * Try to obtain the CAP_IPC_LOCK Linux capability.
+ * Then, whether or not this is successful, drop root
+ * privileges to run as the invoking user. The application is aborted
+ * if for any reason we are unable to drop privileges. Note: even gettext
+ * is unavailable!
+ */
+void
+gkd_capability_obtain_capability_and_drop_privileges (void)
+{
+#ifdef HAVE_LIBCAP
+	cap_t caps;
+	cap_value_t cap_list[1];
+
+	caps = cap_get_proc ();
+	if (caps == NULL) {
+		early_error ("capability state cannot be allocated");
+		goto drop;
+	}
+
+	cap_list[0] = CAP_IPC_LOCK;
+	if (cap_set_flag (caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) {
+		early_error ("error when manipulating capability sets");
+		goto drop;
+	}
+
+	if (cap_set_proc (caps) == -1) {
+		/* Only warn when it's root that's running */
+		if (getuid () == 0)
+			early_error ("cannot apply capabilities to process");
+		goto drop;
+	}
+
+	if (cap_free (caps) == -1) {
+		early_error ("failed to free capability structure");
+		goto drop;
+	}
+drop:
+
+#endif
+	/* Now finally drop the suid by becoming the invoking user */
+	if (geteuid () != getuid() || getegid () != getgid ())
+		drop_privileges ();
+}
diff --git a/daemon/gkd-capability.h b/daemon/gkd-capability.h
new file mode 100644
index 0000000..bb48a77
--- /dev/null
+++ b/daemon/gkd-capability.h
@@ -0,0 +1,27 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Yaron Sheffer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef GKD_CAPABILITY_H_
+#define GKD_CAPABILITY_H_
+
+void gkd_capability_obtain_capability_and_drop_privileges (void);
+
+#endif /* GKD_CAPABILITY_H_ */
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index f702890..97e1b7e 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -25,6 +25,7 @@
 
 #include "gkd-glue.h"
 #include "gkd-main.h"
+#include "gkd-capability.h"
 #include "gkd-pkcs11.h"
 #include "gkd-util.h"
 
@@ -778,6 +779,12 @@ main (int argc, char *argv[])
 	 * predictable startup.
 	 */
 
+	/*
+	 * Before we do ANYTHING, we drop privileges so we don't become
+	 * a security issue ourselves.
+	 */
+	gkd_capability_obtain_capability_and_drop_privileges ();
+
 #ifdef WITH_TESTS
 	g_setenv ("DBUS_FATAL_WARNINGS", "1", FALSE);
 	if (!g_getenv ("G_DEBUG"))



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]