162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AppArmor security module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This file contains AppArmor security identifier (secid) manipulation fns
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * AppArmor allocates a unique secid for every label used. If a label
1062306a36Sopenharmony_ci * is replaced it receives the secid of the label it is replacing.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/err.h>
1562306a36Sopenharmony_ci#include <linux/gfp.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/spinlock.h>
1862306a36Sopenharmony_ci#include <linux/xarray.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "include/cred.h"
2162306a36Sopenharmony_ci#include "include/lib.h"
2262306a36Sopenharmony_ci#include "include/secid.h"
2362306a36Sopenharmony_ci#include "include/label.h"
2462306a36Sopenharmony_ci#include "include/policy_ns.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * secids - do not pin labels with a refcount. They rely on the label
2862306a36Sopenharmony_ci * properly updating/freeing them
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define AA_FIRST_SECID 2
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciint apparmor_display_secid_mode;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * TODO: allow policy to reserve a secid range?
3862306a36Sopenharmony_ci * TODO: add secid pinning
3962306a36Sopenharmony_ci * TODO: use secid_update in label replace
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * aa_secid_update - update a secid mapping to a new label
4462306a36Sopenharmony_ci * @secid: secid to update
4562306a36Sopenharmony_ci * @label: label the secid will now map to
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_civoid aa_secid_update(u32 secid, struct aa_label *label)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	unsigned long flags;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	xa_lock_irqsave(&aa_secids, flags);
5262306a36Sopenharmony_ci	__xa_store(&aa_secids, secid, label, 0);
5362306a36Sopenharmony_ci	xa_unlock_irqrestore(&aa_secids, flags);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * see label for inverse aa_label_to_secid
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_cistruct aa_label *aa_secid_to_label(u32 secid)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return xa_load(&aa_secids, secid);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciint apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	/* TODO: cache secctx and ref count so we don't have to recreate */
6762306a36Sopenharmony_ci	struct aa_label *label = aa_secid_to_label(secid);
6862306a36Sopenharmony_ci	int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
6962306a36Sopenharmony_ci	int len;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	AA_BUG(!seclen);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!label)
7462306a36Sopenharmony_ci		return -EINVAL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (apparmor_display_secid_mode)
7762306a36Sopenharmony_ci		flags |= FLAG_SHOW_MODE;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (secdata)
8062306a36Sopenharmony_ci		len = aa_label_asxprint(secdata, root_ns, label,
8162306a36Sopenharmony_ci					flags, GFP_ATOMIC);
8262306a36Sopenharmony_ci	else
8362306a36Sopenharmony_ci		len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (len < 0)
8662306a36Sopenharmony_ci		return -ENOMEM;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	*seclen = len;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct aa_label *label;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
9862306a36Sopenharmony_ci				    seclen, GFP_KERNEL, false, false);
9962306a36Sopenharmony_ci	if (IS_ERR(label))
10062306a36Sopenharmony_ci		return PTR_ERR(label);
10162306a36Sopenharmony_ci	*secid = label->secid;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_civoid apparmor_release_secctx(char *secdata, u32 seclen)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	kfree(secdata);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/**
11262306a36Sopenharmony_ci * aa_alloc_secid - allocate a new secid for a profile
11362306a36Sopenharmony_ci * @label: the label to allocate a secid for
11462306a36Sopenharmony_ci * @gfp: memory allocation flags
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Returns: 0 with @label->secid initialized
11762306a36Sopenharmony_ci *          <0 returns error with @label->secid set to AA_SECID_INVALID
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_ciint aa_alloc_secid(struct aa_label *label, gfp_t gfp)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	unsigned long flags;
12262306a36Sopenharmony_ci	int ret;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	xa_lock_irqsave(&aa_secids, flags);
12562306a36Sopenharmony_ci	ret = __xa_alloc(&aa_secids, &label->secid, label,
12662306a36Sopenharmony_ci			XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
12762306a36Sopenharmony_ci	xa_unlock_irqrestore(&aa_secids, flags);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (ret < 0) {
13062306a36Sopenharmony_ci		label->secid = AA_SECID_INVALID;
13162306a36Sopenharmony_ci		return ret;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * aa_free_secid - free a secid
13962306a36Sopenharmony_ci * @secid: secid to free
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_civoid aa_free_secid(u32 secid)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	unsigned long flags;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	xa_lock_irqsave(&aa_secids, flags);
14662306a36Sopenharmony_ci	__xa_erase(&aa_secids, secid);
14762306a36Sopenharmony_ci	xa_unlock_irqrestore(&aa_secids, flags);
14862306a36Sopenharmony_ci}
149