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