summaryrefslogtreecommitdiff
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
authorStephen Smalley <stephen.smalley.work@gmail.com>2020-08-07 16:29:34 +0300
committerPaul Moore <paul@paul-moore.com>2020-08-18 03:50:22 +0300
commit02a52c5c8c3b8cbad0f12009cde9f36dbefb6972 (patch)
treef34ac403da646e27bf0420129e1e6289dcf9c643 /security/selinux/ss/services.c
parent461698026ffa740253b3114891d86eeb54a58bbc (diff)
downloadlinux-02a52c5c8c3b8cbad0f12009cde9f36dbefb6972.tar.xz
selinux: move policy commit after updating selinuxfs
With the refactoring of the policy load logic in the security server from the previous change, it is now possible to split out the committing of the new policy from security_load_policy() and perform it only after successful updating of selinuxfs. Change security_load_policy() to return the newly populated policy data structures to the caller, export selinux_policy_commit() for external callers, and introduce selinux_policy_cancel() to provide a way to cancel the policy load in the event of an error during updating of the selinuxfs directory tree. Further, rework the interfaces used by selinuxfs to get information from the policy when creating the new directory tree to take and act upon the new policy data structure rather than the current/active policy. Update selinuxfs to use these updated and new interfaces. While we are here, stop re-creating the policy_capabilities directory on each policy load since it does not depend on the policy, and stop trying to create the booleans and classes directories during the initial creation of selinuxfs since no information is available until first policy load. After this change, a failure while updating the booleans and class directories will cause the entire policy load to be canceled, leaving the original policy intact, and policy load notifications to userspace will only happen after a successful completion of updating those directories. This does not (yet) provide full atomicity with respect to the updating of the directory trees themselves. Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c85
1 files changed, 41 insertions, 44 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 137d9396742a..a3f26b03c123 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2133,8 +2133,16 @@ static void selinux_policy_free(struct selinux_policy *policy)
kfree(policy);
}
-static void selinux_policy_commit(struct selinux_state *state,
- struct selinux_policy *newpolicy)
+void selinux_policy_cancel(struct selinux_state *state,
+ struct selinux_policy *policy)
+{
+
+ sidtab_cancel_convert(&state->ss->policy->sidtab);
+ selinux_policy_free(policy);
+}
+
+void selinux_policy_commit(struct selinux_state *state,
+ struct selinux_policy *newpolicy)
{
struct selinux_policy *oldpolicy;
u32 seqno;
@@ -2195,7 +2203,8 @@ static 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, void *data, size_t len,
+ struct selinux_policy **newpolicyp)
{
struct selinux_policy *newpolicy;
struct sidtab_convert_params convert_params;
@@ -2226,7 +2235,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
if (!selinux_initialized(state)) {
/* First policy load, so no need to preserve state from old policy */
- selinux_policy_commit(state, newpolicy);
+ *newpolicyp = newpolicy;
return 0;
}
@@ -2262,7 +2271,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
goto err;
}
- selinux_policy_commit(state, newpolicy);
+ *newpolicyp = newpolicy;
return 0;
err:
selinux_policy_free(newpolicy);
@@ -2688,17 +2697,15 @@ out:
* Obtain a SID to use for a file in a filesystem that
* cannot support xattr or use a fixed labeling behavior like
* transition SIDs or task SIDs.
- *
- * The caller must acquire the policy_rwlock before calling this function.
*/
-static inline int __security_genfs_sid(struct selinux_state *state,
+static inline int __security_genfs_sid(struct selinux_policy *policy,
const char *fstype,
char *path,
u16 orig_sclass,
u32 *sid)
{
- struct policydb *policydb = &state->ss->policy->policydb;
- struct sidtab *sidtab = &state->ss->policy->sidtab;
+ struct policydb *policydb = &policy->policydb;
+ struct sidtab *sidtab = &policy->sidtab;
int len;
u16 sclass;
struct genfs *genfs;
@@ -2708,7 +2715,7 @@ static inline int __security_genfs_sid(struct selinux_state *state,
while (path[0] == '/' && path[1] == '/')
path++;
- sclass = unmap_class(&state->ss->policy->map, orig_sclass);
+ sclass = unmap_class(&policy->map, orig_sclass);
*sid = SECINITSID_UNLABELED;
for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
@@ -2763,11 +2770,22 @@ int security_genfs_sid(struct selinux_state *state,
int retval;
read_lock(&state->ss->policy_rwlock);
- retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
+ retval = __security_genfs_sid(state->ss->policy,
+ fstype, path, orig_sclass, sid);
read_unlock(&state->ss->policy_rwlock);
return retval;
}
+int selinux_policy_genfs_sid(struct selinux_policy *policy,
+ const char *fstype,
+ char *path,
+ u16 orig_sclass,
+ u32 *sid)
+{
+ /* no lock required, policy is not yet accessible by other threads */
+ return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
+}
+
/**
* security_fs_use - Determine how to handle labeling for a filesystem.
* @sb: superblock in question
@@ -2803,8 +2821,8 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
}
sbsec->sid = c->sid[0];
} else {
- rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
- &sbsec->sid);
+ rc = __security_genfs_sid(state->ss->policy, fstype, "/",
+ SECCLASS_DIR, &sbsec->sid);
if (rc) {
sbsec->behavior = SECURITY_FS_USE_NONE;
rc = 0;
@@ -2818,23 +2836,14 @@ out:
return rc;
}
-int security_get_bools(struct selinux_state *state,
+int security_get_bools(struct selinux_policy *policy,
u32 *len, char ***names, int **values)
{
struct policydb *policydb;
u32 i;
int rc;
- if (!selinux_initialized(state)) {
- *len = 0;
- *names = NULL;
- *values = NULL;
- return 0;
- }
-
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
*names = NULL;
*values = NULL;
@@ -2865,7 +2874,6 @@ int security_get_bools(struct selinux_state *state,
}
rc = 0;
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
err:
if (*names) {
@@ -2958,7 +2966,9 @@ static int security_preserve_bools(struct selinux_state *state,
struct cond_bool_datum *booldatum;
u32 i, nbools = 0;
- rc = security_get_bools(state, &nbools, &bnames, &bvalues);
+ read_lock(&state->ss->policy_rwlock);
+ rc = security_get_bools(state->ss->policy, &nbools, &bnames, &bvalues);
+ read_unlock(&state->ss->policy_rwlock);
if (rc)
goto out;
for (i = 0; i < nbools; i++) {
@@ -3169,21 +3179,13 @@ static int get_classes_callback(void *k, void *d, void *args)
return 0;
}
-int security_get_classes(struct selinux_state *state,
+int security_get_classes(struct selinux_policy *policy,
char ***classes, int *nclasses)
{
struct policydb *policydb;
int rc;
- if (!selinux_initialized(state)) {
- *nclasses = 0;
- *classes = NULL;
- return 0;
- }
-
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
rc = -ENOMEM;
*nclasses = policydb->p_classes.nprim;
@@ -3201,7 +3203,6 @@ int security_get_classes(struct selinux_state *state,
}
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
}
@@ -3218,16 +3219,14 @@ static int get_permissions_callback(void *k, void *d, void *args)
return 0;
}
-int security_get_permissions(struct selinux_state *state,
+int security_get_permissions(struct selinux_policy *policy,
char *class, char ***perms, int *nperms)
{
struct policydb *policydb;
int rc, i;
struct class_datum *match;
- read_lock(&state->ss->policy_rwlock);
-
- policydb = &state->ss->policy->policydb;
+ policydb = &policy->policydb;
rc = -EINVAL;
match = symtab_search(&policydb->p_classes, class);
@@ -3256,11 +3255,9 @@ int security_get_permissions(struct selinux_state *state,
goto err;
out:
- read_unlock(&state->ss->policy_rwlock);
return rc;
err:
- read_unlock(&state->ss->policy_rwlock);
for (i = 0; i < *nperms; i++)
kfree((*perms)[i]);
kfree(*perms);