Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

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

 



On Mon, 2008-08-25 at 21:32 +0900, KaiGai Kohei wrote:
> The following patch is revised one for kernel.
> 
> Updates:
>  - This patch is rebased on James's security-testing-2.6 tree.
>  - security_bounded_transition() is deployed just after read_unlock()
>    within do_each_thread() { ... } while_each_thread() loop again.
>  - The properties of type_datum are packed within the third word of
>    type entries in the kernel policy.
>  - Bounds checks on constraints are integrated within avc creation.
>    Lazy bounds checks are invoked at the tail of context_struct_compute_av(),
>    and it drops all of boundary violated permissions. It compares permissions
>    of a bounded type based on both of TE and constraints by a bounds type in
>    same time, so the bounded type always cannot have any wider permission than
>    its parent.
>    e.g)
>      When a type of child_t is bounded by parent_t and has mcssetcats attribute,
>      we cannot assign undominated categories because parent_t is not allowed to
>      assign them and it bounds permissions of child_t.
>  - Sanity checks for constraints are removed by the above reason.

This looks good to me in terms of the functionality.
Have you run any benchmarks to assess the performance impact on AVC
misses?

> 
> Thanks,
> 
> Signed-off-by: KaiGai Kohei <kaigai@xxxxxxxxxxxx>
> --
>  security/selinux/avc.c              |    2 +-
>  security/selinux/hooks.c            |   11 ++-
>  security/selinux/include/avc.h      |    4 +
>  security/selinux/include/security.h |   15 +++-
>  security/selinux/ss/policydb.c      |  205 ++++++++++++++++++++++++++++++++---
>  security/selinux/ss/policydb.h      |    5 +
>  security/selinux/ss/services.c      |  172 +++++++++++++++++++++++++++++-
>  7 files changed, 395 insertions(+), 19 deletions(-)
> 
> diff --git a/security/selinux/avc.c b/security/selinux/avc.c
> index 114b4b4..cb30c7e 100644
> --- a/security/selinux/avc.c
> +++ b/security/selinux/avc.c
> @@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
>   * @tclass: target security class
>   * @av: access vector
>   */
> -static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
> +void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
>  {
>  	const char **common_pts = NULL;
>  	u32 common_base = 0;
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 03fc6a8..e06e963 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5219,8 +5219,12 @@ static int selinux_setprocattr(struct task_struct *p,
> 
>  		if (sid == 0)
>  			return -EINVAL;
> -
> -		/* Only allow single threaded processes to change context */
> +		/*
> +		 * SELinux allows to change context in the following case only.
> +		 *  - Single threaded processes.
> +		 *  - Multi threaded processes intend to change its context into
> +		 *    more restricted domain (defined by TYPEBOUNDS statement).
> +		 */
>  		if (atomic_read(&p->mm->mm_users) != 1) {
>  			struct task_struct *g, *t;
>  			struct mm_struct *mm = p->mm;
> @@ -5228,11 +5232,14 @@ static int selinux_setprocattr(struct task_struct *p,
>  			do_each_thread(g, t) {
>  				if (t->mm == mm && t != p) {
>  					read_unlock(&tasklist_lock);
> +					if (!security_bounded_transition(tsec->sid, sid))
> +						goto boundary_ok;
>  					return -EPERM;
>  				}
>  			} while_each_thread(g, t);
>  			read_unlock(&tasklist_lock);
>  		}
> +boundary_ok:
> 
>  		/* Check permissions for the transition. */
>  		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
> diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
> index 7b9769f..d12ff1a 100644
> --- a/security/selinux/include/avc.h
> +++ b/security/selinux/include/avc.h
> @@ -12,6 +12,7 @@
>  #include <linux/kdev_t.h>
>  #include <linux/spinlock.h>
>  #include <linux/init.h>
> +#include <linux/audit.h>
>  #include <linux/in6.h>
>  #include <linux/path.h>
>  #include <asm/system.h>
> @@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
>  		     u32 events, u32 ssid, u32 tsid,
>  		     u16 tclass, u32 perms);
> 
> +/* Shows permission in human readable form */
> +void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
> +
>  /* Exported to selinuxfs */
>  int avc_get_hash_stats(char *page);
>  extern unsigned int avc_cache_threshold;
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index 7c54300..7244737 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -27,13 +27,14 @@
>  #define POLICYDB_VERSION_RANGETRANS	21
>  #define POLICYDB_VERSION_POLCAP		22
>  #define POLICYDB_VERSION_PERMISSIVE	23
> +#define POLICYDB_VERSION_BOUNDARY	24
> 
>  /* 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_PERMISSIVE
> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
>  #endif
> 
>  #define CONTEXT_MNT	0x01
> @@ -62,6 +63,16 @@ enum {
>  extern int selinux_policycap_netpeer;
>  extern int selinux_policycap_openperm;
> 
> +/*
> + * type_datum properties
> + * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
> + */
> +#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
> +#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
> +
> +/* limitation of boundary depth  */
> +#define POLICYDB_BOUNDS_MAXDEPTH	4
> +
>  int security_load_policy(void *data, size_t len);
> 
>  int security_policycap_supported(unsigned int req_cap);
> @@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
>  int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
>  				 u16 tclass);
> 
> +int security_bounded_transition(u32 oldsid, u32 newsid);
> +
>  int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
> 
>  int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
> index 2391761..7dbe756 100644
> --- a/security/selinux/ss/policydb.c
> +++ b/security/selinux/ss/policydb.c
> @@ -30,6 +30,7 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/errno.h>
> +#include <linux/audit.h>
>  #include "security.h"
> 
>  #include "policydb.h"
> @@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = {
>  		.version	= POLICYDB_VERSION_PERMISSIVE,
>  		.sym_num	= SYM_NUM,
>  		.ocon_num	= OCON_NUM,
> -	}
> +	},
> +	{
> +		.version	= POLICYDB_VERSION_BOUNDARY,
> +		.sym_num	= SYM_NUM,
> +		.ocon_num	= OCON_NUM,
> +	},
>  };
> 
>  static struct policydb_compat_info *policydb_lookup_compat(int version)
> @@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap)
> 
>  	role = datum;
>  	p = datap;
> -	if (!role->value || role->value > p->p_roles.nprim)
> +	if (!role->value
> +	    || role->value > p->p_roles.nprim
> +	    || role->bounds > p->p_roles.nprim)
>  		return -EINVAL;
>  	p->p_role_val_to_name[role->value - 1] = key;
>  	p->role_val_to_struct[role->value - 1] = role;
> @@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap)
>  	p = datap;
> 
>  	if (typdatum->primary) {
> -		if (!typdatum->value || typdatum->value > p->p_types.nprim)
> +		if (!typdatum->value
> +		    || typdatum->value > p->p_types.nprim
> +		    || typdatum->bounds > p->p_types.nprim)
>  			return -EINVAL;
>  		p->p_type_val_to_name[typdatum->value - 1] = key;
> +		p->type_val_to_struct[typdatum->value - 1] = typdatum;
>  	}
> 
>  	return 0;
> @@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap)
> 
>  	usrdatum = datum;
>  	p = datap;
> -	if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
> +	if (!usrdatum->value
> +	    || usrdatum->value > p->p_users.nprim
> +	    || usrdatum->bounds > p->p_users.nprim)
>  		return -EINVAL;
>  	p->p_user_val_to_name[usrdatum->value - 1] = key;
>  	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
> @@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p)
>  		goto out;
>  	}
> 
> +	p->type_val_to_struct =
> +		kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
> +			GFP_KERNEL);
> +	if (!p->type_val_to_struct) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
>  	if (cond_init_bool_indexes(p)) {
>  		rc = -ENOMEM;
>  		goto out;
> @@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p)
>  	kfree(p->class_val_to_struct);
>  	kfree(p->role_val_to_struct);
>  	kfree(p->user_val_to_struct);
> +	kfree(p->type_val_to_struct);
> 
>  	avtab_destroy(&p->te_avtab);
> 
> @@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
>  {
>  	char *key = NULL;
>  	struct role_datum *role;
> -	int rc;
> -	__le32 buf[2];
> +	int rc, to_read = 2;
> +	__le32 buf[3];
>  	u32 len;
> 
>  	role = kzalloc(sizeof(*role), GFP_KERNEL);
> @@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
>  		goto out;
>  	}
> 
> -	rc = next_entry(buf, fp, sizeof buf);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
> +		to_read = 3;
> +
> +	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
>  	if (rc < 0)
>  		goto bad;
> 
>  	len = le32_to_cpu(buf[0]);
>  	role->value = le32_to_cpu(buf[1]);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
> +		role->bounds = le32_to_cpu(buf[2]);
> 
>  	key = kmalloc(len + 1, GFP_KERNEL);
>  	if (!key) {
> @@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
>  {
>  	char *key = NULL;
>  	struct type_datum *typdatum;
> -	int rc;
> -	__le32 buf[3];
> +	int rc, to_read = 3;
> +	__le32 buf[4];
>  	u32 len;
> 
>  	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
> @@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
>  		return rc;
>  	}
> 
> -	rc = next_entry(buf, fp, sizeof buf);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
> +		to_read = 4;
> +
> +	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
>  	if (rc < 0)
>  		goto bad;
> 
>  	len = le32_to_cpu(buf[0]);
>  	typdatum->value = le32_to_cpu(buf[1]);
> -	typdatum->primary = le32_to_cpu(buf[2]);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
> +		u32 prop = le32_to_cpu(buf[2]);
> +
> +		if (prop & TYPEDATUM_PROPERTY_PRIMARY)
> +			typdatum->primary = 1;
> +		if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
> +			typdatum->attribute = 1;
> +
> +		typdatum->bounds = le32_to_cpu(buf[3]);
> +	} else {
> +		typdatum->primary = le32_to_cpu(buf[2]);
> +	}
> 
>  	key = kmalloc(len + 1, GFP_KERNEL);
>  	if (!key) {
> @@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
>  {
>  	char *key = NULL;
>  	struct user_datum *usrdatum;
> -	int rc;
> -	__le32 buf[2];
> +	int rc, to_read = 2;
> +	__le32 buf[3];
>  	u32 len;
> 
>  	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
> @@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
>  		goto out;
>  	}
> 
> -	rc = next_entry(buf, fp, sizeof buf);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
> +		to_read = 3;
> +
> +	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
>  	if (rc < 0)
>  		goto bad;
> 
>  	len = le32_to_cpu(buf[0]);
>  	usrdatum->value = le32_to_cpu(buf[1]);
> +	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
> +		usrdatum->bounds = le32_to_cpu(buf[2]);
> 
>  	key = kmalloc(len + 1, GFP_KERNEL);
>  	if (!key) {
> @@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
>  	cat_read,
>  };
> 
> +static int user_bounds_sanity_check(void *key, void *datum, void *datap)
> +{
> +	struct user_datum *upper, *user;
> +	struct policydb *p = datap;
> +	int depth = 0;
> +
> +	upper = user = datum;
> +	while (upper->bounds) {
> +		struct ebitmap_node *node;
> +		unsigned long bit;
> +
> +		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
> +			printk(KERN_ERR "SELinux: user %s: "
> +			       "too deep or looped boundary",
> +			       (char *) key);
> +			return -EINVAL;
> +		}
> +
> +		upper = p->user_val_to_struct[upper->bounds - 1];
> +		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
> +			if (ebitmap_get_bit(&upper->roles, bit))
> +				continue;
> +
> +			printk(KERN_ERR
> +			       "SELinux: boundary violated policy: "
> +			       "user=%s role=%s bounds=%s\n",
> +			       p->p_user_val_to_name[user->value - 1],
> +			       p->p_role_val_to_name[bit],
> +			       p->p_user_val_to_name[upper->value - 1]);
> +
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int role_bounds_sanity_check(void *key, void *datum, void *datap)
> +{
> +	struct role_datum *upper, *role;
> +	struct policydb *p = datap;
> +	int depth = 0;
> +
> +	upper = role = datum;
> +	while (upper->bounds) {
> +		struct ebitmap_node *node;
> +		unsigned long bit;
> +
> +		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
> +			printk(KERN_ERR "SELinux: role %s: "
> +			       "too deep or looped bounds\n",
> +			       (char *) key);
> +			return -EINVAL;
> +		}
> +
> +		upper = p->role_val_to_struct[upper->bounds - 1];
> +		ebitmap_for_each_positive_bit(&role->types, node, bit) {
> +			if (ebitmap_get_bit(&upper->types, bit))
> +				continue;
> +
> +			printk(KERN_ERR
> +			       "SELinux: boundary violated policy: "
> +			       "role=%s type=%s bounds=%s\n",
> +			       p->p_role_val_to_name[role->value - 1],
> +			       p->p_type_val_to_name[bit],
> +			       p->p_role_val_to_name[upper->value - 1]);
> +
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int type_bounds_sanity_check(void *key, void *datum, void *datap)
> +{
> +	struct type_datum *upper, *type;
> +	struct policydb *p = datap;
> +	int depth = 0;
> +
> +	upper = type = datum;
> +	while (upper->bounds) {
> +		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
> +			printk(KERN_ERR "SELinux: type %s: "
> +			       "too deep or looped boundary\n",
> +			       (char *) key);
> +			return -EINVAL;
> +		}
> +
> +		upper = p->type_val_to_struct[upper->bounds - 1];
> +		if (upper->attribute) {
> +			printk(KERN_ERR "SELinux: type %s: "
> +			       "bounded by attribute %s",
> +			       (char *) key,
> +			       p->p_type_val_to_name[upper->value - 1]);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int policydb_bounds_sanity_check(struct policydb *p)
> +{
> +	int rc;
> +
> +	if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
> +		return 0;
> +
> +	rc = hashtab_map(p->p_users.table,
> +			 user_bounds_sanity_check, p);
> +	if (rc)
> +		return rc;
> +
> +	rc = hashtab_map(p->p_roles.table,
> +			 role_bounds_sanity_check, p);
> +	if (rc)
> +		return rc;
> +
> +	rc = hashtab_map(p->p_types.table,
> +			 type_bounds_sanity_check, p);
> +	if (rc)
> +		return rc;
> +
> +	return 0;
> +}
> +
>  extern int ss_initialized;
> 
>  /*
> @@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp)
>  				goto bad;
>  	}
> 
> +	rc = policydb_bounds_sanity_check(p);
> +	if (rc)
> +		goto bad;
> +
>  	rc = 0;
>  out:
>  	return rc;
> diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
> index 4253370..55152d4 100644
> --- a/security/selinux/ss/policydb.h
> +++ b/security/selinux/ss/policydb.h
> @@ -61,6 +61,7 @@ struct class_datum {
>  /* Role attributes */
>  struct role_datum {
>  	u32 value;			/* internal role value */
> +	u32 bounds;			/* boundary of role */
>  	struct ebitmap dominates;	/* set of roles dominated by this role */
>  	struct ebitmap types;		/* set of authorized types for role */
>  };
> @@ -81,12 +82,15 @@ struct role_allow {
>  /* Type attributes */
>  struct type_datum {
>  	u32 value;		/* internal type value */
> +	u32 bounds;		/* boundary of type */
>  	unsigned char primary;	/* primary name? */
> +	unsigned char attribute;/* attribute ?*/
>  };
> 
>  /* User attributes */
>  struct user_datum {
>  	u32 value;			/* internal user value */
> +	u32 bounds;			/* bounds of user */
>  	struct ebitmap roles;		/* set of authorized roles for user */
>  	struct mls_range range;		/* MLS range (min - max) for user */
>  	struct mls_level dfltlevel;	/* default login MLS level for user */
> @@ -209,6 +213,7 @@ struct policydb {
>  	struct class_datum **class_val_to_struct;
>  	struct role_datum **role_val_to_struct;
>  	struct user_datum **user_val_to_struct;
> +	struct type_datum **type_val_to_struct;
> 
>  	/* type enforcement access vectors and transitions */
>  	struct avtab te_avtab;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index b52f923..1ed94a3 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -88,6 +88,11 @@ static u32 latest_granting;
>  static int context_struct_to_string(struct context *context, char **scontext,
>  				    u32 *scontext_len);
> 
> +static int context_struct_compute_av(struct context *scontext,
> +				     struct context *tcontext,
> +				     u16 tclass,
> +				     u32 requested,
> +				     struct av_decision *avd);
>  /*
>   * Return the boolean value of a constraint expression
>   * when it is applied to the specified source and target
> @@ -274,6 +279,100 @@ mls_ops:
>  }
> 
>  /*
> + * security_boundary_permission - drops violated permissions
> + * on boundary constraint.
> + */
> +static void type_attribute_bounds_av(struct context *scontext,
> +				     struct context *tcontext,
> +				     u16 tclass,
> +				     u32 requested,
> +				     struct av_decision *avd)
> +{
> +	struct context lo_scontext;
> +	struct context lo_tcontext;
> +	struct av_decision lo_avd;
> +	struct type_datum *source
> +		= policydb.type_val_to_struct[scontext->type - 1];
> +	struct type_datum *target
> +		= policydb.type_val_to_struct[tcontext->type - 1];
> +	u32 masked = 0;
> +
> +	if (source->bounds) {
> +		memset(&lo_avd, 0, sizeof(lo_avd));
> +
> +		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
> +		lo_scontext.type = source->bounds;
> +
> +		context_struct_compute_av(&lo_scontext,
> +					  tcontext,
> +					  tclass,
> +					  requested,
> +					  &lo_avd);
> +		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
> +			return;		/* no masked permission */
> +		masked = ~lo_avd.allowed & avd->allowed;
> +	}
> +
> +	if (target->bounds) {
> +		memset(&lo_avd, 0, sizeof(lo_avd));
> +
> +		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
> +		lo_tcontext.type = target->bounds;
> +
> +		context_struct_compute_av(scontext,
> +					  &lo_tcontext,
> +					  tclass,
> +					  requested,
> +					  &lo_avd);
> +		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
> +			return;		/* no masked permission */
> +		masked = ~lo_avd.allowed & avd->allowed;
> +	}
> +
> +	if (source->bounds && target->bounds) {
> +		memset(&lo_avd, 0, sizeof(lo_avd));
> +		/*
> +		 * lo_scontext and lo_tcontext are already
> +		 * set up.
> +		 */
> +
> +		context_struct_compute_av(&lo_scontext,
> +					  &lo_tcontext,
> +					  tclass,
> +					  requested,
> +					  &lo_avd);
> +		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
> +			return;		/* no masked permission */
> +		masked = ~lo_avd.allowed & avd->allowed;
> +	}
> +
> +	if (masked) {
> +		struct audit_buffer *ab;
> +		char *stype_name
> +			= policydb.p_type_val_to_name[source->value - 1];
> +		char *ttype_name
> +			= policydb.p_type_val_to_name[target->value - 1];
> +		char *tclass_name
> +			= policydb.p_class_val_to_name[tclass - 1];
> +
> +		/* mask violated permissions */
> +		avd->allowed &= ~masked;
> +
> +		/* notice to userspace via audit message */
> +		ab = audit_log_start(current->audit_context,
> +				     GFP_ATOMIC, AUDIT_SELINUX_ERR);
> +		if (!ab)
> +			return;
> +
> +		audit_log_format(ab, "av boundary violation: "
> +				 "source=%s target=%s tclass=%s",
> +				 stype_name, ttype_name, tclass_name);
> +		avc_dump_av(ab, tclass, masked);
> +		audit_log_end(ab);
> +	}
> +}
> +
> +/*
>   * Compute access vectors based on a context structure pair for
>   * the permissions in a particular class.
>   */
> @@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext,
>  							PROCESS__DYNTRANSITION);
>  	}
> 
> +	/*
> +	 * If the given source and target types have boundary
> +	 * constraint, lazy checks have to mask any violated
> +	 * permission and notice it to userspace via audit.
> +	 */
> +	type_attribute_bounds_av(scontext, tcontext,
> +				 tclass, requested, avd);
> +
>  	return 0;
> 
>  inval_class:
> @@ -549,6 +656,69 @@ out:
>  	return rc;
>  }
> 
> +/*
> + * security_bounded_transition - check whether the given
> + * transition is directed to bounded, or not.
> + * It returns 0, if @newsid is bounded by @oldsid.
> + * Otherwise, it returns error code.
> + *
> + * @oldsid : current security identifier
> + * @newsid : destinated security identifier
> + */
> +int security_bounded_transition(u32 old_sid, u32 new_sid)
> +{
> +	struct context *old_context, *new_context;
> +	struct type_datum *type;
> +	int index;
> +	int rc = -EINVAL;
> +
> +	read_lock(&policy_rwlock);
> +
> +	old_context = sidtab_search(&sidtab, old_sid);
> +	if (!old_context) {
> +		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
> +		       __func__, old_sid);
> +		goto out;
> +	}
> +
> +	new_context = sidtab_search(&sidtab, new_sid);
> +	if (!new_context) {
> +		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
> +		       __func__, new_sid);
> +		goto out;
> +	}
> +
> +	/* type/domain unchaned */
> +	if (old_context->type == new_context->type) {
> +		rc = 0;
> +		goto out;
> +	}
> +
> +	index = new_context->type;
> +	while (true) {
> +		type = policydb.type_val_to_struct[index - 1];
> +		BUG_ON(!type);
> +
> +		/* not bounded anymore */
> +		if (!type->bounds) {
> +			rc = -EPERM;
> +			break;
> +		}
> +
> +		/* @newsid is bounded by @oldsid */
> +		if (type->bounds == old_context->type) {
> +			rc = 0;
> +			break;
> +		}
> +		index = type->bounds;
> +	}
> +out:
> +	read_unlock(&policy_rwlock);
> +
> +	return rc;
> +}
> +
> +
>  /**
>   * security_compute_av - Compute access vector decisions.
>   * @ssid: source security identifier
> @@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol,
>  	*p++ = 0;
> 
>  	typdatum = hashtab_search(pol->p_types.table, scontextp);
> -	if (!typdatum)
> +	if (!typdatum || typdatum->attribute)
>  		goto out;
> 
>  	ctx->type = typdatum->value;
> 
-- 
Stephen Smalley
National Security Agency


--
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