xref: /freebsd/sys/security/mac/mac_prison.c (revision b1bebaaba9b9c0ddfe503c43ca8e9e3917ee2c57)
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 	mac_prison_label_free(pr->pr_label);
98 	pr->pr_label = NULL;
99 }
100 
101 void
102 mac_prison_copy_label(struct label *src, struct label *dest)
103 {
104 
105 	MAC_POLICY_PERFORM_NOSLEEP(prison_copy_label, src, dest);
106 }
107 
108 int
109 mac_prison_externalize_label(struct label *label, char *elements,
110     char *outbuf, size_t outbuflen)
111 {
112 	int error;
113 
114 	MAC_POLICY_EXTERNALIZE(prison, label, elements, outbuf, outbuflen);
115 	return (error);
116 }
117 
118 int
119 mac_prison_internalize_label(struct label *label, char *string)
120 {
121 	int error;
122 
123 	MAC_POLICY_INTERNALIZE(prison, label, string);
124 	return (error);
125 }
126 
127 void
128 mac_prison_relabel(struct ucred *cred, struct prison *pr,
129     struct label *newlabel)
130 {
131 	mtx_assert(&pr->pr_mtx, MA_OWNED);
132 	MAC_POLICY_PERFORM_NOSLEEP(prison_relabel, cred, pr, pr->pr_label,
133 	    newlabel);
134 }
135 
136 int
137 mac_prison_label_set(struct ucred *cred, struct prison *pr,
138     struct label *label)
139 {
140 	int error;
141 
142 	mtx_assert(&pr->pr_mtx, MA_OWNED);
143 
144 	error = mac_prison_check_relabel(cred, pr, label);
145 	if (error)
146 		return (error);
147 
148 	mac_prison_relabel(cred, pr, label);
149 
150 	return (0);
151 }
152 
153 MAC_CHECK_PROBE_DEFINE4(prison_check_relabel, "struct ucred *",
154     "struct prison *", "struct label *", "struct label *");
155 int
156 mac_prison_check_relabel(struct ucred *cred, struct prison *pr,
157     struct label *newlabel)
158 {
159 	int error;
160 
161 	mtx_assert(&pr->pr_mtx, MA_OWNED);
162 	MAC_POLICY_CHECK_NOSLEEP(prison_check_relabel, cred, pr,
163 	    pr->pr_label, newlabel);
164 	MAC_CHECK_PROBE4(prison_check_relabel, error, cred, pr,
165 	    pr->pr_label, newlabel);
166 
167 	return (error);
168 }
169 
170 MAC_CHECK_PROBE_DEFINE3(prison_check_attach, "struct ucred *",
171     "struct prison *", "struct label *");
172 int
173 mac_prison_check_attach(struct ucred *cred, struct prison *pr)
174 {
175 	int error;
176 
177 	MAC_POLICY_CHECK_NOSLEEP(prison_check_attach, cred, pr, pr->pr_label);
178 	MAC_CHECK_PROBE3(prison_check_attach, error, cred, pr, pr->pr_label);
179 
180 	return (error);
181 }
182 
183 MAC_CHECK_PROBE_DEFINE3(prison_check_create, "struct ucred *",
184     "struct vfsoptlist *", "int");
185 int
186 mac_prison_check_create(struct ucred *cred, struct vfsoptlist *opts,
187     int flags)
188 {
189 	int error;
190 
191 	MAC_POLICY_CHECK_NOSLEEP(prison_check_create, cred, opts, flags);
192 	MAC_CHECK_PROBE3(prison_check_create, error, cred, opts, flags);
193 
194 	return (error);
195 }
196 
197 MAC_CHECK_PROBE_DEFINE5(prison_check_get, "struct ucred *",
198     "struct prison *", "struct label *", "struct vfsoptlist *", "int");
199 int
200 mac_prison_check_get(struct ucred *cred, struct prison *pr,
201     struct vfsoptlist *opts, int flags)
202 {
203 	int error;
204 
205 	MAC_POLICY_CHECK_NOSLEEP(prison_check_get, cred, pr, pr->pr_label,
206 	    opts, flags);
207 	MAC_CHECK_PROBE5(prison_check_get, error, cred, pr, pr->pr_label, opts,
208 	    flags);
209 
210 	return (error);
211 }
212 
213 MAC_CHECK_PROBE_DEFINE5(prison_check_set, "struct ucred *",
214     "struct prison *", "struct label *", "struct vfsoptlist *", "int");
215 int
216 mac_prison_check_set(struct ucred *cred, struct prison *pr,
217     struct vfsoptlist *opts, int flags)
218 {
219 	int error;
220 
221 	MAC_POLICY_CHECK_NOSLEEP(prison_check_set, cred, pr, pr->pr_label,
222 	    opts, flags);
223 	MAC_CHECK_PROBE5(prison_check_set, error, cred, pr, pr->pr_label, opts,
224 	    flags);
225 
226 	return (error);
227 }
228 
229 MAC_CHECK_PROBE_DEFINE3(prison_check_remove, "struct ucred *",
230     "struct prison *", "struct label *");
231 int
232 mac_prison_check_remove(struct ucred *cred, struct prison *pr)
233 {
234 	int error;
235 
236 	MAC_POLICY_CHECK_NOSLEEP(prison_check_remove, cred, pr, pr->pr_label);
237 	MAC_CHECK_PROBE3(prison_check_remove, error, cred, pr, pr->pr_label);
238 
239 	return (error);
240 }
241 
242 void
243 mac_prison_created(struct ucred *cred, struct prison *pr)
244 {
245 
246 	MAC_POLICY_PERFORM(prison_created, cred, pr, pr->pr_label);
247 }
248 
249 void
250 mac_prison_attached(struct ucred *cred, struct prison *pr, struct proc *p)
251 {
252 
253 	MAC_POLICY_PERFORM(prison_attached, cred, pr, pr->pr_label, p,
254 	    p->p_label);
255 }
256