[gnome-keyring] Use file system based capabilities as a way of getting ipc-lock



commit 66bd5dd32836a770647b8acf3476fb7922be71eb
Author: Steve Grubb <sgrubb redhat com>
Date:   Thu Mar 10 17:01:35 2011 +0100

    Use file system based capabilities as a way of getting ipc-lock
    
    https://bugzilla.redhat.com/show_bug.cgi?id=668831

 configure.in            |   16 +++---
 daemon/gkd-capability.c |  112 +++++++++++++++-------------------------------
 2 files changed, 45 insertions(+), 83 deletions(-)
---
diff --git a/configure.in b/configure.in
index 8e03c7d..a5a434d 100644
--- a/configure.in
+++ b/configure.in
@@ -440,19 +440,19 @@ if test "$ASN1PARSER" = "no" ; then
 fi
 
 # -------------------------------------------------------------------
-# libcap2
+# libcap-ng
 #
 
-AC_CHECK_LIB([cap], [cap_get_proc], have_libcap="yes", have_libcap="no")
+AC_CHECK_LIB([cap-ng], [capng_clear], have_libcapng="yes", have_libcapng="no")
 
-if test $have_libcap = yes; then
-   AC_DEFINE(HAVE_LIBCAP, 1, [Have libcap2 package, libcap library])
-   DAEMON_LIBS="$DAEMON_LIBS -lcap"
+if test $have_libcapng = yes; then
+   AC_DEFINE(HAVE_LIBCAPNG, 1, [Have libcap-ng package, libcap-ng library])
+   DAEMON_LIBS="$DAEMON_LIBS -lcap-ng"
 else
-   AC_MSG_WARN([libcap2 (or development headers) is not installed])
+   AC_MSG_WARN([libcap-ng (or development headers) is not installed])
 fi
 
-libcap_status=$have_libcap
+libcapng_status=$have_libcapng
 
 # --------------------------------------------------------------------
 # Debug mode
@@ -741,7 +741,7 @@ ui/tests/Makefile
 echo
 echo "OPTIONAL DEPENDENCIES"
 echo "  PAM:                  $pam_status"
-echo "  Linux capabilities:   $libcap_status"
+echo "  Linux capabilities:   $libcapng_status"
 echo
 echo "CONFIGURATION"
 echo "  SSH Agent:            $ssh_status"
diff --git a/daemon/gkd-capability.c b/daemon/gkd-capability.c
index 4ca0db1..5b47f4e 100644
--- a/daemon/gkd-capability.c
+++ b/daemon/gkd-capability.c
@@ -1,7 +1,7 @@
 /* -*- 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
+ * Copyright (C) 2011 Steve Grubb
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -18,102 +18,64 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  *
- * Author: Yaron Sheffer <yaronf gmx com>
- * Author: Stef Walter <stef thewalter net>
+ * Author: Steve Grubb <sgrubb redhat com>
  */
 
 #include "config.h"
 
 #include "gkd-capability.h"
 
-#ifdef HAVE_LIBCAP
-#include <sys/capability.h>
+#ifdef HAVE_LIBCAPNG
+#include <cap-ng.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.
- */
+#ifdef HAVE_LIBCAPNG
 
-/*
- * No logging, no gettext
- */
+/* No logging, no gettext */
 static void
 early_error (const char *err_string)
 {
-	fprintf (stderr, "gnome-keyring-daemon: %s\n", err_string);
+	fprintf (stderr, "gnome-keyring-daemon: %s, aborting\n", err_string);
+	exit (1);
 }
 
-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);
-	}
-}
+#endif /* HAVE_LIPCAPNG */
 
 /*
- * 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!
+ * This program needs the CAP_IPC_LOCK posix capability.
+ * We want to allow either setuid root or file system based capabilies
+ * to work. If file system based capabilities, this is a no-op unless
+ * the root user is running the program. In that case we just drop
+ * capabilities down to IPC_LOCK. If we are setuid root, then change to the
+ * invoking user retaining just the IPC_LOCK capability. 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;
+#ifdef HAVE_LIBCAPNG
+	capng_get_caps_process ();
+	switch (capng_have_capabilities (CAPNG_SELECT_CAPS))
+	{
+		case CAPNG_FULL:
+			/* We are either setuid root or the root user */
+			capng_clear (CAPNG_SELECT_CAPS);
+			capng_update (CAPNG_ADD,
+					CAPNG_EFFECTIVE|CAPNG_PERMITTED,
+					CAP_IPC_LOCK);
+			if (capng_change_id (getuid (), getgid (), 0))
+				early_error ("failed dropping capabilities");
+			break;
+		case CAPNG_FAIL:
+		case CAPNG_NONE:
+			early_error ("error getting process capabilities");
+			break;
+		case CAPNG_PARTIAL: /* File system based capabilities */
+                        break;
 	}
-
-	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 ();
+#endif /* HAVE_LIBCAPNG */
 }



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