public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] p9auth: split core function out of some set*{u,g}id functions
@ 2010-04-21  1:27 Serge E. Hallyn
  2010-04-21  1:28 ` [PATCH 2/3] p9auth: add CAP_GRANT_ID to authorize use of /dev/caphash Serge E. Hallyn
                   ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Serge E. Hallyn @ 2010-04-21  1:27 UTC (permalink / raw)
  To: lkml
  Cc: David Howells, Ashwin Ganti, Greg KH, rsc, ericvh,
	linux-security-module, Ron Minnich, jt.beard, Andrew Morton,
	Andrew Morgan, oleg, Eric Paris, Eric W. Biederman

Break the core functionality of set{fs,res}{u,g}id into cred_setX
which performs the access checks based on current_cred(), but performs
the requested change on a passed-in cred.

Export the helpers, since p9auth can be compiled as a module.  It
might be worth not allowing modular p9auth to avoid having to export
them.

Really the setfs{u,g}id helper isn't needed, but move it as
well to keep the code consistent.

This patch also changes set_user() to use new->user->user_ns.  While
technically not needed as all callers should have new->user->user_ns
equal to current_userns(), it is more correct and may prevent surprises
in the future.

Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
---
 include/linux/cred.h |   12 +++++
 kernel/cred.c        |  119 +++++++++++++++++++++++++++++++++++++++++++++
 kernel/sys.c         |  131 ++++++++------------------------------------------
 3 files changed, 151 insertions(+), 111 deletions(-)

diff --git a/include/linux/cred.h b/include/linux/cred.h
index 52507c3..0ce7a50 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -22,6 +22,9 @@ struct user_struct;
 struct cred;
 struct inode;
 
+/* defined in sys.c, used in cred_setresuid */
+extern int set_user(struct cred *new);
+
 /*
  * COW Supplementary groups list
  */
@@ -396,4 +399,13 @@ do {						\
 	*(_fsgid) = __cred->fsgid;		\
 } while(0)
 
+#define CRED_SETID_NOFORCE 0
+#define CRED_SETID_FORCE 1
+int cred_setresuid(struct cred *new, uid_t ruid, uid_t euid, uid_t suid,
+		   int force);
+int cred_setresgid(struct cred *new, gid_t rgid, gid_t egid, gid_t sgid,
+		   int force);
+int cred_setfsuid(struct cred *new, uid_t uid, uid_t *old_fsuid);
+int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid);
+
 #endif /* _LINUX_CRED_H */
diff --git a/kernel/cred.c b/kernel/cred.c
index e1dbe9e..4fc3284 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -785,6 +785,125 @@ int set_create_files_as(struct cred *new, struct inode *inode)
 }
 EXPORT_SYMBOL(set_create_files_as);
 
+int cred_setresuid(struct cred *new, uid_t ruid, uid_t euid, uid_t suid,
+		   int force)
+{
+	int retval;
+	const struct cred *old;
+
+	retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
+	if (retval)
+		return retval;
+	old = current_cred();
+
+	if (!force && !capable(CAP_SETUID)) {
+		if (ruid != (uid_t) -1 && ruid != old->uid &&
+		    ruid != old->euid  && ruid != old->suid)
+			return -EPERM;
+		if (euid != (uid_t) -1 && euid != old->uid &&
+		    euid != old->euid  && euid != old->suid)
+			return -EPERM;
+		if (suid != (uid_t) -1 && suid != old->uid &&
+		    suid != old->euid  && suid != old->suid)
+			return -EPERM;
+	}
+
+	if (ruid != (uid_t) -1) {
+		new->uid = ruid;
+		if (ruid != old->uid) {
+			retval = set_user(new);
+			if (retval < 0)
+				return retval;
+		}
+	}
+	if (euid != (uid_t) -1)
+		new->euid = euid;
+	if (suid != (uid_t) -1)
+		new->suid = suid;
+	new->fsuid = new->euid;
+
+	return security_task_fix_setuid(new, old, LSM_SETID_RES);
+}
+EXPORT_SYMBOL_GPL(cred_setresuid);
+
+int cred_setresgid(struct cred *new, gid_t rgid, gid_t egid, gid_t sgid,
+		   int force)
+{
+	const struct cred *old = current_cred();
+	int retval;
+
+	retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
+	if (retval)
+		return retval;
+
+	if (!force && !capable(CAP_SETGID)) {
+		if (rgid != (gid_t) -1 && rgid != old->gid &&
+		    rgid != old->egid  && rgid != old->sgid)
+			return -EPERM;
+		if (egid != (gid_t) -1 && egid != old->gid &&
+		    egid != old->egid  && egid != old->sgid)
+			return -EPERM;
+		if (sgid != (gid_t) -1 && sgid != old->gid &&
+		    sgid != old->egid  && sgid != old->sgid)
+			return -EPERM;
+	}
+
+	if (rgid != (gid_t) -1)
+		new->gid = rgid;
+	if (egid != (gid_t) -1)
+		new->egid = egid;
+	if (sgid != (gid_t) -1)
+		new->sgid = sgid;
+	new->fsgid = new->egid;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cred_setresgid);
+
+int cred_setfsuid(struct cred *new, uid_t uid, uid_t *old_fsuid)
+{
+	const struct cred *old;
+
+	old = current_cred();
+	*old_fsuid = old->fsuid;
+
+	if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
+		return -EPERM;
+
+	if (uid == old->uid  || uid == old->euid  ||
+	    uid == old->suid || uid == old->fsuid ||
+	    capable(CAP_SETUID)) {
+		if (uid != *old_fsuid) {
+			new->fsuid = uid;
+			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
+				return 0;
+		}
+	}
+	return -EPERM;
+}
+EXPORT_SYMBOL_GPL(cred_setfsuid);
+
+int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid)
+{
+	const struct cred *old;
+
+	old = current_cred();
+	*old_fsgid = old->fsgid;
+
+	if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
+		return -EPERM;
+
+	if (gid == old->gid  || gid == old->egid  ||
+	    gid == old->sgid || gid == old->fsgid ||
+	    capable(CAP_SETGID)) {
+		if (gid != *old_fsgid) {
+			new->fsgid = gid;
+			return 0;
+		}
+	}
+	return -EPERM;
+}
+EXPORT_SYMBOL_GPL(cred_setfsgid);
+
 #ifdef CONFIG_DEBUG_CREDENTIALS
 
 bool creds_are_invalid(const struct cred *cred)
diff --git a/kernel/sys.c b/kernel/sys.c
index 6d1a7e0..78f32eb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -565,11 +565,11 @@ error:
 /*
  * change the user struct in a credentials set to match the new UID
  */
-static int set_user(struct cred *new)
+int set_user(struct cred *new)
 {
 	struct user_struct *new_user;
 
-	new_user = alloc_uid(current_user_ns(), new->uid);
+	new_user = alloc_uid(new->user->user_ns, new->uid);
 	if (!new_user)
 		return -EAGAIN;
 
@@ -711,7 +711,6 @@ error:
  */
 SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 {
-	const struct cred *old;
 	struct cred *new;
 	int retval;
 
@@ -719,45 +718,10 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 	if (!new)
 		return -ENOMEM;
 
-	retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
-	if (retval)
-		goto error;
-	old = current_cred();
+	retval = cred_setresuid(new, ruid, euid, suid, CRED_SETID_NOFORCE);
+	if (retval == 0)
+		return commit_creds(new);
 
-	retval = -EPERM;
-	if (!capable(CAP_SETUID)) {
-		if (ruid != (uid_t) -1 && ruid != old->uid &&
-		    ruid != old->euid  && ruid != old->suid)
-			goto error;
-		if (euid != (uid_t) -1 && euid != old->uid &&
-		    euid != old->euid  && euid != old->suid)
-			goto error;
-		if (suid != (uid_t) -1 && suid != old->uid &&
-		    suid != old->euid  && suid != old->suid)
-			goto error;
-	}
-
-	if (ruid != (uid_t) -1) {
-		new->uid = ruid;
-		if (ruid != old->uid) {
-			retval = set_user(new);
-			if (retval < 0)
-				goto error;
-		}
-	}
-	if (euid != (uid_t) -1)
-		new->euid = euid;
-	if (suid != (uid_t) -1)
-		new->suid = suid;
-	new->fsuid = new->euid;
-
-	retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
-	if (retval < 0)
-		goto error;
-
-	return commit_creds(new);
-
-error:
 	abort_creds(new);
 	return retval;
 }
@@ -779,43 +743,17 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u
  */
 SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 {
-	const struct cred *old;
 	struct cred *new;
 	int retval;
 
 	new = prepare_creds();
 	if (!new)
 		return -ENOMEM;
-	old = current_cred();
 
-	retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
-	if (retval)
-		goto error;
+	retval = cred_setresgid(new, rgid, egid, sgid, CRED_SETID_NOFORCE);
+	if (retval == 0)
+		return commit_creds(new);
 
-	retval = -EPERM;
-	if (!capable(CAP_SETGID)) {
-		if (rgid != (gid_t) -1 && rgid != old->gid &&
-		    rgid != old->egid  && rgid != old->sgid)
-			goto error;
-		if (egid != (gid_t) -1 && egid != old->gid &&
-		    egid != old->egid  && egid != old->sgid)
-			goto error;
-		if (sgid != (gid_t) -1 && sgid != old->gid &&
-		    sgid != old->egid  && sgid != old->sgid)
-			goto error;
-	}
-
-	if (rgid != (gid_t) -1)
-		new->gid = rgid;
-	if (egid != (gid_t) -1)
-		new->egid = egid;
-	if (sgid != (gid_t) -1)
-		new->sgid = sgid;
-	new->fsgid = new->egid;
-
-	return commit_creds(new);
-
-error:
 	abort_creds(new);
 	return retval;
 }
@@ -841,35 +779,20 @@ SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __u
  */
 SYSCALL_DEFINE1(setfsuid, uid_t, uid)
 {
-	const struct cred *old;
 	struct cred *new;
 	uid_t old_fsuid;
+	int retval;
 
 	new = prepare_creds();
 	if (!new)
 		return current_fsuid();
-	old = current_cred();
-	old_fsuid = old->fsuid;
-
-	if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
-		goto error;
-
-	if (uid == old->uid  || uid == old->euid  ||
-	    uid == old->suid || uid == old->fsuid ||
-	    capable(CAP_SETUID)) {
-		if (uid != old_fsuid) {
-			new->fsuid = uid;
-			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
-				goto change_okay;
-		}
-	}
 
-error:
-	abort_creds(new);
-	return old_fsuid;
+	retval = cred_setfsuid(new, uid, &old_fsuid);
+	if (retval == 0)
+		commit_creds(new);
+	else
+		abort_creds(new);
 
-change_okay:
-	commit_creds(new);
 	return old_fsuid;
 }
 
@@ -878,34 +801,20 @@ change_okay:
  */
 SYSCALL_DEFINE1(setfsgid, gid_t, gid)
 {
-	const struct cred *old;
 	struct cred *new;
 	gid_t old_fsgid;
+	int retval;
 
 	new = prepare_creds();
 	if (!new)
 		return current_fsgid();
-	old = current_cred();
-	old_fsgid = old->fsgid;
-
-	if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
-		goto error;
-
-	if (gid == old->gid  || gid == old->egid  ||
-	    gid == old->sgid || gid == old->fsgid ||
-	    capable(CAP_SETGID)) {
-		if (gid != old_fsgid) {
-			new->fsgid = gid;
-			goto change_okay;
-		}
-	}
 
-error:
-	abort_creds(new);
-	return old_fsgid;
+	retval = cred_setfsgid(new, gid, &old_fsgid);
+	if (retval == 0)
+		commit_creds(new);
+	else
+		abort_creds(new);
 
-change_okay:
-	commit_creds(new);
 	return old_fsgid;
 }
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 31+ messages in thread
* [PATCH 0/3] p9auth fs: introduction
@ 2010-04-27 16:41 Serge E. Hallyn
  2010-04-27 16:42 ` [PATCH 1/3] p9auth: split core function out of some set*{u,g}id functions Serge E. Hallyn
  0 siblings, 1 reply; 31+ messages in thread
