From: Peter Enderborg <peter.enderb...@sony.com>

This patch switch to using RCU locks instead of rwlocks. This has
the big advantage that it does not has preempt disable.

Signed-off-by: Peter Enderborg <peter.enderb...@sony.com>
Reported-by: Björn Davidsson <bjorn.davids...@sony.com>
---
 security/selinux/ss/services.c | 162 +++++++++++++++++++++--------------------
 1 file changed, 82 insertions(+), 80 deletions(-)

diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 81c5717..f142ef8 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -87,7 +87,7 @@ int selinux_policycap_alwaysnetwork;
 int selinux_policycap_cgroupseclabel;
 int selinux_policycap_nnp_nosuid_transition;
 
-static DEFINE_RWLOCK(policy_rwlock);
+static DEFINE_SPINLOCK(policy_w_lock);
 
 int ss_initialized;
 
@@ -115,14 +115,14 @@ struct selinux_mapping {
        u32 perms[sizeof(u32) * 8];
 };
 
-struct shared_current_mapping {
+struct shared_rcu_mapping {
        struct selinux_mapping *current_mapping;
        u16 current_mapping_size;
        struct policydb policydb;
        struct sidtab sidtab;
 };
 
-static struct shared_current_mapping *crm;
+static struct shared_rcu_mapping *crm;
 
 static int selinux_set_mapping(struct policydb *pol,
                               struct security_class_mapping *map,
@@ -791,7 +791,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 
newsid, u32 tasksid,
        if (!ss_initialized)
                return 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        if (!user)
                tclass = unmap_class(orig_tclass);
@@ -845,7 +845,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 
newsid, u32 tasksid,
        }
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -879,7 +879,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
        int index;
        int rc;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -EINVAL;
        old_context = sidtab_search(&crm->sidtab, old_sid);
@@ -941,7 +941,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                kfree(old_name);
        }
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 
        return rc;
 }
