1 /* $NetBSD: secmodel_overlay.c,v 1.14 2020/03/16 21:20:12 pgoyette Exp $ */
2 /*-
3 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: secmodel_overlay.c,v 1.14 2020/03/16 21:20:12 pgoyette Exp $");
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/kauth.h>
35 #include <sys/module.h>
36
37 #include <sys/sysctl.h>
38
39 #include <secmodel/secmodel.h>
40
41 #include <secmodel/overlay/overlay.h>
42 #include <secmodel/bsd44/bsd44.h>
43 #include <secmodel/suser/suser.h>
44 #include <secmodel/securelevel/securelevel.h>
45
46 MODULE(MODULE_CLASS_SECMODEL, secmodel_overlay, "secmodel_bsd44");
47
48 /*
49 * Fall-back settings.
50 */
51 #define OVERLAY_ISCOPE_GENERIC "org.netbsd.kauth.overlay.generic"
52 #define OVERLAY_ISCOPE_SYSTEM "org.netbsd.kauth.overlay.system"
53 #define OVERLAY_ISCOPE_PROCESS "org.netbsd.kauth.overlay.process"
54 #define OVERLAY_ISCOPE_NETWORK "org.netbsd.kauth.overlay.network"
55 #define OVERLAY_ISCOPE_MACHDEP "org.netbsd.kauth.overlay.machdep"
56 #define OVERLAY_ISCOPE_DEVICE "org.netbsd.kauth.overlay.device"
57 #define OVERLAY_ISCOPE_VNODE "org.netbsd.kauth.overlay.vnode"
58
59 static kauth_scope_t secmodel_overlay_iscope_generic;
60 static kauth_scope_t secmodel_overlay_iscope_system;
61 static kauth_scope_t secmodel_overlay_iscope_process;
62 static kauth_scope_t secmodel_overlay_iscope_network;
63 static kauth_scope_t secmodel_overlay_iscope_machdep;
64 static kauth_scope_t secmodel_overlay_iscope_device;
65 static kauth_scope_t secmodel_overlay_iscope_vnode;
66
67 static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep,
68 l_device, l_vnode;
69
70 static secmodel_t overlay_sm;
71
72 /*
73 * Initialize the overlay security model.
74 */
75 void
secmodel_overlay_init(void)76 secmodel_overlay_init(void)
77 {
78 /*
79 * Register internal fall-back scopes.
80 */
81 secmodel_overlay_iscope_generic = kauth_register_scope(
82 OVERLAY_ISCOPE_GENERIC, NULL, NULL);
83 secmodel_overlay_iscope_system = kauth_register_scope(
84 OVERLAY_ISCOPE_SYSTEM, NULL, NULL);
85 secmodel_overlay_iscope_process = kauth_register_scope(
86 OVERLAY_ISCOPE_PROCESS, NULL, NULL);
87 secmodel_overlay_iscope_network = kauth_register_scope(
88 OVERLAY_ISCOPE_NETWORK, NULL, NULL);
89 secmodel_overlay_iscope_machdep = kauth_register_scope(
90 OVERLAY_ISCOPE_MACHDEP, NULL, NULL);
91 secmodel_overlay_iscope_device = kauth_register_scope(
92 OVERLAY_ISCOPE_DEVICE, NULL, NULL);
93 secmodel_overlay_iscope_vnode = kauth_register_scope(
94 OVERLAY_ISCOPE_VNODE, NULL, NULL);
95
96 /*
97 * Register fall-back listeners, from suser and securelevel, to each
98 * internal scope.
99 */
100 kauth_listen_scope(OVERLAY_ISCOPE_GENERIC,
101 secmodel_suser_generic_cb, NULL);
102
103 kauth_listen_scope(OVERLAY_ISCOPE_SYSTEM,
104 secmodel_suser_system_cb, NULL);
105 kauth_listen_scope(OVERLAY_ISCOPE_SYSTEM,
106 secmodel_securelevel_system_cb, NULL);
107
108 kauth_listen_scope(OVERLAY_ISCOPE_PROCESS,
109 secmodel_suser_process_cb, NULL);
110 kauth_listen_scope(OVERLAY_ISCOPE_PROCESS,
111 secmodel_securelevel_process_cb, NULL);
112
113 kauth_listen_scope(OVERLAY_ISCOPE_NETWORK,
114 secmodel_suser_network_cb, NULL);
115 kauth_listen_scope(OVERLAY_ISCOPE_NETWORK,
116 secmodel_securelevel_network_cb, NULL);
117
118 kauth_listen_scope(OVERLAY_ISCOPE_MACHDEP,
119 secmodel_suser_machdep_cb, NULL);
120 kauth_listen_scope(OVERLAY_ISCOPE_MACHDEP,
121 secmodel_securelevel_machdep_cb, NULL);
122
123 kauth_listen_scope(OVERLAY_ISCOPE_DEVICE,
124 secmodel_suser_device_cb, NULL);
125 kauth_listen_scope(OVERLAY_ISCOPE_DEVICE,
126 secmodel_securelevel_device_cb, NULL);
127 }
128
129 SYSCTL_SETUP(sysctl_security_overlay_setup, "secmod overlay sysctl")
130 {
131 const struct sysctlnode *rnode;
132
133 sysctl_createv(clog, 0, NULL, &rnode,
134 CTLFLAG_PERMANENT,
135 CTLTYPE_NODE, "models", NULL,
136 NULL, 0, NULL, 0,
137 CTL_SECURITY, CTL_CREATE, CTL_EOL);
138
139 sysctl_createv(clog, 0, &rnode, &rnode,
140 CTLFLAG_PERMANENT,
141 CTLTYPE_NODE, "overlay",
142 SYSCTL_DESCR("Overlay security model on-top of bsd44"),
143 NULL, 0, NULL, 0,
144 CTL_CREATE, CTL_EOL);
145
146 sysctl_createv(clog, 0, &rnode, NULL,
147 CTLFLAG_PERMANENT,
148 CTLTYPE_STRING, "name", NULL,
149 NULL, 0, __UNCONST(SECMODEL_OVERLAY_NAME), 0,
150 CTL_CREATE, CTL_EOL);
151 }
152
153 /*
154 * Start the overlay security model.
155 */
156 void
secmodel_overlay_start(void)157 secmodel_overlay_start(void)
158 {
159 l_generic = kauth_listen_scope(KAUTH_SCOPE_GENERIC,
160 secmodel_overlay_generic_cb, NULL);
161 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
162 secmodel_overlay_system_cb, NULL);
163 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
164 secmodel_overlay_process_cb, NULL);
165 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
166 secmodel_overlay_network_cb, NULL);
167 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
168 secmodel_overlay_machdep_cb, NULL);
169 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
170 secmodel_overlay_device_cb, NULL);
171 l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
172 secmodel_overlay_vnode_cb, NULL);
173 }
174
175 /*
176 * Stop the overlay security model.
177 */
178 void
secmodel_overlay_stop(void)179 secmodel_overlay_stop(void)
180 {
181 kauth_unlisten_scope(l_generic);
182 kauth_unlisten_scope(l_system);
183 kauth_unlisten_scope(l_process);
184 kauth_unlisten_scope(l_network);
185 kauth_unlisten_scope(l_machdep);
186 kauth_unlisten_scope(l_device);
187 kauth_unlisten_scope(l_vnode);
188 }
189
190 static int
secmodel_overlay_modcmd(modcmd_t cmd,void * arg)191 secmodel_overlay_modcmd(modcmd_t cmd, void *arg)
192 {
193 int error = 0;
194
195 switch (cmd) {
196 case MODULE_CMD_INIT:
197 error = secmodel_register(&overlay_sm,
198 SECMODEL_OVERLAY_ID, SECMODEL_OVERLAY_NAME,
199 NULL, NULL, NULL);
200 if (error != 0)
201 printf("secmodel_overlay_modcmd::init: "
202 "secmodel_register returned %d\n", error);
203
204 secmodel_overlay_init();
205 secmodel_suser_stop();
206 secmodel_securelevel_stop();
207 secmodel_overlay_start();
208 break;
209
210 case MODULE_CMD_FINI:
211 secmodel_overlay_stop();
212
213 error = secmodel_deregister(overlay_sm);
214 if (error != 0)
215 printf("secmodel_overlay_modcmd::fini: "
216 "secmodel_deregister returned %d\n", error);
217 break;
218
219 case MODULE_CMD_AUTOUNLOAD:
220 error = EPERM;
221 break;
222
223 default:
224 error = ENOTTY;
225 break;
226 }
227
228 return error;
229 }
230
231 /*
232 * Overlay listener for the generic scope.
233 */
234 int
secmodel_overlay_generic_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)235 secmodel_overlay_generic_cb(kauth_cred_t cred, kauth_action_t action,
236 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
237 {
238 int result;
239
240 result = KAUTH_RESULT_DEFER;
241
242 switch (action) {
243 default:
244 result = KAUTH_RESULT_DEFER;
245 break;
246 }
247
248 if (result == KAUTH_RESULT_DEFER) {
249 result = kauth_authorize_action(
250 secmodel_overlay_iscope_generic, cred, action,
251 arg0, arg1, arg2, arg3);
252 }
253
254 return (result);
255 }
256
257 /*
258 * Overlay listener for the system scope.
259 */
260 int
secmodel_overlay_system_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)261 secmodel_overlay_system_cb(kauth_cred_t cred, kauth_action_t action,
262 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
263 {
264 int result;
265
266 result = KAUTH_RESULT_DEFER;
267
268 switch (action) {
269 default:
270 result = KAUTH_RESULT_DEFER;
271 break;
272 }
273
274 if (result == KAUTH_RESULT_DEFER) {
275 result = kauth_authorize_action(
276 secmodel_overlay_iscope_system, cred, action,
277 arg0, arg1, arg2, arg3);
278 }
279
280 return (result);
281 }
282
283 /*
284 * Overlay listener for the process scope.
285 */
286 int
secmodel_overlay_process_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)287 secmodel_overlay_process_cb(kauth_cred_t cred, kauth_action_t action,
288 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
289 {
290 int result;
291
292 result = KAUTH_RESULT_DEFER;
293
294 switch (action) {
295 default:
296 result = KAUTH_RESULT_DEFER;
297 break;
298 }
299
300 if (result == KAUTH_RESULT_DEFER) {
301 result = kauth_authorize_action(
302 secmodel_overlay_iscope_process, cred, action,
303 arg0, arg1, arg2, arg3);
304 }
305
306 return (result);
307 }
308
309 /*
310 * Overlay listener for the network scope.
311 */
312 int
secmodel_overlay_network_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)313 secmodel_overlay_network_cb(kauth_cred_t cred, kauth_action_t action,
314 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
315 {
316 int result;
317
318 result = KAUTH_RESULT_DEFER;
319
320 switch (action) {
321 default:
322 result = KAUTH_RESULT_DEFER;
323 break;
324 }
325
326 if (result == KAUTH_RESULT_DEFER) {
327 result = kauth_authorize_action(
328 secmodel_overlay_iscope_network, cred, action,
329 arg0, arg1, arg2, arg3);
330 }
331
332 return (result);
333 }
334
335 /*
336 * Overlay listener for the machdep scope.
337 */
338 int
secmodel_overlay_machdep_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)339 secmodel_overlay_machdep_cb(kauth_cred_t cred, kauth_action_t action,
340 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
341 {
342 int result;
343
344 result = KAUTH_RESULT_DEFER;
345
346 switch (action) {
347 default:
348 result = KAUTH_RESULT_DEFER;
349 break;
350 }
351
352 if (result == KAUTH_RESULT_DEFER) {
353 result = kauth_authorize_action(
354 secmodel_overlay_iscope_machdep, cred, action,
355 arg0, arg1, arg2, arg3);
356 }
357
358 return (result);
359 }
360
361 /*
362 * Overlay listener for the device scope.
363 */
364 int
secmodel_overlay_device_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)365 secmodel_overlay_device_cb(kauth_cred_t cred, kauth_action_t action,
366 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
367 {
368 int result;
369
370 result = KAUTH_RESULT_DEFER;
371
372 switch (action) {
373 default:
374 result = KAUTH_RESULT_DEFER;
375 break;
376 }
377
378 if (result == KAUTH_RESULT_DEFER) {
379 result = kauth_authorize_action(
380 secmodel_overlay_iscope_device, cred, action,
381 arg0, arg1, arg2, arg3);
382 }
383
384 return (result);
385 }
386
387 /*
388 * Overlay listener for the vnode scope.
389 */
390 int
secmodel_overlay_vnode_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)391 secmodel_overlay_vnode_cb(kauth_cred_t cred, kauth_action_t action,
392 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
393 {
394 int result;
395
396 result = KAUTH_RESULT_DEFER;
397
398 switch (action) {
399 default:
400 result = KAUTH_RESULT_DEFER;
401 break;
402 }
403
404 if (result == KAUTH_RESULT_DEFER) {
405 result = kauth_authorize_action(
406 secmodel_overlay_iscope_vnode, cred, action,
407 arg0, arg1, arg2, arg3);
408 }
409
410 return (result);
411 }
412