From f3c3a1aa33bc3a34a5bef94d3643c3702cf925c6 Mon Sep 17 00:00:00 2001
From: Stephen Smalley <sds@tycho.nsa.gov>
Date: Thu, 19 Jun 2014 09:07:17 -0400
Subject: [PATCH] Remove execute_no_trans from unconfineddomain.

execute_no_trans controls whether a domain can execve a program
without switching to another domain.  Exclude this permission from
unconfineddomain, add it back to init, init_shell, and recovery for
files in / and /system, and to kernel for files in / (to permit
execution of init prior to setcon).  Prohibit it otherwise for the
kernel domain via neverallow.  This ensures that if a kernel task
attempts to execute a kernel usermodehelper for which no domain transition
is defined, the exec will fail.

Change-Id: Ie7b2349923672dd4f5faf7c068a6e5994fd0e4e3
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
 init.te       |  6 ++++++
 init_shell.te |  4 ++++
 kernel.te     | 16 ++++++++++++++++
 recovery.te   |  4 ++++
 unconfined.te | 10 +++++-----
 5 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/init.te b/init.te
index 3f4d706c8..069f041db 100644
--- a/init.te
+++ b/init.te
@@ -6,6 +6,12 @@ tmpfs_domain(init)
 
 allow init self:capability { sys_rawio mknod };
 
+# Run helpers from / or /system without changing domain.
+# We do not include exec_type here since generally those
+# should always involve a domain transition.
+allow init rootfs:file execute_no_trans;
+allow init system_file:file execute_no_trans;
+
 # Running e2fsck or mkswap via fs_mgr.
 allow init dev_type:blk_file rw_file_perms;
 
diff --git a/init_shell.te b/init_shell.te
index d2e4d74fd..51dbd07e9 100644
--- a/init_shell.te
+++ b/init_shell.te
@@ -4,3 +4,7 @@
 type init_shell, domain;
 domain_auto_trans(init, shell_exec, init_shell)
 permissive_or_unconfined(init_shell)
+
+# Run helpers from / or /system without changing domain.
+allow init_shell rootfs:file execute_no_trans;
+allow init_shell system_file:file execute_no_trans;
diff --git a/kernel.te b/kernel.te
index 08ccbf59c..084462486 100644
--- a/kernel.te
+++ b/kernel.te
@@ -1,6 +1,9 @@
 # Life begins with the kernel.
 type kernel, domain;
 
+# Run /init before we have switched domains.
+allow kernel rootfs:file execute_no_trans;
+
 # setcon to init domain.
 allow kernel self:process setcurrent;
 allow kernel init:process dyntransition;
@@ -38,3 +41,16 @@ allow kernel self:security setcheckreqprot;
 # The initial task starts in the kernel domain (assigned via
 # initial_sid_contexts), but nothing ever transitions to it.
 neverallow domain kernel:process { transition dyntransition };
+
+# The kernel domain is never entered via an exec, nor should it
+# ever execute a program outside the rootfs without changing to another domain.
+# If you encounter an execute_no_trans denial on the kernel domain, then
+# possible causes include:
+# - The program is a kernel usermodehelper.  In this case, define a domain
+#   for the program and domain_auto_trans() to it.
+# - You failed to setcon u:r:init:s0 in your init.rc and thus your init
+#   program was left in the kernel domain and is now trying to execute
+#   some other program.  Fix your init.rc file.
+# - You are running an exploit which switched to the init task credentials
+#   and is then trying to exec a shell or other program.  You lose!
+neverallow kernel { file_type fs_type -rootfs }:file { entrypoint execute_no_trans };
diff --git a/recovery.te b/recovery.te
index e98cf4482..13c21c2fe 100644
--- a/recovery.te
+++ b/recovery.te
@@ -15,6 +15,10 @@ recovery_only(`
   # Set security contexts on files that are not known to the loaded policy.
   allow recovery self:capability2 mac_admin;
 
+  # Run helpers from / or /system without changing domain.
+  allow recovery rootfs:file execute_no_trans;
+  allow recovery system_file:file execute_no_trans;
+
   # Mount filesystems.
   allow recovery rootfs:dir mounton;
   allow recovery fs_type:filesystem ~relabelto;
diff --git a/unconfined.te b/unconfined.te
index ce51f306f..97a7da19d 100644
--- a/unconfined.te
+++ b/unconfined.te
@@ -60,18 +60,18 @@ allow unconfineddomain {
     -shell_data_file
 }:{ dir lnk_file sock_file fifo_file } ~relabelto;
 allow unconfineddomain exec_type:dir r_dir_perms;
-allow unconfineddomain exec_type:file { rx_file_perms execmod };
+allow unconfineddomain exec_type:file { r_file_perms execute execmod };
 allow unconfineddomain exec_type:lnk_file r_file_perms;
 allow unconfineddomain system_file:dir r_dir_perms;
-allow unconfineddomain system_file:file { rx_file_perms execmod };
+allow unconfineddomain system_file:file { r_file_perms execute execmod };
 allow unconfineddomain system_file:lnk_file r_file_perms;
 allow unconfineddomain {
     fs_type
     -usermodehelper
     -proc_security
     -contextmount_type
-}:{ chr_file file } ~{entrypoint execmod execute relabelto};
-allow unconfineddomain {dev_type -kmem_device}:{ chr_file file } ~{entrypoint execmod execute relabelto};
+}:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
+allow unconfineddomain {dev_type -kmem_device}:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
 allow unconfineddomain {
     file_type
     -keystore_data_file
@@ -80,7 +80,7 @@ allow unconfineddomain {
     -exec_type
     -security_file
     -shell_data_file
-}:{ chr_file file } ~{entrypoint execmod execute relabelto};
+}:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
 allow unconfineddomain rootfs:file execute;
 allow unconfineddomain contextmount_type:dir r_dir_perms;
 allow unconfineddomain contextmount_type:notdevfile_class_set r_file_perms;
-- 
GitLab