Re: [PATCH 1/3] Thread/Child-Domain Assignment

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

 



On Fri, 2008-07-25 at 22:03 +0900, KaiGai Kohei wrote:
> [1/3] thread-context-kernel.1.patch
>   This patch enables to assign a thread a "weaker" hierarchical domain,
>   only if the destinated domain is a child of the current domain.
>   Hierachy relationships are defined in the policy version 24.
>   This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it
seems like it should be completely taken into the kernel, i.e. the
hierarchy checking should be applied by the kernel rather than by the
toolchain.  That is what the Flask security server did for its
extensible policy mechanism.

And I think both the neverallow checking and the type hierarchy checking
needs to move away from needing to do a full expansion in order to
check; it is just too expensive these days.

> 
> 
> Signed-off-by: KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
> ----
>  security/selinux/hooks.c            |   11 +++++-
>  security/selinux/include/security.h |    5 ++-
>  security/selinux/ss/policydb.c      |   75 ++++++++++++++++++++++++++++++++--
>  security/selinux/ss/policydb.h      |    2 +
>  security/selinux/ss/services.c      |   60 ++++++++++++++++++++++++++++
>  5 files changed, 146 insertions(+), 7 deletions(-)
> 
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index bc1c3ae..d4c1c5c 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5181,7 +5181,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
> +		 *    lower or same domain in hierarchy relationship.
> +		 */
>  		if (atomic_read(&p->mm->mm_users) != 1) {
>  			struct task_struct *g, *t;
>  			struct mm_struct *mm = p->mm;
> @@ -5189,11 +5194,15 @@ 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_check_hierarchy(tsec->sid, sid))
> +						goto hierarchy_ok;
>  					return -EPERM;
>  				}
>  			} while_each_thread(g, t);
>  			read_unlock(&tasklist_lock);
>  		}
> +hierarchy_ok:
> 
>  		/* Check permissions for the transition. */
>  		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index ad30ac4..97fa9bb 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_HIERARCHY	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_HIERARCHY
>  #endif
> 
>  #define CONTEXT_MNT	0x01
> @@ -118,6 +119,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
>  				 u32 xfrm_sid,
>  				 u32 *peer_sid);
> 
> +int security_check_hierarchy(u32 old_sid, u32 new_sid);
> +
>  int security_get_classes(char ***classes, int *nclasses);
>  int security_get_permissions(char *class, char ***perms, int *nperms);
>  int security_get_reject_unknown(void);
> diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
> index 84f8cc7..e388f7a 100644
> --- a/security/selinux/ss/policydb.c
> +++ b/security/selinux/ss/policydb.c
> @@ -116,7 +116,12 @@ static struct policydb_compat_info policydb_compat[] = {
>  		.version	= POLICYDB_VERSION_PERMISSIVE,
>  		.sym_num	= SYM_NUM,
>  		.ocon_num	= OCON_NUM,
> -	}
> +	},
> +	{
> +		.version	= POLICYDB_VERSION_HIERARCHY,
> +		.sym_num	= SYM_NUM,
> +		.ocon_num	= OCON_NUM,
> +	},
>  };
> 
>  static struct policydb_compat_info *policydb_lookup_compat(int version)
> @@ -270,9 +275,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->parent > 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;
> @@ -397,6 +405,46 @@ static void symtab_hash_eval(struct symtab *s)
>  }
>  #endif
> 
> +static int type_hierarchy_sanity_checks(struct policydb *p)
> +{
> +	struct type_datum *type;
> +	struct ebitmap e;
> +	int rc = 0, i;
> +
> +	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
> +		return 0;
> +
> +	for (i = 0; i < p->p_types.nprim; i++) {
> +		type = p->type_val_to_struct[i];
> +
> +		if (!type || !type->parent)
> +			continue;
> +
> +		ebitmap_init(&e);
> +		while (type) {
> +			if (ebitmap_get_bit(&e, type->value - 1)) {
> +				printk(KERN_ERR "Hierarchy type looped at %s\n",
> +				       p->p_type_val_to_name[type->value - 1]);
> +				rc = -EINVAL;
> +				break;
> +			}
> +
> +			rc = ebitmap_set_bit(&e, type->value - 1, 1);
> +			if (rc)
> +				break;
> +
> +			if (!type->parent)
> +				break;
> +
> +			type = p->type_val_to_struct[type->parent - 1];
> +		}
> +		ebitmap_destroy(&e);
> +		if (rc)
> +			return rc;
> +	}
> +	return 0;
> +}
> +
>  /*
>   * Define the other val_to_name and val_to_struct arrays
>   * in a policy database structure.
> @@ -438,6 +486,14 @@ static int policydb_index_others(struct policydb *p)
>  		goto out;
>  	}
> 
> +	p->type_val_to_struct =
> +		kzalloc(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;
> @@ -455,6 +511,7 @@ static int policydb_index_others(struct policydb *p)
>  			goto out;
>  	}
> 
> +	rc = type_hierarchy_sanity_checks(p);
>  out:
>  	return rc;
>  }
> @@ -625,6 +682,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);
> 
> @@ -1236,8 +1294,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 to_read, rc;
> +	__le32 buf[4];
>  	u32 len;
> 
>  	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
> @@ -1246,13 +1304,20 @@ 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_HIERARCHY)
> +		to_read = sizeof(u32) * 3;
> +	else
> +		to_read = sizeof(u32) * 4;
> +
> +	rc = next_entry(buf, fp, 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_HIERARCHY)
> +		typdatum->parent = le32_to_cpu(buf[3]);
> 
>  	key = kmalloc(len + 1, GFP_KERNEL);
>  	if (!key) {
> diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
> index 4253370..f3484d4 100644
> --- a/security/selinux/ss/policydb.h
> +++ b/security/selinux/ss/policydb.h
> @@ -81,6 +81,7 @@ struct role_allow {
>  /* Type attributes */
>  struct type_datum {
>  	u32 value;		/* internal type value */
> +	u32 parent;		/* parent type, if hierarchy related */
>  	unsigned char primary;	/* primary name? */
>  };
> 
> @@ -209,6 +210,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 dcc2e1c..3ecd793 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -2160,6 +2160,66 @@ out_slowpath:
>  	return rc;
>  }
> 
> +/*
> + * security_check_hierarchy
> + *
> + * It returns 0, if @old_sid is same or upper type of @new_sid in hierarchy
> + * relationship directly/indirectly. 1 means @old_sid is not a child type
> + * of @new_sid, and negative returns are error.
> + */
> +int security_check_hierarchy(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;
> +	}
> +
> +	/* domain unchanged */
> +	if (old_context->type == new_context->type) {
> +		rc = 0;
> +		goto out;
> +	}
> +
> +	/* check domain hierarchy */
> +	index = new_context->type;
> +	while (true) {
> +		type = policydb.type_val_to_struct[index - 1];
> +		if (!type)
> +			break;
> +
> +		/* No hierarchy relationship */
> +		if (type->parent == 0) {
> +			rc = 1;
> +			break;
> +		}
> +		if (type->parent == old_context->type) {
> +			rc = 0;
> +			break;
> +		}
> +		index = type->parent;
> +	}
> +out:
> +	read_unlock(&policy_rwlock);
> +
> +	return rc;
> +}
> +
>  static int get_classes_callback(void *k, void *d, void *args)
>  {
>  	struct class_datum *datum = d;
> 
> 


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