xref: /freebsd/sys/security/mac/mac_prison.c (revision 32cd3ee5901ea33d41ff550e5f40ce743c8d4165)
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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