Re: [PATCH-v3] SELinux: introduce permissive types

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

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephen Smalley wrote:
> On Mon, 2008-03-10 at 18:35 -0400, Eric Paris wrote:
>> Introduce the concept of a permissive type.  A new ebitmap is introduced
>> to the policy database which indicates if a given type has the
>> permissive bit set or not.  This bit is tested for the scontext of any
>> denial.  The bit is meaningless on types which only appear as the target
>> of a decision and never the source.  A domain running with a permissive
>> type will be allowed to perform any action similarly to when the system
>> is globally set permissive.
>>
>> Signed-off-by: Eric Paris <eparis@xxxxxxxxxx>
>>
>> ---
>>
>> - Threw out all of the atomic stuff.  Either the sid is going to get
>> mapped to unlabeled or to the right context in the new policydb and will
>> be the new type number and all will be well.  As usual I was just making
>> things harder on myself.
> 
> Technically, the following could still happen:
> - policy has domain marked as permissive and does not allow an access,
> - the AVC determines that the access is denied and is following the
> permissive code path but has not yet taken the policy rdlock,
> - policy is reloaded with domain marked as non-permissive with access
> allowed,
> - security_permissive_sid is called and takes the policy rdlock,
> - the domain is found to be non-permissive,
> - the AVC denies the access.
> 
> Particularly if we do something like:
> - insert policy module that just makes a domain permissive,
> - run for a while collecting audit messages,
> - generate new policy module from audit messages,
> - replace the permissive policy module with the one that contains the
> allows.
> 
> Don't know if you are concerned about the above, but it could create
> mysterious breakage.

