linux/security/apparmor/secid.c
<<
>>
Prefs
   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}
 162