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/slab.h>
17 #include <linux/spinlock.h>
18 #include <linux/xarray.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
32 static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
33
34 int apparmor_display_secid_mode;
35
36 /*
37 * TODO: allow policy to reserve a secid range?
38 * TODO: add secid pinning
39 * TODO: use secid_update in label replace
40 */
41
42 /*
43 * see label for inverse aa_label_to_secid
44 */
aa_secid_to_label(u32 secid)45 struct aa_label *aa_secid_to_label(u32 secid)
46 {
47 return xa_load(&aa_secids, secid);
48 }
49
apparmor_label_to_secctx(struct aa_label * label,struct lsm_context * cp)50 static int apparmor_label_to_secctx(struct aa_label *label,
51 struct lsm_context *cp)
52 {
53 /* TODO: cache secctx and ref count so we don't have to recreate */
54 int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
55 int len;
56
57 if (!label)
58 return -EINVAL;
59
60 if (apparmor_display_secid_mode)
61 flags |= FLAG_SHOW_MODE;
62
63 if (cp)
64 len = aa_label_asxprint(&cp->context, root_ns, label,
65 flags, GFP_ATOMIC);
66 else
67 len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
68
69 if (len < 0)
70 return -ENOMEM;
71
72 if (cp) {
73 cp->len = len;
74 cp->id = LSM_ID_APPARMOR;
75 }
76
77 return len;
78 }
79
apparmor_secid_to_secctx(u32 secid,struct lsm_context * cp)80 int apparmor_secid_to_secctx(u32 secid, struct lsm_context *cp)
81 {
82 struct aa_label *label = aa_secid_to_label(secid);
83
84 return apparmor_label_to_secctx(label, cp);
85 }
86
apparmor_lsmprop_to_secctx(struct lsm_prop * prop,struct lsm_context * cp)87 int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp)
88 {
89 struct aa_label *label;
90
91 label = prop->apparmor.label;
92
93 return apparmor_label_to_secctx(label, cp);
94 }
95
apparmor_secctx_to_secid(const char * secdata,u32 seclen,u32 * secid)96 int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
97 {
98 struct aa_label *label;
99
100 label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
101 seclen, GFP_KERNEL, false, false);
102 if (IS_ERR(label))
103 return PTR_ERR(label);
104 *secid = label->secid;
105
106 return 0;
107 }
108
apparmor_release_secctx(struct lsm_context * cp)109 void apparmor_release_secctx(struct lsm_context *cp)
110 {
111 if (cp->id == LSM_ID_APPARMOR) {
112 kfree(cp->context);
113 cp->context = NULL;
114 cp->id = LSM_ID_UNDEF;
115 }
116 }
117
118 /**
119 * aa_alloc_secid - allocate a new secid for a profile
120 * @label: the label to allocate a secid for
121 * @gfp: memory allocation flags
122 *
123 * Returns: 0 with @label->secid initialized
124 * <0 returns error with @label->secid set to AA_SECID_INVALID
125 */
aa_alloc_secid(struct aa_label * label,gfp_t gfp)126 int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
127 {
128 unsigned long flags;
129 int ret;
130
131 xa_lock_irqsave(&aa_secids, flags);
132 ret = __xa_alloc(&aa_secids, &label->secid, label,
133 XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
134 xa_unlock_irqrestore(&aa_secids, flags);
135
136 if (ret < 0) {
137 label->secid = AA_SECID_INVALID;
138 return ret;
139 }
140
141 return 0;
142 }
143
144 /**
145 * aa_free_secid - free a secid
146 * @secid: secid to free
147 */
aa_free_secid(u32 secid)148 void aa_free_secid(u32 secid)
149 {
150 unsigned long flags;
151
152 xa_lock_irqsave(&aa_secids, flags);
153 __xa_erase(&aa_secids, secid);
154 xa_unlock_irqrestore(&aa_secids, flags);
155 }
156