From patchwork Wed May 30 14:11:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Enderborg X-Patchwork-Id: 10439101 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 952B8601E9 for ; Wed, 30 May 2018 14:22:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7C63228E5D for ; Wed, 30 May 2018 14:22:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7003A28E89; Wed, 30 May 2018 14:22:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D6AED28E5D for ; Wed, 30 May 2018 14:22:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751474AbeE3OWx (ORCPT ); Wed, 30 May 2018 10:22:53 -0400 Received: from seldsegrel01.sonyericsson.com ([37.139.156.29]:11378 "EHLO SELDSEGREL01.sonyericsson.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753079AbeE3OVh (ORCPT ); Wed, 30 May 2018 10:21:37 -0400 From: Peter Enderborg To: , Paul Moore , Stephen Smalley , Eric Paris , James Morris , Daniel Jurgens , Doug Ledford , , , , "Serge E . Hallyn" , "Paul E . McKenney" Subject: [PATCH V3 2/5 selinux-next] selinux: Introduce selinux_ruleset struct Date: Wed, 30 May 2018 16:11:01 +0200 Message-ID: <20180530141104.28569-3-peter.enderborg@sony.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180530141104.28569-1-peter.enderborg@sony.com> References: <20180530141104.28569-1-peter.enderborg@sony.com> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This is a preparation for moving locking to rcu type. We move policydb, sidtab and map to this structure which is dynamic allocated. To help out the handlig a policydb_copy are added. It is intended to be used in atomic context within a rcu lock, so there are help functions that do vmalloc allocation that are intended to be on the outside of the lock. hastab_insert had a cond_sched call that is removed. When switched to rcu lock the lock can be preempted. Signed-off-by: Peter Enderborg --- security/selinux/ss/hashtab.c | 1 - security/selinux/ss/policydb.c | 48 +++++++ security/selinux/ss/policydb.h | 6 +- security/selinux/ss/services.c | 292 +++++++++++++++++++++++------------------ security/selinux/ss/services.h | 12 +- 5 files changed, 226 insertions(+), 133 deletions(-) diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 0944b1f8060e..967b6e3d25c6 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -44,7 +44,6 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) u32 hvalue; struct hashtab_node *prev, *cur, *newnode; - cond_resched(); if (!h || h->nel == HASHTAB_MAX_NODES) return -EINVAL; diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2a0e21d8c275..93d134d057a7 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -3535,3 +3535,51 @@ int policydb_write(struct policydb *p, void *fp) return 0; } + +int policydb_flattened_alloc(struct policydb *db, void **tmpbuf, size_t *size) +{ + int rc = 0; + + *size = db->len; + *tmpbuf = vmalloc(*size); + + if (!*tmpbuf) { + rc = -ENOMEM; + printk(KERN_ERR "SELinux: vmalloc failed for %ld\n", *size); + } + return rc; +} + +int policydb_flattened_free(void *tmpbuf) +{ + vfree(tmpbuf); + return 0; +} + +int policydb_copy(struct policydb *olddb, struct policydb *newdb, + void **tmpstorage, size_t size) +{ + struct policy_file fp; + void *data = *tmpstorage; + int rc; + + if (size != olddb->len) { + rc = -EAGAIN; + goto out; + } + fp.data = data; + fp.len = size; + rc = policydb_write(olddb, &fp); + if (rc) + goto out; + + fp.len = size; + fp.data = data; + rc = policydb_read(newdb, &fp); + if (rc) + goto out; + + newdb->len = size; +out: + return rc; +} diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 215f8f30ac5a..3e2f86b5b674 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -320,7 +320,11 @@ extern int policydb_type_isvalid(struct policydb *p, unsigned int type); extern int policydb_role_isvalid(struct policydb *p, unsigned int role); extern int policydb_read(struct policydb *p, void *fp); extern int policydb_write(struct policydb *p, void *fp); - +extern int policydb_copy(struct policydb *olddb, struct policydb *newdb, + void **tmpstorage, size_t size); +extern int policydb_flattened_alloc(struct policydb *db, + void **tmpbuf, size_t *size); +extern int policydb_flattened_free(void *tmpbuf); #define PERM_SYMTAB_SIZE 32 #define POLICYDB_CONFIG_MLS 1 diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8057e19dc15f..4f3ce389084c 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -86,6 +86,10 @@ void selinux_ss_init(struct selinux_ss **ss) { rwlock_init(&selinux_ss.policy_rwlock); mutex_init(&selinux_ss.status_lock); + selinux_ss.active_set = kzalloc(sizeof(struct selinux_ruleset), + GFP_KERNEL); + selinux_ss.active_set->sidtab = kzalloc(sizeof(struct sidtab), + GFP_KERNEL); *ss = &selinux_ss; } @@ -249,7 +253,7 @@ static void map_decision(struct selinux_map *map, int security_mls_enabled(struct selinux_state *state) { - struct policydb *p = &state->ss->policydb; + struct policydb *p = &state->ss->active_set->policydb; return p->mls_enabled; } @@ -733,7 +737,7 @@ static int security_validtrans_handle_fail(struct selinux_state *state, struct context *tcontext, u16 tclass) { - struct policydb *p = &state->ss->policydb; + struct policydb *p = &state->ss->active_set->policydb; char *o = NULL, *n = NULL, *t = NULL; u32 olen, nlen, tlen; @@ -777,11 +781,11 @@ static int security_compute_validatetrans(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; if (!user) - tclass = unmap_class(&state->ss->map, orig_tclass); + tclass = unmap_class(&state->ss->active_set->map, orig_tclass); else tclass = orig_tclass; @@ -877,8 +881,8 @@ int security_bounded_transition(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; rc = -EINVAL; old_context = sidtab_search(sidtab, old_sid); @@ -1035,8 +1039,8 @@ void security_compute_xperms_decision(struct selinux_state *state, if (!state->initialized) goto allow; - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; scontext = sidtab_search(sidtab, ssid); if (!scontext) { @@ -1052,7 +1056,7 @@ void security_compute_xperms_decision(struct selinux_state *state, goto out; } - tclass = unmap_class(&state->ss->map, orig_tclass); + tclass = unmap_class(&state->ss->active_set->map, orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb->allow_unknown) goto allow; @@ -1124,8 +1128,8 @@ void security_compute_av(struct selinux_state *state, if (!state->initialized) goto allow; - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; scontext = sidtab_search(sidtab, ssid); if (!scontext) { @@ -1145,7 +1149,7 @@ void security_compute_av(struct selinux_state *state, goto out; } - tclass = unmap_class(&state->ss->map, orig_tclass); + tclass = unmap_class(&state->ss->active_set->map, orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb->allow_unknown) goto allow; @@ -1153,7 +1157,7 @@ void security_compute_av(struct selinux_state *state, } context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, xperms); - map_decision(&state->ss->map, orig_tclass, avd, + map_decision(&state->ss->active_set->map, orig_tclass, avd, policydb->allow_unknown); out: read_unlock(&state->ss->policy_rwlock); @@ -1178,8 +1182,8 @@ void security_compute_av_user(struct selinux_state *state, if (!state->initialized) goto allow; - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; scontext = sidtab_search(sidtab, ssid); if (!scontext) { @@ -1316,8 +1320,8 @@ static int security_sid_to_context_core(struct selinux_state *state, goto out; } read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; if (force) context = sidtab_search_force(sidtab, sid); else @@ -1488,8 +1492,8 @@ static int security_context_to_sid_core(struct selinux_state *state, goto out; } read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; rc = string_to_context_struct(policydb, sidtab, scontext2, scontext_len, &context, def_sid); if (rc == -EINVAL && force) { @@ -1576,7 +1580,7 @@ static int compute_sid_handle_invalid_context( u16 tclass, struct context *newcontext) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; char *s = NULL, *t = NULL, *n = NULL; u32 slen, tlen, nlen; @@ -1665,16 +1669,17 @@ static int security_compute_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); if (kern) { - tclass = unmap_class(&state->ss->map, orig_tclass); + tclass = unmap_class(&state->ss->active_set->map, orig_tclass); sock = security_is_socket_class(orig_tclass); } else { + struct selinux_map *amap = &state->ss->active_set->map; tclass = orig_tclass; - sock = security_is_socket_class(map_class(&state->ss->map, + sock = security_is_socket_class(map_class(amap, tclass)); } - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; scontext = sidtab_search(sidtab, ssid); if (!scontext) { @@ -1903,7 +1908,7 @@ static inline int convert_context_handle_invalid_context( struct selinux_state *state, struct context *context) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; char *s; u32 len; @@ -2071,9 +2076,9 @@ static int convert_context(u32 key, goto out; } -static void security_load_policycaps(struct selinux_state *state) +static void security_load_policycaps(struct selinux_state *state, + struct policydb *p) { - struct policydb *p = &state->ss->policydb; unsigned int i; struct ebitmap_node *node; @@ -2107,47 +2112,47 @@ static int security_preserve_bools(struct selinux_state *state, */ int security_load_policy(struct selinux_state *state, void *data, size_t len) { - struct policydb *policydb; - struct sidtab *sidtab; - struct policydb *oldpolicydb, *newpolicydb; - struct sidtab oldsidtab, newsidtab; - struct selinux_mapping *oldmapping; struct selinux_map newmap; struct convert_context_args args; u32 seqno; int rc = 0; + struct selinux_ruleset *next_set, *old_set; struct policy_file file = { data, len }, *fp = &file; - oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); - if (!oldpolicydb) { + next_set = kzalloc(sizeof(struct selinux_ruleset), GFP_KERNEL); + if (!next_set) { rc = -ENOMEM; goto out; } - newpolicydb = oldpolicydb + 1; - - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + next_set->sidtab = kzalloc(sizeof(struct sidtab), GFP_KERNEL); + if (!next_set->sidtab) { + rc = -ENOMEM; + kfree(next_set); + goto out; + } if (!state->initialized) { - rc = policydb_read(policydb, fp); + old_set = state->ss->active_set; + rc = policydb_read(&next_set->policydb, fp); if (rc) goto out; - policydb->len = len; - rc = selinux_set_mapping(policydb, secclass_map, - &state->ss->map); + next_set->policydb.len = len; + rc = selinux_set_mapping(&next_set->policydb, secclass_map, + &next_set->map); if (rc) { - policydb_destroy(policydb); + policydb_destroy(&next_set->policydb); goto out; } - rc = policydb_load_isids(policydb, sidtab); + rc = policydb_load_isids(&next_set->policydb, next_set->sidtab); if (rc) { - policydb_destroy(policydb); + policydb_destroy(&next_set->policydb); goto out; } - security_load_policycaps(state); + security_load_policycaps(state, &next_set->policydb); + state->ss->active_set = next_set; state->initialized = 1; seqno = ++state->ss->latest_granting; selinux_complete_init(); @@ -2156,45 +2161,48 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) selinux_status_update_policyload(state, seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); + kfree(old_set->sidtab); + kfree(old_set); goto out; } - + old_set = state->ss->active_set; #if 0 sidtab_hash_eval(sidtab, "sids"); #endif - rc = policydb_read(newpolicydb, fp); + rc = policydb_read(&next_set->policydb, fp); if (rc) goto out; - newpolicydb->len = len; + next_set->policydb.len = len; + /* If switching between different policy types, log MLS status */ - if (policydb->mls_enabled && !newpolicydb->mls_enabled) + if (old_set->policydb.mls_enabled && !next_set->policydb.mls_enabled) printk(KERN_INFO "SELinux: Disabling MLS support...\n"); - else if (!policydb->mls_enabled && newpolicydb->mls_enabled) + else if (!old_set->policydb.mls_enabled + && next_set->policydb.mls_enabled) printk(KERN_INFO "SELinux: Enabling MLS support...\n"); - - rc = policydb_load_isids(newpolicydb, &newsidtab); + rc = policydb_load_isids(&next_set->policydb, next_set->sidtab); if (rc) { printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); - policydb_destroy(newpolicydb); + policydb_destroy(&next_set->policydb); goto out; } - rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap); + rc = selinux_set_mapping(&next_set->policydb, secclass_map, &newmap); if (rc) goto err; - rc = security_preserve_bools(state, newpolicydb); + rc = security_preserve_bools(state, &next_set->policydb); if (rc) { printk(KERN_ERR "SELinux: unable to preserve booleans\n"); goto err; } /* Clone the SID table. */ - sidtab_shutdown(sidtab); + sidtab_shutdown(old_set->sidtab); - rc = sidtab_map(sidtab, clone_sid, &newsidtab); + rc = sidtab_map(old_set->sidtab, clone_sid, next_set->sidtab); if (rc) goto err; @@ -2203,9 +2211,9 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) * in the new SID table. */ args.state = state; - args.oldp = policydb; - args.newp = newpolicydb; - rc = sidtab_map(&newsidtab, convert_context, &args); + args.oldp = &old_set->policydb; + args.newp = &next_set->policydb; + rc = sidtab_map(next_set->sidtab, convert_context, &args); if (rc) { printk(KERN_ERR "SELinux: unable to convert the internal" " representation of contexts in the new SID" @@ -2213,48 +2221,43 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len) goto err; } - /* Save the old policydb and SID table to free later. */ - memcpy(oldpolicydb, policydb, sizeof(*policydb)); - sidtab_set(&oldsidtab, sidtab); + next_set->map.mapping = newmap.mapping; + next_set->map.size = newmap.size; /* Install the new policydb and SID table. */ write_lock_irq(&state->ss->policy_rwlock); - memcpy(policydb, newpolicydb, sizeof(*policydb)); - sidtab_set(sidtab, &newsidtab); - security_load_policycaps(state); - oldmapping = state->ss->map.mapping; - state->ss->map.mapping = newmap.mapping; - state->ss->map.size = newmap.size; + security_load_policycaps(state, &next_set->policydb); seqno = ++state->ss->latest_granting; + state->ss->active_set = next_set; write_unlock_irq(&state->ss->policy_rwlock); - /* Free the old policydb and SID table. */ - policydb_destroy(oldpolicydb); - sidtab_destroy(&oldsidtab); - kfree(oldmapping); - avc_ss_reset(state->avc, seqno); selnl_notify_policyload(seqno); selinux_status_update_policyload(state, seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); + /* Free the old policydb and SID table. */ + policydb_destroy(&old_set->policydb); + sidtab_destroy(old_set->sidtab); + kfree(old_set->sidtab); + kfree(old_set->map.mapping); + kfree(old_set); rc = 0; goto out; err: kfree(newmap.mapping); - sidtab_destroy(&newsidtab); - policydb_destroy(newpolicydb); - + sidtab_destroy(next_set->sidtab); + policydb_destroy(&next_set->policydb); + kfree(next_set); out: - kfree(oldpolicydb); return rc; } size_t security_policydb_len(struct selinux_state *state) { - struct policydb *p = &state->ss->policydb; + struct policydb *p = &state->ss->active_set->policydb; size_t len; read_lock(&state->ss->policy_rwlock); @@ -2280,8 +2283,8 @@ int security_port_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; c = policydb->ocontexts[OCON_PORT]; while (c) { @@ -2326,8 +2329,8 @@ int security_ib_pkey_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; c = policydb->ocontexts[OCON_IBPKEY]; while (c) { @@ -2372,8 +2375,8 @@ int security_ib_endport_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; c = policydb->ocontexts[OCON_IBENDPORT]; while (c) { @@ -2418,8 +2421,8 @@ int security_netif_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; c = policydb->ocontexts[OCON_NETIF]; while (c) { @@ -2483,8 +2486,8 @@ int security_node_sid(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; switch (domain) { case AF_INET: { @@ -2583,8 +2586,8 @@ int security_get_user_sids(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; context_init(&usercon); @@ -2685,8 +2688,8 @@ static inline int __security_genfs_sid(struct selinux_state *state, u16 orig_sclass, u32 *sid) { - struct policydb *policydb = &state->ss->policydb; - struct sidtab *sidtab = &state->ss->sidtab; + struct policydb *policydb = &state->ss->active_set->policydb; + struct sidtab *sidtab = state->ss->active_set->sidtab; int len; u16 sclass; struct genfs *genfs; @@ -2696,7 +2699,7 @@ static inline int __security_genfs_sid(struct selinux_state *state, while (path[0] == '/' && path[1] == '/') path++; - sclass = unmap_class(&state->ss->map, orig_sclass); + sclass = unmap_class(&state->ss->active_set->map, orig_sclass); *sid = SECINITSID_UNLABELED; for (genfs = policydb->genfs; genfs; genfs = genfs->next) { @@ -2771,8 +2774,8 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; - sidtab = &state->ss->sidtab; + policydb = &state->ss->active_set->policydb; + sidtab = state->ss->active_set->sidtab; c = policydb->ocontexts[OCON_FSUSE]; while (c) { @@ -2821,7 +2824,7 @@ int security_get_bools(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; + policydb = &state->ss->active_set->policydb; *names = NULL; *values = NULL; @@ -2866,53 +2869,86 @@ int security_get_bools(struct selinux_state *state, int security_set_bools(struct selinux_state *state, int len, int *values) { - struct policydb *policydb; int i, rc; int lenp, seqno = 0; struct cond_node *cur; + struct selinux_ruleset *next_set, *old_set = NULL; + void *storage; + size_t size; - write_lock_irq(&state->ss->policy_rwlock); + next_set = kzalloc(sizeof(struct selinux_ruleset), GFP_KERNEL); + if (!next_set) { + rc = -ENOMEM; + goto errout; + } + + rc = policydb_flattened_alloc(&state->ss->active_set->policydb, + &storage, &size); + if (rc) { + kfree(next_set); + goto errout; + } - policydb = &state->ss->policydb; + write_lock_irq(&state->ss->policy_rwlock); + old_set = state->ss->active_set; + memcpy(next_set, old_set, sizeof(struct selinux_ruleset)); + rc = policydb_copy(&old_set->policydb, &next_set->policydb, + &storage, size); + if (rc) + goto out; rc = -EFAULT; - lenp = policydb->p_bools.nprim; + lenp = next_set->policydb.p_bools.nprim; if (len != lenp) goto out; for (i = 0; i < len; i++) { - if (!!values[i] != policydb->bool_val_to_struct[i]->state) { + if (!!values[i] != + next_set->policydb.bool_val_to_struct[i]->state) { audit_log(current->audit_context, GFP_ATOMIC, AUDIT_MAC_CONFIG_CHANGE, "bool=%s val=%d old_val=%d auid=%u ses=%u", - sym_name(policydb, SYM_BOOLS, i), + sym_name(&next_set->policydb, SYM_BOOLS, i), !!values[i], - policydb->bool_val_to_struct[i]->state, + next_set->policydb.bool_val_to_struct[i]->state, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); } if (values[i]) - policydb->bool_val_to_struct[i]->state = 1; + next_set->policydb.bool_val_to_struct[i]->state = 1; else - policydb->bool_val_to_struct[i]->state = 0; + next_set->policydb.bool_val_to_struct[i]->state = 0; } - for (cur = policydb->cond_list; cur; cur = cur->next) { - rc = evaluate_cond_node(policydb, cur); + for (cur = next_set->policydb.cond_list; cur; cur = cur->next) { + rc = evaluate_cond_node(&next_set->policydb, cur); if (rc) goto out; } seqno = ++state->ss->latest_granting; + state->ss->active_set = next_set; rc = 0; out: - write_unlock_irq(&state->ss->policy_rwlock); if (!rc) { + seqno = ++state->ss->latest_granting; + state->ss->active_set = next_set; + rc = 0; + write_unlock_irq(&state->ss->policy_rwlock); avc_ss_reset(state->avc, seqno); selnl_notify_policyload(seqno); selinux_status_update_policyload(state, seqno); selinux_xfrm_notify_policyload(); + policydb_destroy(&old_set->policydb); + kfree(old_set); + } else { + printk(KERN_ERR "SELinux: %s failed %d\n", __func__, rc); + write_unlock_irq(&state->ss->policy_rwlock); + kfree(next_set); } + policydb_flattened_free(storage); + + errout: return rc; } @@ -2925,7 +2961,7 @@ int security_get_bool_value(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); - policydb = &state->ss->policydb; + policydb = &state->ss->active_set->policydb; rc = -EFAULT; len = policydb->p_bools.nprim; @@ -2977,8 +3013,8 @@ static int security_preserve_bools(struct selinux_state *state, int security_sid_mls_copy(struct selinux_state *state, u32 sid, u32 mls_sid, u32 *new_sid) { - struct policydb *policydb = &state->ss->policydb; - struct sidtab *sidtab = &state->ss->sidtab; + struct policydb *policydb = &state->ss->active_set->policydb; + struct sidtab *sidtab = state->ss->active_set->sidtab; struct context *context1; struct context *context2; struct context newcon; @@ -3068,8 +3104,8 @@ int security_net_peersid_resolve(struct selinux_state *state, u32 xfrm_sid, u32 *peer_sid) { - struct policydb *policydb = &state->ss->policydb; - struct sidtab *sidtab = &state->ss->sidtab; + struct policydb *policydb = &state->ss->active_set->policydb; + struct sidtab *sidtab = state->ss->active_set->sidtab; int rc; struct context *nlbl_ctx; struct context *xfrm_ctx; @@ -3146,7 +3182,7 @@ static int get_classes_callback(void *k, void *d, void *args) int security_get_classes(struct selinux_state *state, char ***classes, int *nclasses) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; int rc; if (!state->initialized) { @@ -3193,7 +3229,7 @@ static int get_permissions_callback(void *k, void *d, void *args) int security_get_permissions(struct selinux_state *state, char *class, char ***perms, int *nperms) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; int rc, i; struct class_datum *match; @@ -3239,12 +3275,12 @@ int security_get_permissions(struct selinux_state *state, int security_get_reject_unknown(struct selinux_state *state) { - return state->ss->policydb.reject_unknown; + return state->ss->active_set->policydb.reject_unknown; } int security_get_allow_unknown(struct selinux_state *state) { - return state->ss->policydb.allow_unknown; + return state->ss->active_set->policydb.allow_unknown; } /** @@ -3260,7 +3296,7 @@ int security_get_allow_unknown(struct selinux_state *state) int security_policycap_supported(struct selinux_state *state, unsigned int req_cap) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; int rc; read_lock(&state->ss->policy_rwlock); @@ -3288,7 +3324,7 @@ void selinux_audit_rule_free(void *vrule) int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) { struct selinux_state *state = &selinux_state; - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; struct selinux_audit_rule *tmprule; struct role_datum *roledatum; struct type_datum *typedatum; @@ -3430,7 +3466,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, goto out; } - ctxt = sidtab_search(&state->ss->sidtab, sid); + ctxt = sidtab_search(state->ss->active_set->sidtab, sid); if (unlikely(!ctxt)) { WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", sid); @@ -3592,8 +3628,8 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, struct netlbl_lsm_secattr *secattr, u32 *sid) { - struct policydb *policydb = &state->ss->policydb; - struct sidtab *sidtab = &state->ss->sidtab; + struct policydb *policydb = &state->ss->active_set->policydb; + struct sidtab *sidtab = state->ss->active_set->sidtab; int rc; struct context *ctx; struct context ctx_new; @@ -3661,7 +3697,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, int security_netlbl_sid_to_secattr(struct selinux_state *state, u32 sid, struct netlbl_lsm_secattr *secattr) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; int rc; struct context *ctx; @@ -3671,7 +3707,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state, read_lock(&state->ss->policy_rwlock); rc = -ENOENT; - ctx = sidtab_search(&state->ss->sidtab, sid); + ctx = sidtab_search(state->ss->active_set->sidtab, sid); if (ctx == NULL) goto out; @@ -3700,7 +3736,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state, int security_read_policy(struct selinux_state *state, void **data, size_t *len) { - struct policydb *policydb = &state->ss->policydb; + struct policydb *policydb = &state->ss->active_set->policydb; int rc; struct policy_file fp; diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index 24c7bdcc8075..9219649c70ed 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -23,12 +23,18 @@ struct selinux_map { u16 size; /* array size of mapping */ }; -struct selinux_ss { - struct sidtab sidtab; +/* sidtab is stored as a pointer. We can then choice to + * use the old pointer or create a new sittab. + */ +struct selinux_ruleset { + struct sidtab *sidtab; struct policydb policydb; + struct selinux_map map; +}; +struct selinux_ss { + struct selinux_ruleset *active_set; /* rcu pointer */ rwlock_t policy_rwlock; u32 latest_granting; - struct selinux_map map; struct page *status_page; struct mutex status_lock; };