[RFC PATCH] selinux: enable proper lockdep checking for policy rcu access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In the previous change to convert the policy rwlock to RCU,
the update code was using rcu_dereference_check(..., 1) with
a comment to explain why it was safe without taking rcu_read_lock()
since the mutex used to provide exclusion was taken at a higher
level in selinuxfs.  This change passes the mutex down to the
necessary functions and replaces rcu_dereference_check(..., 1)
with rcu_dereference_protected(..., lockdep_is_held(mutex)) so
that lockdep checking is correctly applied and the dependency
is made explicit in the code rather than relying on comments.

Signed-off-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx>
---
This is relative to the convert policy read-write lock to RCU patch,
https://patchwork.kernel.org/patch/11724997/.

 security/selinux/include/conditional.h |  3 +-
 security/selinux/include/security.h    |  6 ++--
 security/selinux/selinuxfs.c           | 12 ++++---
 security/selinux/ss/services.c         | 45 ++++++++------------------
 4 files changed, 26 insertions(+), 40 deletions(-)

diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h
index b09343346e3f..4659193dc49d 100644
--- a/security/selinux/include/conditional.h
+++ b/security/selinux/include/conditional.h
@@ -16,7 +16,8 @@
 int security_get_bools(struct selinux_policy *policy,
 		       u32 *len, char ***names, int **values);
 
-int security_set_bools(struct selinux_state *state, u32 len, int *values);
+int security_set_bools(struct selinux_state *state, struct mutex *mutex,
+		u32 len, int *values);
 
 int security_get_bool_value(struct selinux_state *state, u32 index);
 
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 505e51264d51..87eac1f2e6ed 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -209,12 +209,12 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
 }
 
 int security_mls_enabled(struct selinux_state *state);
-int security_load_policy(struct selinux_state *state,
+int security_load_policy(struct selinux_state *state, struct mutex *mutex,
 			void *data, size_t len,
 			struct selinux_policy **newpolicyp);
-void selinux_policy_commit(struct selinux_state *state,
+void selinux_policy_commit(struct selinux_state *state, struct mutex *mutex,
 			struct selinux_policy *newpolicy);
-void selinux_policy_cancel(struct selinux_state *state,
+void selinux_policy_cancel(struct selinux_state *state, struct mutex *mutex,
 			struct selinux_policy *policy);
 int security_read_policy(struct selinux_state *state,
 			 void **data, size_t *len);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 131816878e50..a054683359dd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -560,7 +560,8 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
 	if (copy_from_user(data, buf, count) != 0)
 		goto out;
 
-	length = security_load_policy(fsi->state, data, count, &newpolicy);
+	length = security_load_policy(fsi->state, &fsi->mutex, data, count,
+				&newpolicy);
 	if (length) {
 		pr_warn_ratelimited("SELinux: failed to load policy\n");
 		goto out;
@@ -568,11 +569,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
 
 	length = sel_make_policy_nodes(fsi, newpolicy);
 	if (length) {
-		selinux_policy_cancel(fsi->state, newpolicy);
+		selinux_policy_cancel(fsi->state, &fsi->mutex, newpolicy);
 		goto out1;
 	}
 
-	selinux_policy_commit(fsi->state, newpolicy);
+	selinux_policy_commit(fsi->state, &fsi->mutex, newpolicy);
 
 	length = count;
 
@@ -1309,8 +1310,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 
 	length = 0;
 	if (new_value && fsi->bool_pending_values)
-		length = security_set_bools(fsi->state, fsi->bool_num,
-					    fsi->bool_pending_values);
+		length = security_set_bools(fsi->state, &fsi->mutex,
+					fsi->bool_num,
+					fsi->bool_pending_values);
 
 	if (!length)
 		length = count;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 838161462756..a9fff3592768 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2159,17 +2159,13 @@ static void selinux_policy_cond_free(struct selinux_policy *policy)
 }
 
 void selinux_policy_cancel(struct selinux_state *state,
+			struct mutex *mutex,
 			struct selinux_policy *policy)
 {
 	struct selinux_policy *oldpolicy;
 
-	/*
-	 * NOTE: We do not need to take the rcu read lock
-	 * around the code below because other policy-modifying
-	 * operations are already excluded by selinuxfs via
-	 * fsi->mutex.
-	 */
-	oldpolicy = rcu_dereference_check(state->policy, 1);
+	oldpolicy = rcu_dereference_protected(state->policy,
+					lockdep_is_held(mutex));
 
 	sidtab_cancel_convert(oldpolicy->sidtab);
 	selinux_policy_free(policy);
@@ -2187,18 +2183,14 @@ static void selinux_notify_policy_change(struct selinux_state *state,
 }
 
 void selinux_policy_commit(struct selinux_state *state,
+			struct mutex *mutex,
 			struct selinux_policy *newpolicy)
 {
 	struct selinux_policy *oldpolicy;
 	u32 seqno;
 
-	/*
-	 * NOTE: We do not need to take the rcu read lock
-	 * around the code below because other policy-modifying
-	 * operations are already excluded by selinuxfs via
-	 * fsi->mutex.
-	 */
-	oldpolicy = rcu_dereference_check(state->policy, 1);
+	oldpolicy = rcu_dereference_protected(state->policy,
+					lockdep_is_held(mutex));
 
 	/* If switching between different policy types, log MLS status */
 	if (oldpolicy) {
@@ -2249,7 +2241,8 @@ void selinux_policy_commit(struct selinux_state *state,
  * This function will flush the access vector cache after
  * loading the new policy.
  */
-int security_load_policy(struct selinux_state *state, void *data, size_t len,
+int security_load_policy(struct selinux_state *state, struct mutex *mutex,
+			void *data, size_t len,
 			struct selinux_policy **newpolicyp)
 {
 	struct selinux_policy *newpolicy, *oldpolicy;
@@ -2289,13 +2282,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
 		return 0;
 	}
 
-	/*
-	 * NOTE: We do not need to take the rcu read lock
-	 * around the code below because other policy-modifying
-	 * operations are already excluded by selinuxfs via
-	 * fsi->mutex.
-	 */
-	oldpolicy = rcu_dereference_check(state->policy, 1);
+	oldpolicy = rcu_dereference_protected(state->policy,
+					lockdep_is_held(mutex));
 
 	/* Preserve active boolean values from the old policy */
 	rc = security_preserve_bools(oldpolicy, newpolicy);
@@ -2992,7 +2980,8 @@ int security_get_bools(struct selinux_policy *policy,
 }
 
 
-int security_set_bools(struct selinux_state *state, u32 len, int *values)
+int security_set_bools(struct selinux_state *state, struct mutex *mutex,
+		u32 len, int *values)
 {
 	struct selinux_policy *newpolicy, *oldpolicy;
 	int rc;
@@ -3001,14 +2990,8 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
 	if (!selinux_initialized(state))
 		return -EINVAL;
 
-	/*
-	 * NOTE: We do not need to take the rcu read lock
-	 * around the code below because other policy-modifying
-	 * operations are already excluded by selinuxfs via
-	 * fsi->mutex.
-	 */
-
-	oldpolicy = rcu_dereference_check(state->policy, 1);
+	oldpolicy = rcu_dereference_protected(state->policy,
+					lockdep_is_held(mutex));
 
 	/* Consistency check on number of booleans, should never fail */
 	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
-- 
2.25.1




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux