#include "audit.h"
 #include "policycap_names.h"
 
-static struct selinux_ss selinux_ss;
-
-void selinux_ss_init(struct selinux_ss **ss)
-{
-       rwlock_init(&selinux_ss.policy_rwlock);
-       *ss = &selinux_ss;
-}
-
 /* Forward declaration. */
 static int context_struct_to_string(struct policydb *policydb,
                                    struct context *context,
 int security_mls_enabled(struct selinux_state *state)
 {
        int mls_enabled;
+       struct selinux_policy *policy;
 
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       mls_enabled = state->ss->policy->policydb.mls_enabled;
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       mls_enabled = policy->policydb.mls_enabled;
+       rcu_read_unlock();
        return mls_enabled;
 }
 
 }
 
 static int security_validtrans_handle_fail(struct selinux_state *state,
-                                          struct sidtab_entry *oentry,
-                                          struct sidtab_entry *nentry,
-                                          struct sidtab_entry *tentry,
-                                          u16 tclass)
+                                       struct selinux_policy *policy,
+                                       struct sidtab_entry *oentry,
+                                       struct sidtab_entry *nentry,
+                                       struct sidtab_entry *tentry,
+                                       u16 tclass)
 {
-       struct policydb *p = &state->ss->policy->policydb;
-       struct sidtab *sidtab = state->ss->policy->sidtab;
+       struct policydb *p = &policy->policydb;
+       struct sidtab *sidtab = policy->sidtab;
        char *o = NULL, *n = NULL, *t = NULL;
        u32 olen, nlen, tlen;
 
                                          u32 oldsid, u32 newsid, u32 tasksid,
                                          u16 orig_tclass, bool user)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct sidtab_entry *oentry;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
+       rcu_read_lock();
 
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        if (!user)
-               tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+               tclass = unmap_class(&policy->map, orig_tclass);
        else
                tclass = orig_tclass;
 
                                rc = -EPERM;
                        else
                                rc = security_validtrans_handle_fail(state,
-                                                                    oentry,
-                                                                    nentry,
-                                                                    tentry,
-                                                                    tclass);
+                                                               policy,
+                                                               oentry,
+                                                               nentry,
+                                                               tentry,
+                                                               tclass);
                        goto out;
                }
                constraint = constraint->next;
        }
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 int security_bounded_transition(struct selinux_state *state,
                                u32 old_sid, u32 new_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct sidtab_entry *old_entry, *new_entry;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        rc = -EINVAL;
        old_entry = sidtab_search_entry(sidtab, old_sid);
                kfree(old_name);
        }
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
 
        return rc;
 }
 
-static void avd_init(struct selinux_state *state, struct av_decision *avd)
+static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
 {
        avd->allowed = 0;
        avd->auditallow = 0;
        avd->auditdeny = 0xffffffff;
-       avd->seqno = state->ss->latest_granting;
+       if (policy)
+               avd->seqno = policy->latest_granting;
+       else
+               avd->seqno = 0;
        avd->flags = 0;
 }
 
                                      u8 driver,
                                      struct extended_perms_decision *xpermd)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        u16 tclass;
        memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
        memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
 
-       read_lock(&state->ss->policy_rwlock);
+       rcu_read_lock();
        if (!selinux_initialized(state))
                goto allow;
 
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        scontext = sidtab_search(sidtab, ssid);
        if (!scontext) {
                goto out;
        }
 
-       tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+       tclass = unmap_class(&policy->map, orig_tclass);
        if (unlikely(orig_tclass && !tclass)) {
                if (policydb->allow_unknown)
                        goto allow;
                }
        }
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
                         struct av_decision *avd,
                         struct extended_perms *xperms)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        u16 tclass;
        struct context *scontext = NULL, *tcontext = NULL;
 
-       read_lock(&state->ss->policy_rwlock);
-       avd_init(state, avd);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       avd_init(policy, avd);
        xperms->len = 0;
        if (!selinux_initialized(state))
                goto allow;
 
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        scontext = sidtab_search(sidtab, ssid);
        if (!scontext) {
                goto out;
        }
 
-       tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+       tclass = unmap_class(&policy->map, orig_tclass);
        if (unlikely(orig_tclass && !tclass)) {
                if (policydb->allow_unknown)
                        goto allow;
        }
        context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
                                  xperms);
-       map_decision(&state->ss->policy->map, orig_tclass, avd,
+       map_decision(&policy->map, orig_tclass, avd,
                     policydb->allow_unknown);
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        avd->allowed = 0xffffffff;
                              u16 tclass,
                              struct av_decision *avd)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct context *scontext = NULL, *tcontext = NULL;
 
-       read_lock(&state->ss->policy_rwlock);
-       avd_init(state, avd);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       avd_init(policy, avd);
        if (!selinux_initialized(state))
                goto allow;
 
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        scontext = sidtab_search(sidtab, ssid);
        if (!scontext) {
        context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
                                  NULL);
  out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return;
 allow:
        avd->allowed = 0xffffffff;
 
 int security_sidtab_hash_stats(struct selinux_state *state, char *page)
 {
+       struct selinux_policy *policy;
        int rc;
 
        if (!selinux_initialized(state)) {
                return -EINVAL;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-       rc = sidtab_hash_stats(state->ss->policy->sidtab, page);
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       rc = sidtab_hash_stats(policy->sidtab, page);
+       rcu_read_unlock();
 
        return rc;
 }
                                        u32 *scontext_len, int force,
                                        int only_invalid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct sidtab_entry *entry;
                       "load_policy on unknown SID %d\n", __func__, sid);
                return -EINVAL;
        }
-       read_lock(&state->ss->policy_rwlock);
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        if (force)
                entry = sidtab_search_entry_force(sidtab, sid);
                                    scontext_len);
 
 out_unlock:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 
 }
                                        u32 *sid, u32 def_sid, gfp_t gfp_flags,
                                        int force)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        char *scontext2, *str = NULL;
                if (!str)
                        goto out;
        }
-       read_lock(&state->ss->policy_rwlock);
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
        rc = string_to_context_struct(policydb, sidtab, scontext2,
                                      &context, def_sid);
        if (rc == -EINVAL && force) {
        rc = sidtab_context_to_sid(sidtab, &context, sid);
        context_destroy(&context);
 out_unlock:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
 out:
        kfree(scontext2);
        kfree(str);
 
 static int compute_sid_handle_invalid_context(
        struct selinux_state *state,
+       struct selinux_policy *policy,
        struct sidtab_entry *sentry,
        struct sidtab_entry *tentry,
        u16 tclass,
        struct context *newcontext)
 {
-       struct policydb *policydb = &state->ss->policy->policydb;
-       struct sidtab *sidtab = state->ss->policy->sidtab;
+       struct policydb *policydb = &policy->policydb;
+       struct sidtab *sidtab = policy->sidtab;
        char *s = NULL, *t = NULL, *n = NULL;
        u32 slen, tlen, nlen;
        struct audit_buffer *ab;
                                u32 *out_sid,
                                bool kern)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct class_datum *cladatum = NULL;
 
        context_init(&newcontext);
 
-       read_lock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+
+       policy = rcu_dereference(state->policy);
 
        if (kern) {
-               tclass = unmap_class(&state->ss->policy->map, orig_tclass);
+               tclass = unmap_class(&policy->map, orig_tclass);
                sock = security_is_socket_class(orig_tclass);
        } else {
                tclass = orig_tclass;
-               sock = security_is_socket_class(map_class(&state->ss->policy->map,
+               sock = security_is_socket_class(map_class(&policy->map,
                                                          tclass));
        }
 
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        sentry = sidtab_search_entry(sidtab, ssid);
        if (!sentry) {
 
        /* Check the validity of the context. */
        if (!policydb_context_isvalid(policydb, &newcontext)) {
-               rc = compute_sid_handle_invalid_context(state, sentry, tentry,
-                                                       tclass, &newcontext);
+               rc = compute_sid_handle_invalid_context(state, policy, sentry,
+                                                       tentry, tclass,
+                                                       &newcontext);
                if (rc)
                        goto out_unlock;
        }
        /* Obtain the sid for the context. */
        rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
 out_unlock:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        context_destroy(&newcontext);
 out:
        return rc;
 
 static inline int convert_context_handle_invalid_context(
        struct selinux_state *state,
+       struct policydb *policydb,
        struct context *context)
 {
-       struct policydb *policydb = &state->ss->policy->policydb;
        char *s;
        u32 len;
 
 
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(args->newp, newc)) {
-               rc = convert_context_handle_invalid_context(args->state, oldc);
+               rc = convert_context_handle_invalid_context(args->state,
+                                                       args->oldp,
+                                                       oldc);
                if (rc)
                        goto bad;
        }
        return 0;
 }
 
-static void security_load_policycaps(struct selinux_state *state)
+static void security_load_policycaps(struct selinux_state *state,
+                               struct selinux_policy *policy)
 {
        struct policydb *p;
        unsigned int i;
        struct ebitmap_node *node;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       p = &state->ss->policy->policydb;
+       p = &policy->policydb;
 
        for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
                state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
                        pr_info("SELinux:  unknown policy capability %u\n",
                                i);
        }
-
-       read_unlock(&state->ss->policy_rwlock);
 }
 
-static int security_preserve_bools(struct selinux_state *state,
-                                  struct policydb *newpolicydb);
+static int security_preserve_bools(struct selinux_policy *oldpolicy,
+                               struct selinux_policy *newpolicy);
 
 static void selinux_policy_free(struct selinux_policy *policy)
 {
        kfree(policy);
 }
 
+static void selinux_policy_cond_free(struct selinux_policy *policy)
+{
+       cond_policydb_destroy_dup(&policy->policydb);
+       kfree(policy);
+}
+
 void selinux_policy_cancel(struct selinux_state *state,
                        struct selinux_policy *policy)
 {
-       sidtab_cancel_convert(state->ss->policy->sidtab);
+       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);
+
+       sidtab_cancel_convert(oldpolicy->sidtab);
        selinux_policy_free(policy);
 }
 
        u32 seqno;
 
        /*
-        * NOTE: We do not need to take the policy read-lock
+        * 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);
 
        /* If switching between different policy types, log MLS status */
-       oldpolicy = state->ss->policy;
        if (oldpolicy) {
                if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
                        pr_info("SELinux: Disabling MLS support...\n");
                        pr_info("SELinux: Enabling MLS support...\n");
        }
 
+       /* Set latest granting seqno for new policy. */
+       if (oldpolicy)
+               newpolicy->latest_granting = oldpolicy->latest_granting + 1;
+       else
+               newpolicy->latest_granting = 1;
+       seqno = newpolicy->latest_granting;
+
        /* Install the new policy. */
-       write_lock_irq(&state->ss->policy_rwlock);
-       state->ss->policy = newpolicy;
-       seqno = ++state->ss->latest_granting;
-       write_unlock_irq(&state->ss->policy_rwlock);
+       rcu_assign_pointer(state->policy, newpolicy);
 
        /* Load the policycaps from the new policy */
-       security_load_policycaps(state);
+       security_load_policycaps(state, newpolicy);
 
        if (!selinux_initialized(state)) {
                /*
        }
 
        /* Free the old policy */
+       synchronize_rcu();
        selinux_policy_free(oldpolicy);
 
        /* Notify others of the policy change */
 int security_load_policy(struct selinux_state *state, void *data, size_t len,
                        struct selinux_policy **newpolicyp)
 {
-       struct selinux_policy *newpolicy;
+       struct selinux_policy *newpolicy, *oldpolicy;
        struct sidtab_convert_params convert_params;
        struct convert_context_args args;
        int rc = 0;
                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);
+
        /* Preserve active boolean values from the old policy */
-       rc = security_preserve_bools(state, &newpolicy->policydb);
+       rc = security_preserve_bools(oldpolicy, newpolicy);
        if (rc) {
                pr_err("SELinux:  unable to preserve booleans\n");
                goto err;
        /*
         * Convert the internal representations of contexts
         * in the new SID table.
-        *
-        * NOTE: We do not need to take the policy read-lock
-        * around the code below because other policy-modifying
-        * operations are already excluded by selinuxfs via
-        * fsi->mutex.
         */
        args.state = state;
-       args.oldp = &state->ss->policy->policydb;
+       args.oldp = &oldpolicy->policydb;
        args.newp = &newpolicy->policydb;
 
        convert_params.func = convert_context;
        convert_params.args = &args;
        convert_params.target = newpolicy->sidtab;
 
-       rc = sidtab_convert(state->ss->policy->sidtab, &convert_params);
+       rc = sidtab_convert(oldpolicy->sidtab, &convert_params);
        if (rc) {
                pr_err("SELinux:  unable to convert the internal"
                        " representation of contexts in the new SID"
 
 size_t security_policydb_len(struct selinux_state *state)
 {
+       struct selinux_policy *policy;
        size_t len;
 
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       len = state->ss->policy->policydb.len;
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       len = policy->policydb.len;
+       rcu_read_unlock();
 
        return len;
 }
 int security_port_sid(struct selinux_state *state,
                      u8 protocol, u16 port, u32 *out_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct ocontext *c;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        c = policydb->ocontexts[OCON_PORT];
        while (c) {
        }
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 int security_ib_pkey_sid(struct selinux_state *state,
                         u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct ocontext *c;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        c = policydb->ocontexts[OCON_IBPKEY];
        while (c) {
                *out_sid = SECINITSID_UNLABELED;
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 int security_ib_endport_sid(struct selinux_state *state,
                            const char *dev_name, u8 port_num, u32 *out_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct ocontext *c;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        c = policydb->ocontexts[OCON_IBENDPORT];
        while (c) {
                *out_sid = SECINITSID_UNLABELED;
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 int security_netif_sid(struct selinux_state *state,
                       char *name, u32 *if_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        int rc = 0;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        c = policydb->ocontexts[OCON_NETIF];
        while (c) {
                *if_sid = SECINITSID_NETIF;
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
                      u32 addrlen,
                      u32 *out_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        int rc;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        switch (domain) {
        case AF_INET: {
 
        rc = 0;
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
                           u32 **sids,
                           u32 *nel)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct context *fromcon, usercon;
        if (!selinux_initialized(state))
                goto out;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        context_init(&usercon);
 
        }
        rc = 0;
 out_unlock:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        if (rc || !mynel) {
                kfree(mysids);
                goto out;
                       u16 orig_sclass,
                       u32 *sid)
 {
+       struct selinux_policy *policy;
        int retval;
 
        if (!selinux_initialized(state)) {
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-       retval = __security_genfs_sid(state->ss->policy,
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       retval = __security_genfs_sid(policy,
                                fstype, path, orig_sclass, sid);
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return retval;
 }
 
  */
 int security_fs_use(struct selinux_state *state, struct super_block *sb)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        int rc = 0;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        c = policydb->ocontexts[OCON_FSUSE];
        while (c) {
                }
                sbsec->sid = c->sid[0];
        } else {
-               rc = __security_genfs_sid(state->ss->policy, fstype, "/",
+               rc = __security_genfs_sid(policy, fstype, "/",
                                        SECCLASS_DIR, &sbsec->sid);
                if (rc) {
                        sbsec->behavior = SECURITY_FS_USE_NONE;
        }
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
                return -EINVAL;
 
        /*
-        * NOTE: We do not need to take the policy read-lock
+        * 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);
+
        /* Consistency check on number of booleans, should never fail */
-       if (WARN_ON(len != state->ss->policy->policydb.p_bools.nprim))
+       if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
                return -EINVAL;
 
-       newpolicy = kmemdup(state->ss->policy, sizeof(*newpolicy),
-                       GFP_KERNEL);
+       newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
        if (!newpolicy)
                return -ENOMEM;
 
-       oldpolicy = state->ss->policy;
-
        /*
         * Deep copy only the parts of the policydb that might be
         * modified as a result of changing booleans.
        /* Re-evaluate the conditional rules in the copy */
        evaluate_cond_nodes(&newpolicy->policydb);
 
+       /* Set latest granting seqno for new policy */
+       newpolicy->latest_granting = oldpolicy->latest_granting + 1;
+       seqno = newpolicy->latest_granting;
+
        /* Install the new policy */
-       write_lock_irq(&state->ss->policy_rwlock);
-       state->ss->policy = newpolicy;
-       seqno = ++state->ss->latest_granting;
-       write_unlock_irq(&state->ss->policy_rwlock);
+       rcu_assign_pointer(state->policy, newpolicy);
 
        /*
         * Free the conditional portions of the old policydb
-        * that were copied for the new policy.
+        * that were copied for the new policy, and the oldpolicy
+        * structure itself but not what it references.
         */
-       cond_policydb_destroy_dup(&oldpolicy->policydb);
-
-       /* Free the old policy structure but not what it references. */
-       kfree(oldpolicy);
+       synchronize_rcu();
+       selinux_policy_cond_free(oldpolicy);
 
        /* Notify others of the policy change */
        selinux_notify_policy_change(state, seqno);
 int security_get_bool_value(struct selinux_state *state,
                            u32 index)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        int rc;
        u32 len;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
 
        rc = -EFAULT;
        len = policydb->p_bools.nprim;
 
        rc = policydb->bool_val_to_struct[index]->state;
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
-static int security_preserve_bools(struct selinux_state *state,
-                                  struct policydb *policydb)
+static int security_preserve_bools(struct selinux_policy *oldpolicy,
+                               struct selinux_policy *newpolicy)
 {
        int rc, *bvalues = NULL;
        char **bnames = NULL;
        struct cond_bool_datum *booldatum;
        u32 i, nbools = 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       rc = security_get_bools(state->ss->policy, &nbools, &bnames, &bvalues);
-       read_unlock(&state->ss->policy_rwlock);
+       rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
        if (rc)
                goto out;
        for (i = 0; i < nbools; i++) {
-               booldatum = symtab_search(&policydb->p_bools, bnames[i]);
+               booldatum = symtab_search(&newpolicy->policydb.p_bools,
+                                       bnames[i]);
                if (booldatum)
                        booldatum->state = bvalues[i];
        }
-       evaluate_cond_nodes(policydb);
+       evaluate_cond_nodes(&newpolicy->policydb);
 
 out:
        if (bnames) {
 int security_sid_mls_copy(struct selinux_state *state,
                          u32 sid, u32 mls_sid, u32 *new_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        struct context *context1;
 
        context_init(&newcon);
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        if (!policydb->mls_enabled) {
                *new_sid = sid;
 
        /* Check the validity of the new context. */
        if (!policydb_context_isvalid(policydb, &newcon)) {
-               rc = convert_context_handle_invalid_context(state, &newcon);
+               rc = convert_context_handle_invalid_context(state, policydb,
+                                                       &newcon);
                if (rc) {
                        if (!context_struct_to_string(policydb, &newcon, &s,
                                                      &len)) {
        }
        rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
 out_unlock:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        context_destroy(&newcon);
 out:
        return rc;
                                 u32 xfrm_sid,
                                 u32 *peer_sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        int rc;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        /*
         * We don't need to check initialized here since the only way both
         * expressive */
        *peer_sid = xfrm_sid;
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 
 int security_get_reject_unknown(struct selinux_state *state)
 {
+       struct selinux_policy *policy;
        int value;
 
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       value = state->ss->policy->policydb.reject_unknown;
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       value = policy->policydb.reject_unknown;
+       rcu_read_unlock();
        return value;
 }
 
 int security_get_allow_unknown(struct selinux_state *state)
 {
+       struct selinux_policy *policy;
        int value;
 
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       value = state->ss->policy->policydb.allow_unknown;
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       value = policy->policydb.allow_unknown;
+       rcu_read_unlock();
        return value;
 }
 
 int security_policycap_supported(struct selinux_state *state,
                                 unsigned int req_cap)
 {
+       struct selinux_policy *policy;
        int rc;
 
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-       rc = ebitmap_get_bit(&state->ss->policy->policydb.policycaps, req_cap);
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
+       rcu_read_unlock();
 
        return rc;
 }
 int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
 {
        struct selinux_state *state = &selinux_state;
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct selinux_audit_rule *tmprule;
        struct role_datum *roledatum;
 
        context_init(&tmprule->au_ctxt);
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
 
-       tmprule->au_seqno = state->ss->latest_granting;
+       tmprule->au_seqno = policy->latest_granting;
 
        switch (field) {
        case AUDIT_SUBJ_USER:
        }
        rc = 0;
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
 
        if (rc) {
                selinux_audit_rule_free(tmprule);
 int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
 {
        struct selinux_state *state = &selinux_state;
+       struct selinux_policy *policy;
        struct context *ctxt;
        struct mls_level *level;
        struct selinux_audit_rule *rule = vrule;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+
+       policy = rcu_dereference(state->policy);
 
-       if (rule->au_seqno < state->ss->latest_granting) {
+       if (rule->au_seqno < policy->latest_granting) {
                match = -ESTALE;
                goto out;
        }
 
-       ctxt = sidtab_search(state->ss->policy->sidtab, sid);
+       ctxt = sidtab_search(policy->sidtab, sid);
        if (unlikely(!ctxt)) {
                WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
                          sid);
        }
 
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return match;
 }
 
                                   struct netlbl_lsm_secattr *secattr,
                                   u32 *sid)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        struct sidtab *sidtab;
        int rc;
                return 0;
        }
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
-       sidtab = state->ss->policy->sidtab;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
+       sidtab = policy->sidtab;
 
        if (secattr->flags & NETLBL_SECATTR_CACHE)
                *sid = *(u32 *)secattr->cache->data;
        } else
                *sid = SECSID_NULL;
 
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return 0;
 out_free:
        ebitmap_destroy(&ctx_new.range.level[0].cat);
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 
 int security_netlbl_sid_to_secattr(struct selinux_state *state,
                                   u32 sid, struct netlbl_lsm_secattr *secattr)
 {
+       struct selinux_policy *policy;
        struct policydb *policydb;
        int rc;
        struct context *ctx;
        if (!selinux_initialized(state))
                return 0;
 
-       read_lock(&state->ss->policy_rwlock);
-
-       policydb = &state->ss->policy->policydb;
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       policydb = &policy->policydb;
 
        rc = -ENOENT;
-       ctx = sidtab_search(state->ss->policy->sidtab, sid);
+       ctx = sidtab_search(policy->sidtab, sid);
        if (ctx == NULL)
                goto out;
 
        mls_export_netlbl_lvl(policydb, ctx, secattr);
        rc = mls_export_netlbl_cat(policydb, ctx, secattr);
 out:
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_unlock();
        return rc;
 }
 #endif /* CONFIG_NETLABEL */
 int security_read_policy(struct selinux_state *state,
                         void **data, size_t *len)
 {
+       struct selinux_policy *policy;
        int rc;
        struct policy_file fp;
 
        fp.data = *data;
        fp.len = *len;
 
-       read_lock(&state->ss->policy_rwlock);
-       rc = policydb_write(&state->ss->policy->policydb, &fp);
-       read_unlock(&state->ss->policy_rwlock);
+       rcu_read_lock();
+       policy = rcu_dereference(state->policy);
+       rc = policydb_write(&policy->policydb, &fp);
+       rcu_read_unlock();
 
        if (rc)
                return rc;