forked from mirrors/linux
		
	devcg: prepare may_access() for hierarchy support
Currently may_access() is only able to verify if an exception is valid for the current cgroup, which has the same behavior. With hierarchy, it'll be also used to verify if a cgroup local exception is valid towards its cgroup parent, which might have different behavior. v2: - updated patch description - rebased on top of a new patch to expand the may_access() logic to make it more clear - fixed argument description order in may_access() Acked-by: Tejun Heo <tj@kernel.org> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Cc: Tejun Heo <tj@kernel.org> Cc: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Aristeu Rozanski <aris@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
		
							parent
							
								
									26898fdff3
								
							
						
					
					
						commit
						c39a2a3018
					
				
					 1 changed files with 31 additions and 18 deletions
				
			
		| 
						 | 
					@ -25,6 +25,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEFINE_MUTEX(devcgroup_mutex);
 | 
					static DEFINE_MUTEX(devcgroup_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum devcg_behavior {
 | 
				
			||||||
 | 
						DEVCG_DEFAULT_NONE,
 | 
				
			||||||
 | 
						DEVCG_DEFAULT_ALLOW,
 | 
				
			||||||
 | 
						DEVCG_DEFAULT_DENY,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * exception list locking rules:
 | 
					 * exception list locking rules:
 | 
				
			||||||
 * hold devcgroup_mutex for update/read.
 | 
					 * hold devcgroup_mutex for update/read.
 | 
				
			||||||
| 
						 | 
					@ -42,10 +48,7 @@ struct dev_exception_item {
 | 
				
			||||||
struct dev_cgroup {
 | 
					struct dev_cgroup {
 | 
				
			||||||
	struct cgroup_subsys_state css;
 | 
						struct cgroup_subsys_state css;
 | 
				
			||||||
	struct list_head exceptions;
 | 
						struct list_head exceptions;
 | 
				
			||||||
	enum {
 | 
						enum devcg_behavior behavior;
 | 
				
			||||||
		DEVCG_DEFAULT_ALLOW,
 | 
					 | 
				
			||||||
		DEVCG_DEFAULT_DENY,
 | 
					 | 
				
			||||||
	} behavior;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
 | 
					static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
 | 
				
			||||||
| 
						 | 
					@ -304,9 +307,11 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
 | 
				
			||||||
 *		verify if a certain access is allowed.
 | 
					 *		verify if a certain access is allowed.
 | 
				
			||||||
 * @dev_cgroup: dev cgroup to be tested against
 | 
					 * @dev_cgroup: dev cgroup to be tested against
 | 
				
			||||||
 * @refex: new exception
 | 
					 * @refex: new exception
 | 
				
			||||||
 | 
					 * @behavior: behavior of the exception
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool may_access(struct dev_cgroup *dev_cgroup,
 | 
					static bool may_access(struct dev_cgroup *dev_cgroup,
 | 
				
			||||||
		       struct dev_exception_item *refex)
 | 
							       struct dev_exception_item *refex,
 | 
				
			||||||
 | 
							       enum devcg_behavior behavior)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dev_exception_item *ex;
 | 
						struct dev_exception_item *ex;
 | 
				
			||||||
	bool match = false;
 | 
						bool match = false;
 | 
				
			||||||
| 
						 | 
					@ -330,20 +335,28 @@ static bool may_access(struct dev_cgroup *dev_cgroup,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
 | 
				
			||||||
	 * In two cases we'll consider this new exception valid:
 | 
							if (behavior == DEVCG_DEFAULT_ALLOW) {
 | 
				
			||||||
	 * - the dev cgroup has its default policy to deny + exception list:
 | 
								/* the exception will deny access to certain devices */
 | 
				
			||||||
	 *   the new exception *should* match the exceptions
 | 
					 | 
				
			||||||
	 * - the dev cgroup has its default policy to allow + exception list:
 | 
					 | 
				
			||||||
	 *   the new exception should *not* match any of the exceptions
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (dev_cgroup->behavior == DEVCG_DEFAULT_DENY) {
 | 
					 | 
				
			||||||
		if (match)
 | 
					 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
		if (!match)
 | 
								/* the exception will allow access to certain devices */
 | 
				
			||||||
 | 
								if (match)
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * a new exception allowing access shouldn't
 | 
				
			||||||
 | 
									 * match an parent's exception
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* only behavior == DEVCG_DEFAULT_DENY allowed here */
 | 
				
			||||||
 | 
							if (match)
 | 
				
			||||||
 | 
								/* parent has an exception that matches the proposed */
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -361,7 +374,7 @@ static int parent_has_perm(struct dev_cgroup *childcg,
 | 
				
			||||||
	if (!pcg)
 | 
						if (!pcg)
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	parent = cgroup_to_devcgroup(pcg);
 | 
						parent = cgroup_to_devcgroup(pcg);
 | 
				
			||||||
	return may_access(parent, ex);
 | 
						return may_access(parent, ex, childcg->behavior);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -395,7 +408,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *b;
 | 
						const char *b;
 | 
				
			||||||
	char temp[12];		/* 11 + 1 characters needed for a u32 */
 | 
						char temp[12];		/* 11 + 1 characters needed for a u32 */
 | 
				
			||||||
	int count, rc;
 | 
						int count, rc = 0;
 | 
				
			||||||
	struct dev_exception_item ex;
 | 
						struct dev_exception_item ex;
 | 
				
			||||||
	struct cgroup *p = devcgroup->css.cgroup;
 | 
						struct cgroup *p = devcgroup->css.cgroup;
 | 
				
			||||||
	struct dev_cgroup *parent = NULL;
 | 
						struct dev_cgroup *parent = NULL;
 | 
				
			||||||
| 
						 | 
					@ -612,7 +625,7 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	dev_cgroup = task_devcgroup(current);
 | 
						dev_cgroup = task_devcgroup(current);
 | 
				
			||||||
	rc = may_access(dev_cgroup, &ex);
 | 
						rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior);
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rc)
 | 
						if (!rc)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue