163 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| Some applications, like gdb, are able to ptrace both children or other
 | |
| completely unrelated tasks.  We would like to be able to discern these two
 | |
| things and to be able to allow gdb to ptrace it's children, but not to be
 | |
| able to ptrace unrelated tasks for security reasons.
 | |
| 
 | |
| Upstream is a bit weary of this patch as it may be incomplete.  They are
 | |
| not fundamentally opposed to the patch, I was just ask to see if I could
 | |
| flush out any needed refinement in Fedora where we already had the
 | |
| problem.  We may find that we need to emulate the YAMA non-child
 | |
| registration module in order to completely deal with 'normal' ptrace on
 | |
| a system.  At the moment however, this patch will at least let us get
 | |
| gdb working for many users in Fedora (See fedora-devel-list for a
 | |
| discussion of the current issues people are complaining about in F17
 | |
| without this)
 | |
| 
 | |
| ---
 | |
| 
 | |
|  security/selinux/hooks.c            |   38 +++++++++++++++++++++++++++++++++++
 | |
|  security/selinux/include/classmap.h |    2 +-
 | |
|  security/selinux/include/security.h |    2 ++
 | |
|  security/selinux/selinuxfs.c        |    3 ++-
 | |
|  security/selinux/ss/services.c      |    3 +++
 | |
|  5 files changed, 46 insertions(+), 2 deletions(-)
 | |
| 
 | |
| diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
 | |
| index 1a4acf4..b226f26 100644
 | |
| --- a/security/selinux/hooks.c
 | |
| +++ b/security/selinux/hooks.c
 | |
| @@ -1805,6 +1805,39 @@ static inline u32 open_file_to_av(struct file *file)
 | |
|  
 | |
|  /* Hook functions begin here. */
 | |
|  
 | |
| +/**
 | |
| + * task_is_descendant - walk up a process family tree looking for a match
 | |
| + * @parent: the process to compare against while walking up from child
 | |
| + * @child: the process to start from while looking upwards for parent
 | |
| + *
 | |
| + * Returns 1 if child is a descendant of parent, 0 if not.
 | |
| + */
 | |
| +static int task_is_descendant(struct task_struct *parent,
 | |
| +			      struct task_struct *child)
 | |
| +{
 | |
| +	int rc = 0;
 | |
| +	struct task_struct *walker = child;
 | |
| +
 | |
| +	if (!parent || !child)
 | |
| +		return 0;
 | |
| +
 | |
| +	rcu_read_lock();
 | |
| +	if (!thread_group_leader(parent))
 | |
| +		parent = rcu_dereference(parent->group_leader);
 | |
| +	while (walker->pid > 0) {
 | |
| +		if (!thread_group_leader(walker))
 | |
| +			walker = rcu_dereference(walker->group_leader);
 | |
| +		if (walker == parent) {
 | |
| +			rc = 1;
 | |
| +			break;
 | |
| +		}
 | |
| +		walker = rcu_dereference(walker->real_parent);
 | |
| +	}
 | |
| +	rcu_read_unlock();
 | |
| +
 | |
| +	return rc;
 | |
| +}
 | |
| +
 | |
|  static int selinux_ptrace_access_check(struct task_struct *child,
 | |
|  				     unsigned int mode)
 | |
|  {
 | |
| @@ -1820,6 +1853,9 @@ static int selinux_ptrace_access_check(struct task_struct *child,
 | |
|  		return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
 | |
|  	}
 | |
|  
 | |
| +
 | |
| +	if (selinux_policycap_ptrace_child && task_is_descendant(current, child))
 | |
| +		return current_has_perm(child, PROCESS__PTRACE_CHILD);
 | |
|  	return current_has_perm(child, PROCESS__PTRACE);
 | |
|  }
 | |
|  
 | |
| @@ -1831,6 +1867,8 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
 | |
|  	if (rc)
 | |
|  		return rc;
 | |
|  
 | |
| +	if (selinux_policycap_ptrace_child && task_is_descendant(parent, current))
 | |
| +		return task_has_perm(parent, current, PROCESS__PTRACE_CHILD);
 | |
|  	return task_has_perm(parent, current, PROCESS__PTRACE);
 | |
|  }
 | |
|  
 | |
| diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
 | |
| index 39e678c..72c08b9 100644
 | |
| --- a/security/selinux/include/classmap.h
 | |
| +++ b/security/selinux/include/classmap.h
 | |
| @@ -29,7 +29,7 @@ struct security_class_mapping secclass_map[] = {
 | |
|  	    "getattr", "setexec", "setfscreate", "noatsecure", "siginh",
 | |
|  	    "setrlimit", "rlimitinh", "dyntransition", "setcurrent",
 | |
|  	    "execmem", "execstack", "execheap", "setkeycreate",
 | |
| -	    "setsockcreate", NULL } },
 | |
| +	    "setsockcreate", "ptrace_child", NULL } },
 | |
|  	{ "system",
 | |
|  	  { "ipc_info", "syslog_read", "syslog_mod",
 | |
|  	    "syslog_console", "module_request", NULL } },
 | |
| diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
 | |
| index dde2005..ac14b0a 100644
 | |
| --- a/security/selinux/include/security.h
 | |
| +++ b/security/selinux/include/security.h
 | |
| @@ -68,12 +68,14 @@ extern int selinux_enabled;
 | |
|  enum {
 | |
|  	POLICYDB_CAPABILITY_NETPEER,
 | |
|  	POLICYDB_CAPABILITY_OPENPERM,
 | |
| +	POLICYDB_CAPABILITY_PTRACE_CHILD,
 | |
|  	__POLICYDB_CAPABILITY_MAX
 | |
|  };
 | |
|  #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
 | |
|  
 | |
|  extern int selinux_policycap_netpeer;
 | |
|  extern int selinux_policycap_openperm;
 | |
| +extern int selinux_policycap_ptrace_child;
 | |
|  
 | |
|  /*
 | |
|   * type_datum properties
 | |
| diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
 | |
| index 4e93f9e..3379765 100644
 | |
| --- a/security/selinux/selinuxfs.c
 | |
| +++ b/security/selinux/selinuxfs.c
 | |
| @@ -44,7 +44,8 @@
 | |
|  /* Policy capability filenames */
 | |
|  static char *policycap_names[] = {
 | |
|  	"network_peer_controls",
 | |
| -	"open_perms"
 | |
| +	"open_perms",
 | |
| +	"ptrace_child",
 | |
|  };
 | |
|  
 | |
|  unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 | |
| diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
 | |
| index 9b7e7ed..4d12a6e 100644
 | |
| --- a/security/selinux/ss/services.c
 | |
| +++ b/security/selinux/ss/services.c
 | |
| @@ -72,6 +72,7 @@
 | |
|  
 | |
|  int selinux_policycap_netpeer;
 | |
|  int selinux_policycap_openperm;
 | |
| +int selinux_policycap_ptrace_child;
 | |
|  
 | |
|  static DEFINE_RWLOCK(policy_rwlock);
 | |
|  
 | |
| @@ -1812,6 +1813,8 @@ static void security_load_policycaps(void)
 | |
|  						  POLICYDB_CAPABILITY_NETPEER);
 | |
|  	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
 | |
|  						  POLICYDB_CAPABILITY_OPENPERM);
 | |
| +	selinux_policycap_ptrace_child = ebitmap_get_bit(&policydb.policycaps,
 | |
| +						  POLICYDB_CAPABILITY_PTRACE_CHILD);
 | |
|  }
 | |
|  
 | |
|  static int security_preserve_bools(struct policydb *p);
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| _______________________________________________
 | |
| kernel mailing list
 | |
| kernel@lists.fedoraproject.org
 | |
| https://admin.fedoraproject.org/mailman/listinfo/kernel
 |