secid.c (3518B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * AppArmor security module 4 * 5 * This file contains AppArmor security identifier (secid) manipulation fns 6 * 7 * Copyright 2009-2017 Canonical Ltd. 8 * 9 * AppArmor allocates a unique secid for every label used. If a label 10 * is replaced it receives the secid of the label it is replacing. 11 */ 12 13#include <linux/errno.h> 14#include <linux/err.h> 15#include <linux/gfp.h> 16#include <linux/idr.h> 17#include <linux/slab.h> 18#include <linux/spinlock.h> 19 20#include "include/cred.h" 21#include "include/lib.h" 22#include "include/secid.h" 23#include "include/label.h" 24#include "include/policy_ns.h" 25 26/* 27 * secids - do not pin labels with a refcount. They rely on the label 28 * properly updating/freeing them 29 */ 30#define AA_FIRST_SECID 2 31 32static DEFINE_IDR(aa_secids); 33static DEFINE_SPINLOCK(secid_lock); 34 35/* 36 * TODO: allow policy to reserve a secid range? 37 * TODO: add secid pinning 38 * TODO: use secid_update in label replace 39 */ 40 41/** 42 * aa_secid_update - update a secid mapping to a new label 43 * @secid: secid to update 44 * @label: label the secid will now map to 45 */ 46void aa_secid_update(u32 secid, struct aa_label *label) 47{ 48 unsigned long flags; 49 50 spin_lock_irqsave(&secid_lock, flags); 51 idr_replace(&aa_secids, label, secid); 52 spin_unlock_irqrestore(&secid_lock, flags); 53} 54 55/** 56 * 57 * see label for inverse aa_label_to_secid 58 */ 59struct aa_label *aa_secid_to_label(u32 secid) 60{ 61 struct aa_label *label; 62 63 rcu_read_lock(); 64 label = idr_find(&aa_secids, secid); 65 rcu_read_unlock(); 66 67 return label; 68} 69 70int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 71{ 72 /* TODO: cache secctx and ref count so we don't have to recreate */ 73 struct aa_label *label = aa_secid_to_label(secid); 74 int len; 75 76 AA_BUG(!seclen); 77 78 if (!label) 79 return -EINVAL; 80 81 if (secdata) 82 len = aa_label_asxprint(secdata, root_ns, label, 83 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 84 FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT, 85 GFP_ATOMIC); 86 else 87 len = aa_label_snxprint(NULL, 0, root_ns, label, 88 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 89 FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT); 90 if (len < 0) 91 return -ENOMEM; 92 93 *seclen = len; 94 95 return 0; 96} 97 98int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 99{ 100 struct aa_label *label; 101 102 label = aa_label_strn_parse(&root_ns->unconfined->label, secdata, 103 seclen, GFP_KERNEL, false, false); 104 if (IS_ERR(label)) 105 return PTR_ERR(label); 106 *secid = label->secid; 107 108 return 0; 109} 110 111void apparmor_release_secctx(char *secdata, u32 seclen) 112{ 113 kfree(secdata); 114} 115 116/** 117 * aa_alloc_secid - allocate a new secid for a profile 118 * @label: the label to allocate a secid for 119 * @gfp: memory allocation flags 120 * 121 * Returns: 0 with @label->secid initialized 122 * <0 returns error with @label->secid set to AA_SECID_INVALID 123 */ 124int aa_alloc_secid(struct aa_label *label, gfp_t gfp) 125{ 126 unsigned long flags; 127 int ret; 128 129 idr_preload(gfp); 130 spin_lock_irqsave(&secid_lock, flags); 131 ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); 132 spin_unlock_irqrestore(&secid_lock, flags); 133 idr_preload_end(); 134 135 if (ret < 0) { 136 label->secid = AA_SECID_INVALID; 137 return ret; 138 } 139 140 AA_BUG(ret == AA_SECID_INVALID); 141 label->secid = ret; 142 return 0; 143} 144 145/** 146 * aa_free_secid - free a secid 147 * @secid: secid to free 148 */ 149void aa_free_secid(u32 secid) 150{ 151 unsigned long flags; 152 153 spin_lock_irqsave(&secid_lock, flags); 154 idr_remove(&aa_secids, secid); 155 spin_unlock_irqrestore(&secid_lock, flags); 156} 157 158void aa_secids_init(void) 159{ 160 idr_init_base(&aa_secids, AA_FIRST_SECID); 161}