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