From patchwork Fri Jan 26 14:32:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Enderborg X-Patchwork-Id: 10186123 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 13DD5603ED for ; Fri, 26 Jan 2018 14:33:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05F4228C74 for ; Fri, 26 Jan 2018 14:33:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EEC3628E8B; Fri, 26 Jan 2018 14:33:55 +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 4C4AE28C74 for ; Fri, 26 Jan 2018 14:33:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753080AbeAZOdI (ORCPT ); Fri, 26 Jan 2018 09:33:08 -0500 Received: from seldsegrel01.sonyericsson.com ([37.139.156.29]:1245 "EHLO SELDSEGREL01.sonyericsson.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753272AbeAZOc4 (ORCPT ); Fri, 26 Jan 2018 09:32:56 -0500 X-Authentication-Warning: seldlx23035.corpusers.net: 23059638 set sender to peter.enderborg@sony.com using -f From: To: Paul Moore , Stephen Smalley , Eric Paris , James Morris , Daniel Jurgens , Doug Ledford , , , , Ingo Molnar , , "Serge E . Hallyn" CC: Peter Enderborg Subject: [PATCH v2 4/5] selinux: Use pointer to switch policydb and sidtab Date: Fri, 26 Jan 2018 15:32:40 +0100 Message-ID: <20180126143241.23108-5-peter.enderborg@sony.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <20180126143241.23108-1-peter.enderborg@sony.com> References: <20180126143241.23108-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 From: Peter Enderborg This i preparation for switching to RCU locks. To be able to use RCU we need atomic switched pointer. This adds the dynamic memory copying to be a single pointer. It copy all the data structures in to new ones. This is an overhead for writing rules but the benifit is RCU. Signed-off-by: Peter Enderborg --- security/selinux/ss/services.c | 139 +++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 61 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2a8486c..81c5717 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2064,76 +2064,67 @@ static int security_preserve_bools(struct policydb *p); */ int security_load_policy(void *data, size_t len) { - struct policydb *oldpolicydb, *newpolicydb; + struct policydb *oldpolicydb; struct sidtab oldsidtab, newsidtab; struct selinux_mapping *oldmap = NULL, *map = NULL; struct convert_context_args args; - struct shared_current_mapping *new_mapping; struct shared_current_mapping *next_rcu; - + struct shared_current_mapping *old_rcu; u32 seqno; u16 map_size; int rc = 0; struct policy_file file = { data, len }, *fp = &file; - oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); - if (!oldpolicydb) { - rc = -ENOMEM; - goto out; - } - new_mapping = kzalloc(sizeof(struct shared_current_mapping), - GFP_KERNEL); - if (!new_mapping) { - rc = -ENOMEM; - goto out; - } - newpolicydb = oldpolicydb + 1; - next_rcu = kmalloc(sizeof(struct shared_current_mapping), GFP_KERNEL); - if (!next_rcu) { - rc = -ENOMEM; - goto out; - } - if (!ss_initialized) { - crm = kzalloc(sizeof(struct shared_current_mapping), - GFP_KERNEL); - if (!crm) { + struct shared_current_mapping *first_mapping; + + first_mapping = kzalloc(sizeof(struct shared_current_mapping), + GFP_KERNEL); + if (!first_mapping) { rc = -ENOMEM; goto out; } avtab_cache_init(); ebitmap_cache_init(); hashtab_cache_init(); - rc = policydb_read(&crm->policydb, fp); + rc = policydb_read(&first_mapping->policydb, fp); if (rc) { avtab_cache_destroy(); ebitmap_cache_destroy(); hashtab_cache_destroy(); + kfree(first_mapping); goto out; } - crm->policydb.len = len; - rc = selinux_set_mapping(&crm->policydb, secclass_map, - &crm->current_mapping, - &crm->current_mapping_size); + first_mapping->policydb.len = len; + rc = selinux_set_mapping(&first_mapping->policydb, secclass_map, + &first_mapping->current_mapping, + &first_mapping->current_mapping_size); if (rc) { - policydb_destroy(&crm->policydb); + policydb_destroy(&first_mapping->policydb); avtab_cache_destroy(); ebitmap_cache_destroy(); hashtab_cache_destroy(); + kfree(first_mapping); goto out; } - rc = policydb_load_isids(&crm->policydb, &crm->sidtab); + rc = policydb_load_isids(&first_mapping->policydb, + &first_mapping->sidtab); if (rc) { - policydb_destroy(&crm->policydb); + policydb_destroy(&first_mapping->policydb); avtab_cache_destroy(); ebitmap_cache_destroy(); hashtab_cache_destroy(); + kfree(first_mapping); goto out; } - security_load_policycaps(&crm->policydb); + security_load_policycaps(&first_mapping->policydb); + crm = first_mapping; + + smp_mb(); /* make sure that crm exist before we */ + /* switch ss_initialized */ ss_initialized = 1; seqno = ++latest_granting; selinux_complete_init(); @@ -2148,30 +2139,44 @@ int security_load_policy(void *data, size_t len) #if 0 sidtab_hash_eval(&crm->sidtab, "sids"); #endif + oldpolicydb = kzalloc(sizeof(*oldpolicydb), GFP_KERNEL); + if (!oldpolicydb) { + rc = -ENOMEM; + goto out; + } + + next_rcu = kzalloc(sizeof(struct shared_current_mapping), GFP_KERNEL); + if (!next_rcu) { + kfree(oldpolicydb); + rc = -ENOMEM; + goto out; + } - rc = policydb_read(newpolicydb, fp); + rc = policydb_read(&next_rcu->policydb, fp); if (rc) goto out; - newpolicydb->len = len; + next_rcu->policydb.len = len; + read_lock(&policy_rwlock); /* If switching between different policy types, log MLS status */ - if (crm->policydb.mls_enabled && !newpolicydb->mls_enabled) + if (crm->policydb.mls_enabled && !next_rcu->policydb.mls_enabled) printk(KERN_INFO "SELinux: Disabling MLS support...\n"); - else if (!crm->policydb.mls_enabled && newpolicydb->mls_enabled) + else if (!crm->policydb.mls_enabled && next_rcu->policydb.mls_enabled) printk(KERN_INFO "SELinux: Enabling MLS support...\n"); - rc = policydb_load_isids(newpolicydb, &newsidtab); + rc = policydb_load_isids(&next_rcu->policydb, &newsidtab); if (rc) { printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); - policydb_destroy(newpolicydb); + policydb_destroy(&next_rcu->policydb); goto out; } - rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); + rc = selinux_set_mapping(&next_rcu->policydb, secclass_map, + &map, &map_size); if (rc) goto err; - rc = security_preserve_bools(newpolicydb); + rc = security_preserve_bools(&next_rcu->policydb); if (rc) { printk(KERN_ERR "SELinux: unable to preserve booleans\n"); goto err; @@ -2189,7 +2194,7 @@ int security_load_policy(void *data, size_t len) * in the new SID table. */ args.oldp = &crm->policydb; - args.newp = newpolicydb; + args.newp = &next_rcu->policydb; rc = sidtab_map(&newsidtab, convert_context, &args); if (rc) { printk(KERN_ERR "SELinux: unable to convert the internal" @@ -2204,8 +2209,9 @@ 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); - memcpy(&next_rcu->policydb, newpolicydb, sizeof(struct policydb)); sidtab_set(&next_rcu->sidtab, &newsidtab); security_load_policycaps(&next_rcu->policydb); oldmap = crm->current_mapping; @@ -2213,8 +2219,9 @@ int security_load_policy(void *data, size_t len) next_rcu->current_mapping_size = map_size; seqno = ++latest_granting; - write_unlock_irq(&policy_rwlock); + old_rcu = crm; crm = next_rcu; + write_unlock_irq(&policy_rwlock); /* Free the old policydb and SID table. */ policydb_destroy(oldpolicydb); @@ -2226,17 +2233,16 @@ int security_load_policy(void *data, size_t len) selinux_status_update_policyload(seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); + kfree(oldpolicydb); + kfree(old_rcu); rc = 0; goto out; - err: kfree(map); sidtab_destroy(&newsidtab); - policydb_destroy(newpolicydb); - + policydb_destroy(&next_rcu->policydb); out: - kfree(oldpolicydb); return rc; } @@ -2795,54 +2801,65 @@ int security_get_bools(int *len, char ***names, int **values) goto out; } - int security_set_bools(int len, int *values) { + struct shared_current_mapping *next_rcu, *old_rcu; int i, rc; int lenp, seqno = 0; struct cond_node *cur; - write_lock_irq(&policy_rwlock); - + next_rcu = kzalloc(sizeof(struct shared_current_mapping), GFP_KERNEL); + read_lock(&policy_rwlock); + old_rcu = crm; + memcpy(&next_rcu->policydb, &old_rcu->policydb, + sizeof(struct policydb)); rc = -EFAULT; - lenp = crm->policydb.p_bools.nprim; + lenp = next_rcu->policydb.p_bools.nprim; + if (len != lenp) goto out; for (i = 0; i < len; i++) { if (!!values[i] != - crm->policydb.bool_val_to_struct[i]->state) { + next_rcu->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(&crm->policydb, SYM_BOOLS, i), + sym_name(&next_rcu->policydb, SYM_BOOLS, i), !!values[i], - crm->policydb.bool_val_to_struct[i]->state, + next_rcu->policydb.bool_val_to_struct[i]->state, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); } if (values[i]) - crm->policydb.bool_val_to_struct[i]->state = 1; + next_rcu->policydb.bool_val_to_struct[i]->state = 1; else - crm->policydb.bool_val_to_struct[i]->state = 0; + next_rcu->policydb.bool_val_to_struct[i]->state = 0; } - for (cur = crm->policydb.cond_list; cur; cur = cur->next) { - rc = evaluate_cond_node(&crm->policydb, cur); + for (cur = next_rcu->policydb.cond_list; cur; cur = cur->next) { + rc = evaluate_cond_node(&next_rcu->policydb, cur); if (rc) goto out; } + read_unlock(&policy_rwlock); + rc = 0; + write_lock_irq(&policy_rwlock); seqno = ++latest_granting; - rc = 0; -out: + crm = next_rcu; write_unlock_irq(&policy_rwlock); +out: if (!rc) { avc_ss_reset(seqno); selnl_notify_policyload(seqno); selinux_status_update_policyload(seqno); selinux_xfrm_notify_policyload(); + } else { + kfree(next_rcu); } + kfree(old_rcu); + return rc; }