From: Serge E. Hallyn @ 2010-04-27 16:41 UTC (permalink / raw)
  To: lkml
  Cc: Ashwin Ganti, David Howells, Greg KH, rsc, ericvh,
	linux-security-module, Ron Minnich, jt.beard, Andrew Morgan,
	Andrew Morton, Oleg Nesterov, Eric Paris, Eric W. Biederman,
	Randy Dunlap, Michael Kerrisk, Alan Cox, Kyle Moffett,
	Steve Grubb

Hi,

Here is an updated version of the p9auth setuid capability
module, which hopefully addresses all previous feedback.  It
is now a separate filesystem instead of a device, as per Eric's
suggestion.

During the last round, Alan Cox made a great suggestion of sending
credentials over AF_UNIX sock allowing the recipient to 'become me.'
I think that's still an interesting idea, and intend to pursue it
as Eric pushes the patches to translate userids across user
namespaces.

The tradeoffs are worth discussing.  On the one
hand, p9auth requires a scary CAP_GRANT_ID capability, while a
SO_PASSAUTH would be more akin to an extension of CAP_SETUID.
Also, SO_PASSAUTH would be usable by any unprivileged app, while
one would hope there would be only one p9auth service for the whole
system.  On the other hand, the p9auth API appears to be pretty
well settled and understood, and only provides for a very simple
setting of all uids and all gids to one value, plus some auxiliary
groups, which is perfect for use by simple login servers.

p9auth and SO_PASSAUTH don't appear to be mutually exclusive.  I don't
know how painful it would be for plan-9 folks to make use of the
SO_PASSAUTH feature.  (It should definately be possible)  But in any
case here is the next iteration of p9auth fs for discussion and
consideration.

thanks,
-serge

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2010-05-04 14:53 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-21  1:27 [PATCH 1/3] p9auth: split core function out of some set*{u,g}id functions Serge E. Hallyn
2010-04-21  1:28 ` [PATCH 2/3] p9auth: add CAP_GRANT_ID to authorize use of /dev/caphash Serge E. Hallyn
2010-04-21  2:54   ` Greg KH
2010-04-21  1:29 ` [PATCH 3/3] p9auth: add p9auth driver Serge E. Hallyn
2010-04-21  3:04   ` Greg KH
2010-04-21  3:45     ` Serge E. Hallyn
2010-04-21  4:18       ` Ashwin Ganti
2010-04-21 13:47         ` Serge E. Hallyn
2010-04-21 14:44           ` Ashwin Ganti
2010-04-21  4:45       ` Eric W. Biederman
2010-04-21 13:21         ` Serge E. Hallyn
2010-04-24  3:36         ` Serge E. Hallyn
2010-04-24 16:25           ` ron minnich
2010-04-24 18:01             ` Eric W. Biederman
2010-04-25  3:24               ` Serge E. Hallyn
2010-04-21  9:27   ` Alan Cox
2010-04-21 13:39     ` Serge E. Hallyn
2010-04-21 14:19       ` Alan Cox
2010-04-21 15:09         ` Serge E. Hallyn
2010-04-21 19:15           ` Eric W. Biederman
2010-04-21 20:23             ` Serge E. Hallyn
2010-04-22  4:57             ` Kyle Moffett
2010-04-22 14:36               ` Serge E. Hallyn
2010-04-21 13:55     ` Eric Paris
2010-04-21 14:30       ` Serge E. Hallyn
2010-04-21 10:49   ` David Howells
2010-04-21 13:40     ` Serge E. Hallyn
2010-04-21 10:46 ` [PATCH 1/3] p9auth: split core function out of some set*{u,g}id functions David Howells
2010-04-21 13:40   ` Serge E. Hallyn
  -- strict thread matches above, loose matches on Subject: below --
2010-04-27 16:41 [PATCH 0/3] p9auth fs: introduction Serge E. Hallyn
2010-04-27 16:42 ` [PATCH 1/3] p9auth: split core function out of some set*{u,g}id functions Serge E. Hallyn
2010-05-04 14:52   ` David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox