xref: /openbmc/linux/security/apparmor/secid.c (revision 76862af5)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2121d4a91SJohn Johansen /*
3121d4a91SJohn Johansen  * AppArmor security module
4121d4a91SJohn Johansen  *
5121d4a91SJohn Johansen  * This file contains AppArmor security identifier (secid) manipulation fns
6121d4a91SJohn Johansen  *
7c0929212SJohn Johansen  * Copyright 2009-2017 Canonical Ltd.
8121d4a91SJohn Johansen  *
9c0929212SJohn Johansen  * AppArmor allocates a unique secid for every label used. If a label
10c0929212SJohn Johansen  * is replaced it receives the secid of the label it is replacing.
11121d4a91SJohn Johansen  */
12121d4a91SJohn Johansen 
13121d4a91SJohn Johansen #include <linux/errno.h>
14121d4a91SJohn Johansen #include <linux/err.h>
15c0929212SJohn Johansen #include <linux/gfp.h>
16c0929212SJohn Johansen #include <linux/slab.h>
17c0929212SJohn Johansen #include <linux/spinlock.h>
18df439093SMatthew Wilcox #include <linux/xarray.h>
19121d4a91SJohn Johansen 
20c0929212SJohn Johansen #include "include/cred.h"
21c0929212SJohn Johansen #include "include/lib.h"
22121d4a91SJohn Johansen #include "include/secid.h"
23c0929212SJohn Johansen #include "include/label.h"
24c0929212SJohn Johansen #include "include/policy_ns.h"
25121d4a91SJohn Johansen 
26c0929212SJohn Johansen /*
27c0929212SJohn Johansen  * secids - do not pin labels with a refcount. They rely on the label
28c0929212SJohn Johansen  * properly updating/freeing them
29c0929212SJohn Johansen  */
30617a629cSMatthew Garrett #define AA_FIRST_SECID 2
31a4c3f89cSJohn Johansen 
32df439093SMatthew Wilcox static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
33121d4a91SJohn Johansen 
34524d8e14SJohn Johansen int apparmor_display_secid_mode;
35524d8e14SJohn Johansen 
36c0929212SJohn Johansen /*
37c0929212SJohn Johansen  * TODO: allow policy to reserve a secid range?
38c0929212SJohn Johansen  * TODO: add secid pinning
39c0929212SJohn Johansen  * TODO: use secid_update in label replace
40c0929212SJohn Johansen  */
41c0929212SJohn Johansen 
42c0929212SJohn Johansen /**
43c0929212SJohn Johansen  * aa_secid_update - update a secid mapping to a new label
44c0929212SJohn Johansen  * @secid: secid to update
45c0929212SJohn Johansen  * @label: label the secid will now map to
46c0929212SJohn Johansen  */
aa_secid_update(u32 secid,struct aa_label * label)47c0929212SJohn Johansen void aa_secid_update(u32 secid, struct aa_label *label)
48c0929212SJohn Johansen {
49c0929212SJohn Johansen 	unsigned long flags;
50c0929212SJohn Johansen 
51df439093SMatthew Wilcox 	xa_lock_irqsave(&aa_secids, flags);
52df439093SMatthew Wilcox 	__xa_store(&aa_secids, secid, label, 0);
53df439093SMatthew Wilcox 	xa_unlock_irqrestore(&aa_secids, flags);
54c0929212SJohn Johansen }
55c0929212SJohn Johansen 
56*76862af5SRandy Dunlap /*
57c0929212SJohn Johansen  * see label for inverse aa_label_to_secid
58c0929212SJohn Johansen  */
aa_secid_to_label(u32 secid)59c0929212SJohn Johansen struct aa_label *aa_secid_to_label(u32 secid)
60c0929212SJohn Johansen {
61df439093SMatthew Wilcox 	return xa_load(&aa_secids, secid);
62c0929212SJohn Johansen }
63c0929212SJohn Johansen 
apparmor_secid_to_secctx(u32 secid,char ** secdata,u32 * seclen)64c0929212SJohn Johansen int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
65c0929212SJohn Johansen {
66c0929212SJohn Johansen 	/* TODO: cache secctx and ref count so we don't have to recreate */
67c0929212SJohn Johansen 	struct aa_label *label = aa_secid_to_label(secid);
68524d8e14SJohn Johansen 	int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
6952e7128eSJohn Johansen 	int len;
70c0929212SJohn Johansen 
71c0929212SJohn Johansen 	AA_BUG(!seclen);
72c0929212SJohn Johansen 
73c0929212SJohn Johansen 	if (!label)
74c0929212SJohn Johansen 		return -EINVAL;
75c0929212SJohn Johansen 
76524d8e14SJohn Johansen 	if (apparmor_display_secid_mode)
77524d8e14SJohn Johansen 		flags |= FLAG_SHOW_MODE;
78524d8e14SJohn Johansen 
79c0929212SJohn Johansen 	if (secdata)
8052e7128eSJohn Johansen 		len = aa_label_asxprint(secdata, root_ns, label,
81524d8e14SJohn Johansen 					flags, GFP_ATOMIC);
82c0929212SJohn Johansen 	else
83524d8e14SJohn Johansen 		len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
84524d8e14SJohn Johansen 
8552e7128eSJohn Johansen 	if (len < 0)
86c0929212SJohn Johansen 		return -ENOMEM;
87c0929212SJohn Johansen 
8852e7128eSJohn Johansen 	*seclen = len;
8952e7128eSJohn Johansen 
90c0929212SJohn Johansen 	return 0;
91c0929212SJohn Johansen }
92c0929212SJohn Johansen 
apparmor_secctx_to_secid(const char * secdata,u32 seclen,u32 * secid)93c0929212SJohn Johansen int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
94c0929212SJohn Johansen {
95c0929212SJohn Johansen 	struct aa_label *label;
96c0929212SJohn Johansen 
97c0929212SJohn Johansen 	label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
98c0929212SJohn Johansen 				    seclen, GFP_KERNEL, false, false);
99c0929212SJohn Johansen 	if (IS_ERR(label))
100c0929212SJohn Johansen 		return PTR_ERR(label);
101c0929212SJohn Johansen 	*secid = label->secid;
102c0929212SJohn Johansen 
103c0929212SJohn Johansen 	return 0;
104c0929212SJohn Johansen }
105c0929212SJohn Johansen 
apparmor_release_secctx(char * secdata,u32 seclen)106c0929212SJohn Johansen void apparmor_release_secctx(char *secdata, u32 seclen)
107c0929212SJohn Johansen {
108c0929212SJohn Johansen 	kfree(secdata);
109c0929212SJohn Johansen }
110c0929212SJohn Johansen 
111121d4a91SJohn Johansen /**
112121d4a91SJohn Johansen  * aa_alloc_secid - allocate a new secid for a profile
113a4c3f89cSJohn Johansen  * @label: the label to allocate a secid for
114a4c3f89cSJohn Johansen  * @gfp: memory allocation flags
115a4c3f89cSJohn Johansen  *
116a4c3f89cSJohn Johansen  * Returns: 0 with @label->secid initialized
117a4c3f89cSJohn Johansen  *          <0 returns error with @label->secid set to AA_SECID_INVALID
118121d4a91SJohn Johansen  */
aa_alloc_secid(struct aa_label * label,gfp_t gfp)119a4c3f89cSJohn Johansen int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
120121d4a91SJohn Johansen {
121c0929212SJohn Johansen 	unsigned long flags;
122a4c3f89cSJohn Johansen 	int ret;
123121d4a91SJohn Johansen 
124df439093SMatthew Wilcox 	xa_lock_irqsave(&aa_secids, flags);
125df439093SMatthew Wilcox 	ret = __xa_alloc(&aa_secids, &label->secid, label,
126df439093SMatthew Wilcox 			XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
127df439093SMatthew Wilcox 	xa_unlock_irqrestore(&aa_secids, flags);
128c0929212SJohn Johansen 
129a4c3f89cSJohn Johansen 	if (ret < 0) {
130a4c3f89cSJohn Johansen 		label->secid = AA_SECID_INVALID;
131a4c3f89cSJohn Johansen 		return ret;
132a4c3f89cSJohn Johansen 	}
133a4c3f89cSJohn Johansen 
134a4c3f89cSJohn Johansen 	return 0;
135121d4a91SJohn Johansen }
136121d4a91SJohn Johansen 
137121d4a91SJohn Johansen /**
138121d4a91SJohn Johansen  * aa_free_secid - free a secid
139121d4a91SJohn Johansen  * @secid: secid to free
140121d4a91SJohn Johansen  */
aa_free_secid(u32 secid)141121d4a91SJohn Johansen void aa_free_secid(u32 secid)
142121d4a91SJohn Johansen {
143c0929212SJohn Johansen 	unsigned long flags;
144c0929212SJohn Johansen 
145df439093SMatthew Wilcox 	xa_lock_irqsave(&aa_secids, flags);
146df439093SMatthew Wilcox 	__xa_erase(&aa_secids, secid);
147df439093SMatthew Wilcox 	xa_unlock_irqrestore(&aa_secids, flags);
148a4c3f89cSJohn Johansen }
149