@@ -1029,7 +1029,7 @@ void security_compute_xperms_decision(u32 ssid,
        memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
        memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        if (!ss_initialized)
                goto allow;
 
@@ -1083,7 +1083,7 @@ void security_compute_xperms_decision(u32 ssid,
                }
        }
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
@@ -1110,7 +1110,7 @@ void security_compute_av(u32 ssid,
        u16 tclass;
        struct context *scontext = NULL, *tcontext = NULL;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        avd_init(avd);
        xperms->len = 0;
        if (!ss_initialized)
@@ -1143,7 +1143,7 @@ void security_compute_av(u32 ssid,
        context_struct_compute_av(scontext, tcontext, tclass, avd, xperms);
        map_decision(orig_tclass, avd, crm->policydb.allow_unknown);
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        avd->allowed = 0xffffffff;
@@ -1157,7 +1157,7 @@ void security_compute_av_user(u32 ssid,
 {
        struct context *scontext = NULL, *tcontext = NULL;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        avd_init(avd);
        if (!ss_initialized)
                goto allow;
@@ -1188,7 +1188,7 @@ void security_compute_av_user(u32 ssid,
 
        context_struct_compute_av(scontext, tcontext, tclass, avd, NULL);
  out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        avd->allowed = 0xffffffff;
@@ -1293,7 +1293,7 @@ static int security_sid_to_context_core(u32 sid, char 
**scontext,
                rc = -EINVAL;
                goto out;
        }
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        if (force)
                context = sidtab_search_force(&crm->sidtab, sid);
        else
@@ -1306,7 +1306,7 @@ static int security_sid_to_context_core(u32 sid, char 
**scontext,
        }
        rc = context_struct_to_string(context, scontext, scontext_len);
 out_unlock:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 out:
        return rc;
 
@@ -1458,7 +1458,7 @@ static int security_context_to_sid_core(const char 
*scontext, u32 scontext_len,
                        goto out;
        }
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        rc = string_to_context_struct(&crm->policydb, &crm->sidtab, scontext2,
                                      scontext_len, &context, def_sid);
        if (rc == -EINVAL && force) {
@@ -1470,7 +1470,7 @@ static int security_context_to_sid_core(const char 
*scontext, u32 scontext_len,
        rc = sidtab_context_to_sid(&crm->sidtab, &context, sid);
        context_destroy(&context);
 out_unlock:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 out:
        kfree(scontext2);
        kfree(str);
@@ -1620,7 +1620,7 @@ static int security_compute_sid(u32 ssid,
 
        context_init(&newcontext);
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        if (kern) {
                tclass = unmap_class(orig_tclass);
@@ -1759,7 +1759,7 @@ static int security_compute_sid(u32 ssid,
        /* Obtain the sid for the context. */
        rc = sidtab_context_to_sid(&crm->sidtab, &newcontext, out_sid);
 out_unlock:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        context_destroy(&newcontext);
 out:
        return rc;
@@ -2051,7 +2051,6 @@ static void security_load_policycaps(struct policydb *pdb)
 }
 
 static int security_preserve_bools(struct policydb *p);
-
 /**
  * security_load_policy - Load a security policy configuration.
  * @data: binary policy data
@@ -2068,17 +2067,17 @@ int security_load_policy(void *data, size_t len)
        struct sidtab oldsidtab, newsidtab;
        struct selinux_mapping *oldmap = NULL, *map = NULL;
        struct convert_context_args args;
-       struct shared_current_mapping *next_rcu;
-       struct shared_current_mapping *old_rcu;
+       struct shared_rcu_mapping *next_rcu;
+       struct shared_rcu_mapping *old_rcu;
        u32 seqno;
        u16 map_size;
        int rc = 0;
        struct policy_file file = { data, len }, *fp = &file;
 
        if (!ss_initialized) {
-               struct shared_current_mapping *first_mapping;
+               struct shared_rcu_mapping *first_mapping;
 
-               first_mapping = kzalloc(sizeof(struct shared_current_mapping),
+               first_mapping = kzalloc(sizeof(struct shared_rcu_mapping),
                                        GFP_KERNEL);
                if (!first_mapping) {
                        rc = -ENOMEM;
@@ -2145,7 +2144,7 @@ int security_load_policy(void *data, size_t len)
                goto out;
        }
 
-       next_rcu = kzalloc(sizeof(struct shared_current_mapping), GFP_KERNEL);
+       next_rcu = kzalloc(sizeof(struct shared_rcu_mapping), GFP_KERNEL);
        if (!next_rcu) {
                kfree(oldpolicydb);
                rc = -ENOMEM;
@@ -2157,7 +2156,7 @@ int security_load_policy(void *data, size_t len)
                goto out;
 
        next_rcu->policydb.len = len;
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        /* If switching between different policy types, log MLS status */
        if (crm->policydb.mls_enabled && !next_rcu->policydb.mls_enabled)
                printk(KERN_INFO "SELinux: Disabling MLS support...\n");
@@ -2210,19 +2209,19 @@ int security_load_policy(void *data, size_t len)
        /* Install the new policydb and SID table. */
        /* next */
        security_load_policycaps(&next_rcu->policydb);
-       read_unlock(&policy_rwlock);
-       write_lock_irq(&policy_rwlock);
        sidtab_set(&next_rcu->sidtab, &newsidtab);
        security_load_policycaps(&next_rcu->policydb);
        oldmap = crm->current_mapping;
+       rcu_read_unlock();
        next_rcu->current_mapping = map;
        next_rcu->current_mapping_size = map_size;
 
+       spin_lock(&policy_w_lock);
        seqno = ++latest_granting;
        old_rcu = crm;
        crm = next_rcu;
-       write_unlock_irq(&policy_rwlock);
-
+       spin_unlock(&policy_w_lock);
+       synchronize_rcu();
        /* Free the old policydb and SID table. */
        policydb_destroy(oldpolicydb);
        sidtab_destroy(&oldsidtab);
@@ -2250,9 +2249,9 @@ size_t security_policydb_len(void)
 {
        size_t len;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        len = crm->policydb.len;
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 
        return len;
 }
@@ -2268,7 +2267,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
        struct ocontext *c;
        int rc = 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        c = crm->policydb.ocontexts[OCON_PORT];
        while (c) {
@@ -2293,7 +2292,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
        }
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2308,7 +2307,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, 
u32 *out_sid)
        struct ocontext *c;
        int rc = 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        c = crm->policydb.ocontexts[OCON_IBPKEY];
        while (c) {
@@ -2333,7 +2332,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, 
u32 *out_sid)
                *out_sid = SECINITSID_UNLABELED;
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2348,7 +2347,7 @@ int security_ib_endport_sid(const char *dev_name, u8 
port_num, u32 *out_sid)
        struct ocontext *c;
        int rc = 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        c = crm->policydb.ocontexts[OCON_IBENDPORT];
        while (c) {
@@ -2374,7 +2373,7 @@ int security_ib_endport_sid(const char *dev_name, u8 
port_num, u32 *out_sid)
                *out_sid = SECINITSID_UNLABELED;
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2388,7 +2387,7 @@ int security_netif_sid(char *name, u32 *if_sid)
        int rc = 0;
        struct ocontext *c;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        c = crm->policydb.ocontexts[OCON_NETIF];
        while (c) {
@@ -2415,7 +2414,7 @@ int security_netif_sid(char *name, u32 *if_sid)
                *if_sid = SECINITSID_NETIF;
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2447,7 +2446,7 @@ int security_node_sid(u16 domain,
        int rc;
        struct ocontext *c;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        switch (domain) {
        case AF_INET: {
@@ -2502,7 +2501,7 @@ int security_node_sid(u16 domain,
 
        rc = 0;
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2541,7 +2540,7 @@ int security_get_user_sids(u32 fromsid,
        if (!ss_initialized)
                goto out;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        context_init(&usercon);
 
@@ -2593,7 +2592,7 @@ int security_get_user_sids(u32 fromsid,
        }
        rc = 0;
 out_unlock:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        if (rc || !mynel) {
                kfree(mysids);
                goto out;
@@ -2704,9 +2703,9 @@ int security_genfs_sid(const char *fstype,
 {
        int retval;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        retval = __security_genfs_sid(fstype, path, orig_sclass, sid);
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return retval;
 }
 
@@ -2721,7 +2720,7 @@ int security_fs_use(struct super_block *sb)
        struct superblock_security_struct *sbsec = sb->s_security;
        const char *fstype = sb->s_type->name;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        c = crm->policydb.ocontexts[OCON_FSUSE];
        while (c) {
@@ -2752,7 +2751,7 @@ int security_fs_use(struct super_block *sb)
        }
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2760,7 +2759,7 @@ int security_get_bools(int *len, char ***names, int 
**values)
 {
        int i, rc;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        *names = NULL;
        *values = NULL;
 
@@ -2790,7 +2789,7 @@ int security_get_bools(int *len, char ***names, int 
**values)
        }
        rc = 0;
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 err:
        if (*names) {
@@ -2803,13 +2802,14 @@ int security_get_bools(int *len, char ***names, int 
**values)
 
 int security_set_bools(int len, int *values)
 {
-       struct shared_current_mapping *next_rcu, *old_rcu;
+
+       struct shared_rcu_mapping *next_rcu, *old_rcu;
        int i, rc;
        int lenp, seqno = 0;
        struct cond_node *cur;
 
-       next_rcu = kzalloc(sizeof(struct shared_current_mapping), GFP_KERNEL);
-       read_lock(&policy_rwlock);
+       next_rcu = kzalloc(sizeof(struct shared_rcu_mapping), GFP_KERNEL);
+       rcu_read_lock();
        old_rcu = crm;
        memcpy(&next_rcu->policydb, &old_rcu->policydb,
               sizeof(struct policydb));
@@ -2842,13 +2842,15 @@ int security_set_bools(int len, int *values)
                if (rc)
                        goto out;
        }
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
+
        rc = 0;
 
-       write_lock_irq(&policy_rwlock);
+       spin_lock(&policy_w_lock);
        seqno = ++latest_granting;
        crm = next_rcu;
-       write_unlock_irq(&policy_rwlock);
+       spin_unlock(&policy_w_lock);
+       synchronize_rcu();
 out:
        if (!rc) {
                avc_ss_reset(seqno);
@@ -2868,7 +2870,7 @@ int security_get_bool_value(int index)
        int rc;
        int len;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -EFAULT;
        len = crm->policydb.p_bools.nprim;
@@ -2877,7 +2879,7 @@ int security_get_bool_value(int index)
 
        rc = crm->policydb.bool_val_to_struct[index]->state;
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -2933,7 +2935,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 
*new_sid)
 
        context_init(&newcon);
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -EINVAL;
        context1 = sidtab_search(&crm->sidtab, sid);
@@ -2975,7 +2977,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 
*new_sid)
 
        rc = sidtab_context_to_sid(&crm->sidtab, &newcon, new_sid);
 out_unlock:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        context_destroy(&newcon);
 out:
        return rc;
@@ -3032,7 +3034,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 
nlbl_type,
        if (!crm->policydb.mls_enabled)
                return 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -EINVAL;
        nlbl_ctx = sidtab_search(&crm->sidtab, nlbl_sid);
@@ -3059,7 +3061,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 
nlbl_type,
         * expressive */
        *peer_sid = xfrm_sid;
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -3080,7 +3082,7 @@ int security_get_classes(char ***classes, int *nclasses)
 {
        int rc;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -ENOMEM;
        *nclasses = crm->policydb.p_classes.nprim;
@@ -3098,7 +3100,7 @@ int security_get_classes(char ***classes, int *nclasses)
        }
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -3120,7 +3122,7 @@ int security_get_permissions(char *class, char ***perms, 
int *nperms)
        int rc, i;
        struct class_datum *match;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -EINVAL;
        match = hashtab_search(crm->policydb.p_classes.table, class);
@@ -3149,11 +3151,11 @@ int security_get_permissions(char *class, char 
***perms, int *nperms)
                goto err;
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 
 err:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        for (i = 0; i < *nperms; i++)
                kfree((*perms)[i]);
        kfree(*perms);
@@ -3184,9 +3186,9 @@ int security_policycap_supported(unsigned int req_cap)
 {
        int rc;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        rc = ebitmap_get_bit(&crm->policydb.policycaps, req_cap);
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 
        return rc;
 }
@@ -3250,7 +3252,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char 
*rulestr, void **vrule)
 
        context_init(&tmprule->au_ctxt);
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        tmprule->au_seqno = latest_granting;
 
@@ -3294,7 +3296,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char 
*rulestr, void **vrule)
        }
        rc = 0;
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 
        if (rc) {
                selinux_audit_rule_free(tmprule);
@@ -3344,7 +3346,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, 
void *vrule,
                return -ENOENT;
        }
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        if (rule->au_seqno < latest_granting) {
                match = -ESTALE;
@@ -3435,7 +3437,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, 
void *vrule,
        }
 
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return match;
 }
 
@@ -3521,7 +3523,7 @@ int security_netlbl_secattr_to_sid(struct 
netlbl_lsm_secattr *secattr,
                return 0;
        }
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        if (secattr->flags & NETLBL_SECATTR_CACHE)
                *sid = *(u32 *)secattr->cache->data;
@@ -3558,12 +3560,12 @@ int security_netlbl_secattr_to_sid(struct 
netlbl_lsm_secattr *secattr,
        } else
                *sid = SECSID_NULL;
 
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return 0;
 out_free:
        ebitmap_destroy(&ctx_new.range.level[0].cat);
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -3585,7 +3587,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct 
netlbl_lsm_secattr *secattr)
        if (!ss_initialized)
                return 0;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
 
        rc = -ENOENT;
        ctx = sidtab_search(&crm->sidtab, sid);
@@ -3604,7 +3606,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct 
netlbl_lsm_secattr *secattr)
        mls_export_netlbl_lvl(&crm->policydb, ctx, secattr);
        rc = mls_export_netlbl_cat(&crm->policydb, ctx, secattr);
 out:
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 #endif /* CONFIG_NETLABEL */
@@ -3632,9 +3634,9 @@ int security_read_policy(void **data, size_t *len)
        fp.data = *data;
        fp.len = *len;
 
-       read_lock(&policy_rwlock);
+       rcu_read_lock();
        rc = policydb_write(&crm->policydb, &fp);
-       read_unlock(&policy_rwlock);
+       rcu_read_unlock();
 
        if (rc)
                return rc;
-- 
2.7.4

Reply via email to