[nfs-utils/private-jlayton-gssd-1] gssd: make it fork and switch creds before acquiring GSSAPI creds

Jeff Layton jlayton at fedoraproject.org
Tue Oct 15 00:34:11 UTC 2013


commit ffb034487896382266514ef364c8eba4722486ee
Author: Jeff Layton <jlayton at redhat.com>
Date:   Mon Oct 14 20:27:31 2013 -0400

    gssd: make it fork and switch creds before acquiring GSSAPI creds
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

 nfs-utils-1.2.9-gssd-switch-creds.patch |  166 +++++++++++++++++++++++++++++++
 nfs-utils.spec                          |    9 ++-
 2 files changed, 174 insertions(+), 1 deletions(-)
---
diff --git a/nfs-utils-1.2.9-gssd-switch-creds.patch b/nfs-utils-1.2.9-gssd-switch-creds.patch
new file mode 100644
index 0000000..264faaf
--- /dev/null
+++ b/nfs-utils-1.2.9-gssd-switch-creds.patch
@@ -0,0 +1,166 @@
+diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
+index e58c341..b48d163 100644
+--- a/utils/gssd/gssd_proc.c
++++ b/utils/gssd/gssd_proc.c
+@@ -67,6 +67,8 @@
+ #include <errno.h>
+ #include <gssapi/gssapi.h>
+ #include <netdb.h>
++#include <sys/types.h>
++#include <sys/wait.h>
+ 
+ #include "gssd.h"
+ #include "err_util.h"
+@@ -832,7 +834,6 @@ create_auth_rpc_client(struct clnt_info *clp,
+ 	CLIENT			*rpc_clnt = NULL;
+ 	struct rpc_gss_sec	sec;
+ 	AUTH			*auth = NULL;
+-	uid_t			save_uid = -1;
+ 	int			retval = -1;
+ 	OM_uint32		min_stat;
+ 	char			rpc_errmsg[1024];
+@@ -841,16 +842,6 @@ create_auth_rpc_client(struct clnt_info *clp,
+ 	struct sockaddr		*addr = (struct sockaddr *) &clp->addr;
+ 	socklen_t		salen;
+ 
+-	/* Create the context as the user (not as root) */
+-	save_uid = geteuid();
+-	if (setfsuid(uid) != 0) {
+-		printerr(0, "WARNING: Failed to setfsuid for "
+-			    "user with uid %d\n", uid);
+-		goto out_fail;
+-	}
+-	printerr(2, "creating context using fsuid %d (save_uid %d)\n",
+-			uid, save_uid);
+-
+ 	sec.qop = GSS_C_QOP_DEFAULT;
+ 	sec.svc = RPCSEC_GSS_SVC_NONE;
+ 	sec.cred = cred;
+@@ -949,11 +940,6 @@ create_auth_rpc_client(struct clnt_info *clp,
+   out:
+ 	if (sec.cred != GSS_C_NO_CREDENTIAL)
+ 		gss_release_cred(&min_stat, &sec.cred);
+-	/* Restore euid to original value */
+-	if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
+-		printerr(0, "WARNING: Failed to restore fsuid"
+-			    " to uid %d from %d\n", save_uid, uid);
+-	}
+ 	return retval;
+ 
+   out_fail:
+@@ -964,6 +950,64 @@ create_auth_rpc_client(struct clnt_info *clp,
+ }
+ 
+ /*
++ * Create the context as the user (not as root).
++ *
++ * Note that we change the *real* uid here, as changing the effective uid is
++ * not sufficient. This is due to an unfortunate historical error in the MIT
++ * krb5 libs, where they used %{uid} in the default_ccache_name. Changing that
++ * now might break some applications so we're sort of stuck with it.
++ *
++ * Unfortunately, doing this leaves the forked child vulnerable to signals and
++ * renicing, but this is the best we can do. In the event that a child is
++ * signalled before downcalling, the kernel will just eventually time out the
++ * upcall attempt.
++ */
++static int
++change_identity(uid_t uid)
++{
++	struct passwd	*pw;
++
++	/* drop list of supplimentary groups first */
++	if (setgroups(0, NULL) != 0) {
++		printerr(0, "WARNING: unable to drop supplimentary groups!");
++		return errno;
++	}
++
++	/* try to get pwent for user */
++	pw = getpwuid(uid);
++	if (!pw) {
++		/* if that doesn't work, try to get one for "nobody" */
++		errno = 0;
++		pw = getpwnam("nobody");
++		if (!pw) {
++			printerr(0, "WARNING: unable to determine gid for uid %u\n", uid);
++			return errno ? errno : ENOENT;
++		}
++	}
++
++	/*
++	 * Switch the GIDs. Note that we leave the saved-set-gid alone in an
++	 * attempt to prevent attacks via ptrace()
++	 */
++	if (setresgid(pw->pw_gid, pw->pw_gid, -1) != 0) {
++		printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid);
++		return errno;
++	}
++
++	/*
++	 * Switch UIDs, but leave saved-set-uid alone to prevent ptrace() by
++	 * other processes running with this uid.
++	 */
++	if (setresuid(uid, uid, -1) != 0) {
++		printerr(0, "WARNING: Failed to setuid for user with uid %u\n",
++				uid);
++		return errno;
++	}
++
++	return 0;
++}
++
++/*
+  * this code uses the userland rpcsec gss library to create a krb5
+  * context on behalf of the kernel
+  */
+@@ -982,6 +1026,26 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+ 	int			err, downcall_err = -EACCES;
+ 	gss_cred_id_t		gss_cred;
+ 	OM_uint32		maj_stat, min_stat, lifetime_rec;
++	pid_t			pid;
++
++	pid = fork();
++	switch(pid) {
++	case 0:
++		/* Child: fall through to rest of function */
++		break;
++	case -1:
++		/* fork() failed! */
++		printerr(0, "WARNING: unable to fork() to handle upcall: %s\n",
++				strerror(errno));
++		return;
++	default:
++		/* Parent: just wait on child to exit and return */
++		wait(&err);
++		if (WIFSIGNALED(err))
++			printerr(0, "WARNING: forked child was killed with signal %d\n",
++					WTERMSIG(err));
++		return;
++	}
+ 
+ 	printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
+ 
+@@ -1014,6 +1078,14 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+ 		 service ? service : "<null>");
+ 	if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
+ 				service == NULL)) {
++
++		err = change_identity(uid);
++		if (err) {
++			printerr(0, "WARNING: failed to change identity: %s",
++				 strerror(err));
++			goto out_return_error;
++		}
++
+ 		/* Tell krb5 gss which credentials cache to use */
+ 		/* Try first to acquire credentials directly via GSSAPI */
+ 		err = gssd_acquire_user_cred(uid, &gss_cred);
+@@ -1121,7 +1193,7 @@ out:
+ 		AUTH_DESTROY(auth);
+ 	if (rpc_clnt)
+ 		clnt_destroy(rpc_clnt);
+-	return;
++	exit(0);
+ 
+ out_return_error:
+ 	do_error_downcall(fd, uid, downcall_err);
diff --git a/nfs-utils.spec b/nfs-utils.spec
index 9fae510..077c58b 100644
--- a/nfs-utils.spec
+++ b/nfs-utils.spec
@@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser
 Name: nfs-utils
 URL: http://sourceforge.net/projects/nfs
 Version: 1.2.8
-Release: 6.0%{?dist}
+Release: 6.0.gssd.1%{?dist}
 Epoch: 1
 
 # group all 32bit related archs
@@ -43,6 +43,8 @@ Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch
 Patch102: nfs-utils-1.2.3-sm-notify-res_init.patch
 Patch103: nfs-utils-1.2.5-idmap-errmsg.patch
 
+Patch201: nfs-utils-1.2.9-gssd-switch-creds.patch
+
 Group: System Environment/Daemons
 Provides: exportfs    = %{epoch}:%{version}-%{release}
 Provides: nfsstat     = %{epoch}:%{version}-%{release}
@@ -100,6 +102,8 @@ This package also contains the mount.nfs and umount.nfs program.
 %patch102 -p1
 %patch103 -p1
 
+%patch201 -p1
+
 # Remove .orig files
 find . -name "*.orig" | xargs rm -f
 
@@ -312,6 +316,9 @@ fi
 /sbin/umount.nfs4
 
 %changelog
+* Mon Oct 14 2013 Steve Dickson <steved at redhat.com> 1.2.8-6.0.gssd.1
+- make gssd fork and switch creds before acquiring GSSAPI creds
+
 * Tue Sep 24 2013 Steve Dickson <steved at redhat.com> 1.2.8-6.0
 - Updated to latest upstream RC release: nfs-utils-1-2-9-rc6
 


More information about the scm-commits mailing list