1 /*-
2 * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <sys/cdefs.h>
8 #include "opt_mac.h"
9
10 #include <sys/param.h>
11 #include <sys/condvar.h>
12 #include <sys/imgact.h>
13 #include <sys/jail.h>
14 #include <sys/kernel.h>
15 #include <sys/lock.h>
16 #include <sys/malloc.h>
17 #include <sys/mutex.h>
18 #include <sys/mac.h>
19 #include <sys/proc.h>
20 #include <sys/sbuf.h>
21 #include <sys/sdt.h>
22 #include <sys/systm.h>
23 #include <sys/vnode.h>
24 #include <sys/mount.h>
25 #include <sys/file.h>
26 #include <sys/namei.h>
27 #include <sys/sysctl.h>
28
29 #include <security/mac/mac_framework.h>
30 #include <security/mac/mac_internal.h>
31 #include <security/mac/mac_policy.h>
32
33 void
mac_prison_label_free(struct label * label)34 mac_prison_label_free(struct label *label)
35 {
36 if (label == NULL)
37 return;
38
39 MAC_POLICY_PERFORM_NOSLEEP(prison_destroy_label, label);
40 mac_labelzone_free(label);
41 }
42
43 struct label *
mac_prison_label_alloc(int flag)44 mac_prison_label_alloc(int flag)
45 {
46 struct label *label;
47 int error;
48
49 label = mac_labelzone_alloc(flag);
50 if (label == NULL)
51 return (NULL);
52
53 if (flag & M_WAITOK)
54 MAC_POLICY_CHECK(prison_init_label, label, flag);
55 else
56 MAC_POLICY_CHECK_NOSLEEP(prison_init_label, label, flag);
57 if (error) {
58 mac_prison_label_free(label);
59 return (NULL);
60 }
61 return (label);
62 }
63
64 /*
65 * The caller's expecting us to return with the prison locked if we were
66 * successful, since we're also setting pr->pr_label. On error, it remains
67 * unlocked.
68 */
69 int
mac_prison_init(struct prison * pr,int flag)70 mac_prison_init(struct prison *pr, int flag)
71 {
72 struct label *prlabel;
73
74 mtx_assert(&pr->pr_mtx, MA_NOTOWNED);
75 if ((mac_labeled & MPC_OBJECT_PRISON) == 0) {
76 mtx_lock(&pr->pr_mtx);
77 pr->pr_label = NULL;
78 return (0);
79 }
80
81 prlabel = mac_prison_label_alloc(flag);
82 if (prlabel == NULL) {
83 KASSERT((flag & M_WAITOK) == 0,
84 ("MAC policy prison_init_label failed under M_WAITOK"));
85 return (ENOMEM);
86 }
87
88 mtx_lock(&pr->pr_mtx);
89 pr->pr_label = prlabel;
90 return (0);
91 }
92
93 void
mac_prison_destroy(struct prison * pr)94 mac_prison_destroy(struct prison *pr)
95 {
96 mtx_assert(&pr->pr_mtx, MA_OWNED);
97
98 /* Symmetry with prison_created */
99 MAC_POLICY_PERFORM_NOSLEEP(prison_cleanup, curthread->td_ucred, pr);
100 mac_prison_label_free(pr->pr_label);
101 pr->pr_label = NULL;
102 }
103
104 void
mac_prison_copy_label(struct label * src,struct label * dest)105 mac_prison_copy_label(struct label *src, struct label *dest)
106 {
107
108 MAC_POLICY_PERFORM_NOSLEEP(prison_copy_label, src, dest);
109 }
110
111 int
mac_prison_externalize_label(struct label * label,char * elements,char * outbuf,size_t outbuflen)112 mac_prison_externalize_label(struct label *label, char *elements,
113 char *outbuf, size_t outbuflen)
114 {
115 int error;
116
117 MAC_POLICY_EXTERNALIZE(prison, label, elements, outbuf, outbuflen);
118 return (error);
119 }
120
121 int
mac_prison_internalize_label(struct label * label,char * string)122 mac_prison_internalize_label(struct label *label, char *string)
123 {
124 int error;
125
126 MAC_POLICY_INTERNALIZE(prison, label, string);
127 return (error);
128 }
129
130 void
mac_prison_relabel(struct ucred * cred,struct prison * pr,struct label * newlabel)131 mac_prison_relabel(struct ucred *cred, struct prison *pr,
132 struct label *newlabel)
133 {
134 mtx_assert(&pr->pr_mtx, MA_OWNED);
135 MAC_POLICY_PERFORM_NOSLEEP(prison_relabel, cred, pr, pr->pr_label,
136 newlabel);
137 }
138
139 int
mac_prison_label_set(struct ucred * cred,struct prison * pr,struct label * label)140 mac_prison_label_set(struct ucred *cred, struct prison *pr,
141 struct label *label)
142 {
143 int error;
144
145 mtx_assert(&pr->pr_mtx, MA_OWNED);
146
147 error = mac_prison_check_relabel(cred, pr, label);
148 if (error)
149 return (error);
150
151 mac_prison_relabel(cred, pr, label);
152
153 return (0);
154 }
155
156 MAC_CHECK_PROBE_DEFINE4(prison_check_relabel, "struct ucred *",
157 "struct prison *", "struct label *", "struct label *");
158 int
mac_prison_check_relabel(struct ucred * cred,struct prison * pr,struct label * newlabel)159 mac_prison_check_relabel(struct ucred *cred, struct prison *pr,
160 struct label *newlabel)
161 {
162 int error;
163
164 mtx_assert(&pr->pr_mtx, MA_OWNED);
165 MAC_POLICY_CHECK_NOSLEEP(prison_check_relabel, cred, pr,
166 pr->pr_label, newlabel);
167 MAC_CHECK_PROBE4(prison_check_relabel, error, cred, pr,
168 pr->pr_label, newlabel);
169
170 return (error);
171 }
172
173 MAC_CHECK_PROBE_DEFINE3(prison_check_attach, "struct ucred *",
174 "struct prison *", "struct label *");
175 int
mac_prison_check_attach(struct ucred * cred,struct prison * pr)176 mac_prison_check_attach(struct ucred *cred, struct prison *pr)
177 {
178 int error;
179
180 MAC_POLICY_CHECK_NOSLEEP(prison_check_attach, cred, pr, pr->pr_label);
181 MAC_CHECK_PROBE3(prison_check_attach, error, cred, pr, pr->pr_label);
182
183 return (error);
184 }
185
186 MAC_CHECK_PROBE_DEFINE3(prison_check_create, "struct ucred *",
187 "struct vfsoptlist *", "int");
188 int
mac_prison_check_create(struct ucred * cred,struct vfsoptlist * opts,int flags)189 mac_prison_check_create(struct ucred *cred, struct vfsoptlist *opts,
190 int flags)
191 {
192 int error;
193
194 MAC_POLICY_CHECK_NOSLEEP(prison_check_create, cred, opts, flags);
195 MAC_CHECK_PROBE3(prison_check_create, error, cred, opts, flags);
196
197 return (error);
198 }
199
200 MAC_CHECK_PROBE_DEFINE5(prison_check_get, "struct ucred *",
201 "struct prison *", "struct label *", "struct vfsoptlist *", "int");
202 int
mac_prison_check_get(struct ucred * cred,struct prison * pr,struct vfsoptlist * opts,int flags)203 mac_prison_check_get(struct ucred *cred, struct prison *pr,
204 struct vfsoptlist *opts, int flags)
205 {
206 int error;
207
208 MAC_POLICY_CHECK_NOSLEEP(prison_check_get, cred, pr, pr->pr_label,
209 opts, flags);
210 MAC_CHECK_PROBE5(prison_check_get, error, cred, pr, pr->pr_label, opts,
211 flags);
212
213 return (error);
214 }
215
216 MAC_CHECK_PROBE_DEFINE5(prison_check_set, "struct ucred *",
217 "struct prison *", "struct label *", "struct vfsoptlist *", "int");
218 int
mac_prison_check_set(struct ucred * cred,struct prison * pr,struct vfsoptlist * opts,int flags)219 mac_prison_check_set(struct ucred *cred, struct prison *pr,
220 struct vfsoptlist *opts, int flags)
221 {
222 int error;
223
224 MAC_POLICY_CHECK_NOSLEEP(prison_check_set, cred, pr, pr->pr_label,
225 opts, flags);
226 MAC_CHECK_PROBE5(prison_check_set, error, cred, pr, pr->pr_label, opts,
227 flags);
228
229 return (error);
230 }
231
232 MAC_CHECK_PROBE_DEFINE3(prison_check_remove, "struct ucred *",
233 "struct prison *", "struct label *");
234 int
mac_prison_check_remove(struct ucred * cred,struct prison * pr)235 mac_prison_check_remove(struct ucred *cred, struct prison *pr)
236 {
237 int error;
238
239 MAC_POLICY_CHECK_NOSLEEP(prison_check_remove, cred, pr, pr->pr_label);
240 MAC_CHECK_PROBE3(prison_check_remove, error, cred, pr, pr->pr_label);
241
242 return (error);
243 }
244
245 void
mac_prison_created(struct ucred * cred,struct prison * pr)246 mac_prison_created(struct ucred *cred, struct prison *pr)
247 {
248
249 MAC_POLICY_PERFORM(prison_created, cred, pr, pr->pr_label);
250 }
251
252 void
mac_prison_attached(struct ucred * cred,struct prison * pr,struct proc * p)253 mac_prison_attached(struct ucred *cred, struct prison *pr, struct proc *p)
254 {
255
256 MAC_POLICY_PERFORM(prison_attached, cred, pr, pr->pr_label, p,
257 p->p_label);
258 }
259