Re: Capabilities module

From: Stephen Smalley (sdsat_private)
Date: Tue Jun 19 2001 - 13:48:05 PDT

  • Next message: jmjonesat_private: "Re: Bitkeeper (was: New LSM patch for consideration)"

    Here is a small patch relative to my previous capabilities
    patch that moves the capability-specific hacks from 
    the set*uid calls to a new post_setuid hook.
    
    --
    Stephen D. Smalley, NAI Labs
    ssmalleyat_private
    
    
    
    
    Index: include/linux/security.h
    ===================================================================
    RCS file: /cvs/lsm/lsm-new/include/linux/security.h,v
    retrieving revision 1.12
    retrieving revision 1.13
    diff -u -r1.12 -r1.13
    --- include/linux/security.h	2001/06/19 20:31:46	1.12
    +++ include/linux/security.h	2001/06/19 20:37:17	1.13
    @@ -108,6 +108,7 @@
     #define LSM_SETID_RES 4 /* setresuid or setresgid, id0 == real, id1 == eff, uid2 == saved */
     #define LSM_SETID_FS  8 /* setfsuid or setfsgid, id0 == fsuid or fsgid */
     	int (* setuid)			(uid_t id0, uid_t id1, uid_t id2, int flags);
    +	int (* post_setuid)		(uid_t old_ruid /* or fsuid */, uid_t old_euid, uid_t old_suid, int flags);
     	int (* setgid)			(gid_t id0, gid_t id1, gid_t id2, int flags);
     	int (* setgroups)               (int gidsetsize, gid_t *grouplist);
     	int (* setnice)			(struct task_struct *p, int nice);
    Index: kernel/capability_plug.c
    ===================================================================
    RCS file: /cvs/lsm/lsm-new/kernel/capability_plug.c,v
    retrieving revision 1.2
    retrieving revision 1.3
    diff -u -r1.2 -r1.3
    --- kernel/capability_plug.c	2001/06/19 20:35:03	1.2
    +++ kernel/capability_plug.c	2001/06/19 20:37:17	1.3
    @@ -189,6 +189,94 @@
     static int cap_task_alloc_security	(struct task_struct *p)	{return 0;}
     static void cap_task_free_security	(struct task_struct *p)	{return;}
     static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; }
    +
    +/* Copied from kernel/sys.c. */
    +/* 
    + * cap_emulate_setxuid() fixes the effective / permitted capabilities of
    + * a process after a call to setuid, setreuid, or setresuid.
    + *
    + *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
    + *  {r,e,s}uid != 0, the permitted and effective capabilities are
    + *  cleared.
    + *
    + *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
    + *  capabilities of the process are cleared.
    + *
    + *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
    + *  capabilities are set to the permitted capabilities.
    + *
    + *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
    + *  never happen.
    + *
    + *  -astor 
    + *
    + * cevans - New behaviour, Oct '99
    + * A process may, via prctl(), elect to keep its capabilities when it
    + * calls setuid() and switches away from uid==0. Both permitted and
    + * effective sets will be retained.
    + * Without this change, it was impossible for a daemon to drop only some
    + * of its privilege. The call to setuid(!=0) would drop all privileges!
    + * Keeping uid 0 is not an option because uid 0 owns too many vital
    + * files..
    + * Thanks to Olaf Kirch and Peter Benie for spotting this.
    + */
    +extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
    +				       int old_suid)
    +{
    +	if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
    +	    (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
    +	    !current->keep_capabilities) {
    +		cap_clear(current->cap_permitted);
    +		cap_clear(current->cap_effective);
    +	}
    +	if (old_euid == 0 && current->euid != 0) {
    +		cap_clear(current->cap_effective);
    +	}
    +	if (old_euid != 0 && current->euid == 0) {
    +		current->cap_effective = current->cap_permitted;
    +	}
    +}
    +
    +static int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags) 
    +{
    +	switch (flags) {
    +	case LSM_SETID_RE:
    +	case LSM_SETID_ID:
    +	case LSM_SETID_RES:
    +		/* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
    +		if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    +			cap_emulate_setxuid(old_ruid, old_euid, old_suid);
    +		}
    +		break;
    +	case LSM_SETID_FS: 
    +	{
    +		uid_t old_fsuid = old_ruid;
    +
    +		/* Copied from kernel/sys.c:setfsuid. */
    +
    +		/*
    +		 * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
    +		 *          if not, we might be a bit too harsh here.
    +		 */
    +
    +		if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    +			if (old_fsuid == 0 && current->fsuid != 0) {
    +				cap_t(current->cap_effective) &= ~CAP_FS_MASK;
    +			}
    +			if (old_fsuid != 0 && current->fsuid == 0) {
    +				cap_t(current->cap_effective) |=
    +					(cap_t(current->cap_permitted) & CAP_FS_MASK);
    +			}
    +		}
    +		break;
    +	}
    +	default:
    +		return -EINVAL;
    +	}
    +	
    +	return 0;
    +}
    +
     static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) { return 0; }
     static int cap_task_setgroups(int gidsetsize, gid_t *grouplist) { return 0; }
     static int cap_task_setnice(struct task_struct *p, int nice) { return 0; }
    @@ -298,6 +386,7 @@
     	alloc_security:	cap_task_alloc_security,
     	free_security:	cap_task_free_security,
     	setuid:		cap_task_setuid,
    +	post_setuid:	cap_task_post_setuid,
     	setgid:		cap_task_setgid,
     	setgroups:	cap_task_setgroups,
     	setnice:	cap_task_setnice,
    Index: kernel/security.c
    ===================================================================
    RCS file: /cvs/lsm/lsm-new/kernel/security.c,v
    retrieving revision 1.12
    retrieving revision 1.13
    diff -u -r1.12 -r1.13
    --- kernel/security.c	2001/06/19 20:31:46	1.12
    +++ kernel/security.c	2001/06/19 20:37:17	1.13
    @@ -117,6 +117,7 @@
     static int dummy_task_alloc_security	(struct task_struct *p)	{return 0;}
     static void dummy_task_free_security	(struct task_struct *p)	{return;}
     static int dummy_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; }
    +static int dummy_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; }
     static int dummy_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) { return 0; }
     static int dummy_task_setgroups(int gidsetsize, gid_t *grouplist) { return 0; }
     static int dummy_task_setnice(struct task_struct *p, int nice) { return 0; }
    @@ -221,6 +222,7 @@
     	alloc_security:	dummy_task_alloc_security,
     	free_security:	dummy_task_free_security,
     	setuid:		dummy_task_setuid,
    +	post_setuid:	dummy_task_post_setuid,
     	setgid:		dummy_task_setgid,
     	setgroups:	dummy_task_setgroups,
     	setnice:	dummy_task_setnice,
    Index: kernel/sys.c
    ===================================================================
    RCS file: /cvs/lsm/lsm-new/kernel/sys.c,v
    retrieving revision 1.4
    retrieving revision 1.5
    diff -u -r1.4 -r1.5
    --- kernel/sys.c	2001/06/18 17:22:05	1.4
    +++ kernel/sys.c	2001/06/19 20:37:17	1.5
    @@ -466,52 +466,6 @@
     	return 0;
     }
       
    -/* 
    - * cap_emulate_setxuid() fixes the effective / permitted capabilities of
    - * a process after a call to setuid, setreuid, or setresuid.
    - *
    - *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
    - *  {r,e,s}uid != 0, the permitted and effective capabilities are
    - *  cleared.
    - *
    - *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
    - *  capabilities of the process are cleared.
    - *
    - *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
    - *  capabilities are set to the permitted capabilities.
    - *
    - *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
    - *  never happen.
    - *
    - *  -astor 
    - *
    - * cevans - New behaviour, Oct '99
    - * A process may, via prctl(), elect to keep its capabilities when it
    - * calls setuid() and switches away from uid==0. Both permitted and
    - * effective sets will be retained.
    - * Without this change, it was impossible for a daemon to drop only some
    - * of its privilege. The call to setuid(!=0) would drop all privileges!
    - * Keeping uid 0 is not an option because uid 0 owns too many vital
    - * files..
    - * Thanks to Olaf Kirch and Peter Benie for spotting this.
    - */
    -extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
    -				       int old_suid)
    -{
    -	if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
    -	    (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
    -	    !current->keep_capabilities) {
    -		cap_clear(current->cap_permitted);
    -		cap_clear(current->cap_effective);
    -	}
    -	if (old_euid == 0 && current->euid != 0) {
    -		cap_clear(current->cap_effective);
    -	}
    -	if (old_euid != 0 && current->euid == 0) {
    -		current->cap_effective = current->cap_permitted;
    -	}
    -}
    -
     static int set_user(uid_t new_ruid, int dumpclear)
     {
     	struct user_struct *new_user, *old_user;
    @@ -597,12 +551,8 @@
     	    (euid != (uid_t) -1 && euid != old_ruid))
     		current->suid = current->euid;
     	current->fsuid = current->euid;
    -
    -	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    -		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
    -	}
     
    -	return 0;
    +	return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
     }
     
     
    @@ -646,12 +596,8 @@
     	}
     	current->fsuid = current->euid = uid;
     	current->suid = new_suid;
    -
    -	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    -		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
    -	}
     
    -	return 0;
    +	return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
     }
     
     
    @@ -697,11 +643,7 @@
     	if (suid != (uid_t) -1)
     		current->suid = suid;
     
    -	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    -		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
    -	}
    -
    -	return 0;
    +	return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
     }
     
     asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
    @@ -793,24 +735,9 @@
     		current->fsuid = uid;
     	}
     
    -	/* We emulate fsuid by essentially doing a scaled-down version
    -	 * of what we did in setresuid and friends. However, we only
    -	 * operate on the fs-specific bits of the process' effective
    -	 * capabilities 
    -	 *
    -	 * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
    -	 *          if not, we might be a bit too harsh here.
    -	 */
    -	
    -	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
    -		if (old_fsuid == 0 && current->fsuid != 0) {
    -			cap_t(current->cap_effective) &= ~CAP_FS_MASK;
    -		}
    -		if (old_fsuid != 0 && current->fsuid == 0) {
    -			cap_t(current->cap_effective) |=
    -				(cap_t(current->cap_permitted) & CAP_FS_MASK);
    -		}
    -	}
    +	retval = security_ops->task_ops->post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
    +	if (retval)
    +		return retval;
     
     	return old_fsuid;
     }
    
    _______________________________________________
    linux-security-module mailing list
    linux-security-moduleat_private
    http://mail.wirex.com/mailman/listinfo/linux-security-module
    



    This archive was generated by hypermail 2b30 : Tue Jun 19 2001 - 13:50:26 PDT