I think this is highly unlikely.  I believe the standard way to use
permissive domains, would be to ship a policy.  Once you have gone a
considerable amount of time without any AVC messages, you would reload
the policy with the permissive domain removed.  So I don't think this
race is likely to happen unless forced.
> 
>> - moved !requested into its own handling
> 
> Separate patch, put it first, and I think BUG_ON is cleaner there.
> 
>> - dropped unlikely() around the permissive sid, because really, if we
>> get a denial and we are selinux_enforcing its actually not all that
>> unlikely that we might not have a permissive domain.  Just let the
>> compiler do its thing.
> 
> Ok.
> 
>> - dropped the test for the existence of node.  avc_update_node might
>> return -ENOENT, but really who cares?  We are on a slow code path here
>> so it seems to be needless complexity.  Isn't this code nice and clear
>> now?  I can add it in, but its just a slight perf win and not much
>> else..
> 
> Seems fine - we will rarely not have a node (requires that there not
> already be a node for the key, and that the allocation of a new node
> fail), and it is harmless to proceed.
>>  security/selinux/Kconfig            |    2 +-
>>  security/selinux/avc.c              |   18 +++++++++++++-----
>>  security/selinux/include/security.h |    5 ++++-
>>  security/selinux/ss/policydb.c      |   11 +++++++++++
>>  security/selinux/ss/policydb.h      |    2 ++
>>  security/selinux/ss/services.c      |   21 +++++++++++++++++++++
>>  6 files changed, 52 insertions(+), 7 deletions(-)
>>
>> diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
>> index 2b517d6..a436d1c 100644
>> --- a/security/selinux/Kconfig
>> +++ b/security/selinux/Kconfig
>> @@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
>>  config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
>>  	int "NSA SELinux maximum supported policy format version value"
>>  	depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
>> -	range 15 22
>> +	range 15 23
>>  	default 19
>>  	help
>>  	  This option sets the value for the maximum policy format version
>> diff --git a/security/selinux/avc.c b/security/selinux/avc.c
>> index 187964e..8d78b88 100644
>> --- a/security/selinux/avc.c
>> +++ b/security/selinux/avc.c
>> @@ -890,13 +890,21 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
>>  
>>  	denied = requested & ~(p_ae->avd.allowed);
>>  
>> -	if (!requested || denied) {
>> -		if (selinux_enforcing || (flags & AVC_STRICT))
>> +	if (unlikely(!requested)) {
>> +		printk(KERN_ERR "%s: found !requested, fix me\n", __func__);
> 
> Likely want SELinux somewhere in that message for clarity.
> 
>> +		WARN_ON(1);
>> +		if (selinux_enforcing)
>>  			rc = -EACCES;
> 
> Simpler as a BUG_ON, and correct.
> 
>> +	}
>> +
>> +	if (denied) {
>> +		if (flags & AVC_STRICT)
>> +			rc = -EACCES;
>> +		else if (!selinux_enforcing || security_permissive_sid(ssid))
>> +			avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
>> +					tsid, tclass);
>>  		else
>> -			if (node)
>> -				avc_update_node(AVC_CALLBACK_GRANT,requested,
>> -						ssid,tsid,tclass);
>> +			rc = -EACCES;
>>  	}
>>  
>>  	rcu_read_unlock();
>> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
>> index f7d2f03..fde8690 100644
>> --- a/security/selinux/include/security.h
>> +++ b/security/selinux/include/security.h
>> @@ -26,13 +26,14 @@
>>  #define POLICYDB_VERSION_AVTAB		20
>>  #define POLICYDB_VERSION_RANGETRANS	21
>>  #define POLICYDB_VERSION_POLCAP		22
>> +#define POLICYDB_VERSION_PERMISSIVE	23
>>  
>>  /* Range of policy versions we understand*/
>>  #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
>>  #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
>>  #define POLICYDB_VERSION_MAX	CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
>>  #else
>> -#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_POLCAP
>> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
>>  #endif
>>  
>>  #define CONTEXT_MNT	0x01
>> @@ -67,6 +68,8 @@ struct av_decision {
>>  	u32 seqno;
>>  };
>>  
>> +int security_permissive_sid(u32 sid);
>> +
>>  int security_compute_av(u32 ssid, u32 tsid,
>>  	u16 tclass, u32 requested,
>>  	struct av_decision *avd);
>> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
>> index bd7d6a0..84dbab9 100644
>> --- a/security/selinux/ss/policydb.c
>> +++ b/security/selinux/ss/policydb.c
>> @@ -111,6 +111,11 @@ static struct policydb_compat_info policydb_compat[] = {
>>  		.version	= POLICYDB_VERSION_POLCAP,
>>  		.sym_num	= SYM_NUM,
>>  		.ocon_num	= OCON_NUM,
>> +	},
>> +	{
>> +		.version	= POLICYDB_VERSION_PERMISSIVE,
>> +		.sym_num	= SYM_NUM,
>> +		.ocon_num	= OCON_NUM,
>>  	}
>>  };
>>  
>> @@ -194,6 +199,7 @@ static int policydb_init(struct policydb *p)
>>  		goto out_free_symtab;
>>  
>>  	ebitmap_init(&p->policycaps);
>> +	ebitmap_init(&p->permissive_map);
>>  
>>  out:
>>  	return rc;
>> @@ -687,6 +693,7 @@ void policydb_destroy(struct policydb *p)
>>  	kfree(p->type_attr_map);
>>  	kfree(p->undefined_perms);
>>  	ebitmap_destroy(&p->policycaps);
>> +	ebitmap_destroy(&p->permissive_map);
>>  
>>  	return;
>>  }
>> @@ -1570,6 +1577,10 @@ int policydb_read(struct policydb *p, void *fp)
>>  	    ebitmap_read(&p->policycaps, fp) != 0)
>>  		goto bad;
>>  
>> +	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
>> +	    ebitmap_read(&p->permissive_map, fp) != 0)
>> +		goto bad;
>> +
>>  	info = policydb_lookup_compat(p->policyvers);
>>  	if (!info) {
>>  		printk(KERN_ERR "security:  unable to find policy compat info "
>> diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
>> index c4ce996..ba593a3 100644
>> --- a/security/selinux/ss/policydb.h
>> +++ b/security/selinux/ss/policydb.h
>> @@ -243,6 +243,8 @@ struct policydb {
>>  
>>  	struct ebitmap policycaps;
>>  
>> +	struct ebitmap permissive_map;
>> +
>>  	unsigned int policyvers;
>>  
>>  	unsigned int reject_unknown : 1;
>> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
>> index f374186..f5d1dcc 100644
>> --- a/security/selinux/ss/services.c
>> +++ b/security/selinux/ss/services.c
>> @@ -416,6 +416,27 @@ inval_class:
>>  	return -EINVAL;
>>  }
>>  
>> +/*
>> + * Given a sid find if the type has the permissive flag set
>> + */
>> +int security_permissive_sid(u32 sid)
>> +{
>> +	struct context *context;
>> +	u32 type;
>> +	int rc;
>> +
>> +	POLICY_RDLOCK;
>> +
>> +	context = sidtab_search(&sidtab, sid);
>> +	BUG_ON(!context);
>> +
>> +	type = context->type;
>> +	rc = ebitmap_get_bit(&policydb.permissive_map, type);
> 
> Maybe a comment then to note that we are intentionally not using (type -
> 1) here due to possibly global use of that bit - otherwise it is a
> confusing inconsistency with other ebitmap_get_bit calls.
> 
>> +
>> +	POLICY_RDUNLOCK;
>> +	return rc;
>> +}
>> +
>>  static int security_validtrans_handle_fail(struct context *ocontext,
>>                                             struct context *ncontext,
>>                                             struct context *tcontext,
>>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkfXQEIACgkQrlYvE4MpobNsBgCffHW2x1Pq3g8ArEcgSF3HfUBG
nEgAoOMQlwnm0+g4VwC3IAF5vPgwTCkF
=wSvv
-----END PGP SIGNATURE-----

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux