xref: /netbsd-src/external/cddl/osnet/sys/kern/policy.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: policy.c,v 1.7 2018/05/28 21:05:09 chs Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*-
33  * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  */
57 
58 /*
59  * CDDL HEADER START
60  *
61  * The contents of this file are subject to the terms of the
62  * Common Development and Distribution License (the "License").
63  * You may not use this file except in compliance with the License.
64  *
65  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
66  * or http://www.opensolaris.org/os/licensing.
67  * See the License for the specific language governing permissions
68  * and limitations under the License.
69  *
70  * When distributing Covered Code, include this CDDL HEADER in each
71  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
72  * If applicable, add the following below this CDDL HEADER, with the
73  * fields enclosed by brackets "[]" replaced with your own identifying
74  * information: Portions Copyright [yyyy] [name of copyright owner]
75  *
76  * CDDL HEADER END
77  */
78 /*
79  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
80  * Copyright 2012, Joyent, Inc. All rights reserved.
81  */
82 
83 #include <sys/param.h>
84 #include <sys/vnode.h>
85 #include <sys/mount.h>
86 #include <sys/stat.h>
87 #include <sys/policy.h>
88 
89 int
90 secpolicy_nfs(cred_t *cr)
91 {
92 
93 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
94 }
95 
96 int
97 secpolicy_zfs(cred_t *cred)
98 {
99 
100 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
101 }
102 
103 int
104 secpolicy_sys_config(cred_t *cred, int checkonly __unused)
105 {
106 
107 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
108 }
109 
110 int
111 secpolicy_zinject(cred_t *cred)
112 {
113 
114 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
115 }
116 
117 int
118 secpolicy_fs_mount(cred_t *cred, vnode_t *mvp, struct mount *vfsp)
119 {
120 
121 	return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT,
122 	    KAUTH_REQ_SYSTEM_MOUNT_NEW, vfsp, NULL, NULL);
123 }
124 
125 int
126 secpolicy_fs_unmount(cred_t *cred, struct mount *vfsp)
127 {
128 
129 	return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT,
130 	    KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, vfsp, NULL, NULL);
131 }
132 
133 int
134 secpolicy_fs_owner(struct mount *mp, cred_t *cr)
135 {
136 
137 	return (EPERM);
138 }
139 
140 /*
141  * This check is done in kern_link(), so we could just return 0 here.
142  */
143 int
144 secpolicy_basic_link(vnode_t *vp, cred_t *cred)
145 {
146 
147 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
148 }
149 
150 int
151 secpolicy_vnode_stky_modify(cred_t *cred)
152 {
153 
154 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
155 }
156 
157 int
158 secpolicy_vnode_remove(vnode_t *vp, cred_t *cred)
159 {
160 
161 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
162 }
163 
164 
165 int
166 secpolicy_vnode_owner(vnode_t *vp, cred_t *cred, uid_t owner)
167 {
168 
169 	if (owner == kauth_cred_getuid(cred))
170 		return (0);
171 
172 	if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
173 		return (0);
174 
175 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
176 }
177 
178 int
179 secpolicy_vnode_access(cred_t *cred, vnode_t *vp, uid_t owner,
180     int mode)
181 {
182 
183 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
184 }
185 
186 /*
187  * Like secpolicy_vnode_access() but we get the actual wanted mode and the
188  * current mode of the file, not the missing bits.
189  */
190 int
191 secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
192     accmode_t curmode, accmode_t wantmode)
193 {
194 	accmode_t mode;
195 
196 	mode = ~curmode & wantmode;
197 
198 	if (mode == 0)
199 		return (0);
200 
201 	return (secpolicy_vnode_access(cr, vp, owner, mode));
202 }
203 
204 int
205 secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
206 {
207 
208 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
209 }
210 
211 int
212 secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cred, vtype_t vtype)
213 {
214 
215 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
216 }
217 
218 int
219 secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cred, boolean_t issuidroot __unused)
220 {
221 
222 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
223 }
224 
225 int
226 secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cred, gid_t gid)
227 {
228 
229 	if (groupmember(gid, cred))
230 		return (0);
231 
232 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
233 }
234 
235 int
236 secpolicy_vnode_chown(vnode_t *vp, cred_t *cred, uid_t owner)
237 {
238 
239 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
240 }
241 
242 int
243 secpolicy_vnode_create_gid(cred_t *cred)
244 {
245 
246 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
247 }
248 
249 int
250 secpolicy_vnode_utime_modify(cred_t *cred)
251 {
252 
253 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
254 }
255 
256 int
257 secpolicy_vnode_setdac(vnode_t *vp, cred_t *cred, uid_t owner)
258 {
259 
260 	if (owner == kauth_cred_getuid(cred))
261 		return (0);
262 
263 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
264 }
265 
266 int
267 secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
268     const struct vattr *ovap, cred_t *cred)
269 {
270 	/*
271 	 * Privileged processes may set the sticky bit on non-directories,
272 	 * as well as set the setgid bit on a file with a group that the process
273 	 * is not a member of. Both of these are allowed in jail(8).
274 	 */
275 	if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
276 		if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL))
277 			return (EFTYPE);
278 	}
279 	/*
280 	 * Check for privilege if attempting to set the
281 	 * group-id bit.
282 	 */
283 	if ((vap->va_mode & S_ISGID) != 0)
284 		return (secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid));
285 
286 	return (0);
287 }
288 
289 /*
290  * XXX Copied from illumos.  Should not be here; should be under
291  * external/cddl/osnet/dist.  Not sure why it is even in illumos's
292  * policy.c rather than somewhere in vnode.c or something.
293  */
294 int
295 secpolicy_vnode_setattr(cred_t *cred, vnode_t *vp, struct vattr *vap,
296     const struct vattr *ovap, int flags,
297     int unlocked_access(void *, int, cred_t *), void *node)
298 {
299 	int mask = vap->va_mask;
300 	int error = 0;
301 	boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
302 
303 	if (mask & AT_SIZE) {
304 		if (vp->v_type == VDIR) {
305 			error = EISDIR;
306 			goto out;
307 		}
308 
309 		/*
310 		 * If ATTR_NOACLCHECK is set in the flags, then we don't
311 		 * perform the secondary unlocked_access() call since the
312 		 * ACL (if any) is being checked there.
313 		 */
314 		if (skipaclchk == B_FALSE) {
315 			error = unlocked_access(node, VWRITE, cred);
316 			if (error)
317 				goto out;
318 		}
319 	}
320 	if (mask & AT_MODE) {
321 		/*
322 		 * If not the owner of the file then check privilege
323 		 * for two things: the privilege to set the mode at all
324 		 * and, if we're setting setuid, we also need permissions
325 		 * to add the set-uid bit, if we're not the owner.
326 		 * In the specific case of creating a set-uid root
327 		 * file, we need even more permissions.
328 		 */
329 		if ((error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid)) != 0)
330 			goto out;
331 
332 		if ((error = secpolicy_setid_setsticky_clear(vp, vap,
333 		    ovap, cred)) != 0)
334 			goto out;
335 	} else
336 		vap->va_mode = ovap->va_mode;
337 
338 	if (mask & (AT_UID|AT_GID)) {
339 		boolean_t checkpriv = B_FALSE;
340 
341 		/*
342 		 * Chowning files.
343 		 *
344 		 * If you are the file owner:
345 		 *	chown to other uid		FILE_CHOWN_SELF
346 		 *	chown to gid (non-member) 	FILE_CHOWN_SELF
347 		 *	chown to gid (member) 		<none>
348 		 *
349 		 * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also
350 		 * acceptable but the first one is reported when debugging.
351 		 *
352 		 * If you are not the file owner:
353 		 *	chown from root			PRIV_FILE_CHOWN + zone
354 		 *	chown from other to any		PRIV_FILE_CHOWN
355 		 *
356 		 */
357 		if (kauth_cred_getuid(cred) != ovap->va_uid) {
358 			checkpriv = B_TRUE;
359 		} else {
360 			if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
361 			    ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
362 			    !groupmember(vap->va_gid, cred))) {
363 				checkpriv = B_TRUE;
364 			}
365 		}
366 		/*
367 		 * If necessary, check privilege to see if update can be done.
368 		 */
369 		if (checkpriv &&
370 		    (error = secpolicy_vnode_chown(vp, cred, ovap->va_uid)) != 0) {
371 			goto out;
372 		}
373 
374 		/*
375 		 * If the file has either the set UID or set GID bits
376 		 * set and the caller can set the bits, then leave them.
377 		 */
378 		secpolicy_setid_clear(vap, vp, cred);
379 	}
380 	if (mask & (AT_ATIME|AT_MTIME)) {
381 		/*
382 		 * If not the file owner and not otherwise privileged,
383 		 * always return an error when setting the
384 		 * time other than the current (ATTR_UTIME flag set).
385 		 * If setting the current time (ATTR_UTIME not set) then
386 		 * unlocked_access will check permissions according to policy.
387 		 */
388 		if (kauth_cred_getuid(cred) != ovap->va_uid) {
389 			if (flags & ATTR_UTIME)
390 				error = secpolicy_vnode_utime_modify(cred);
391 			else if (skipaclchk == B_FALSE) {
392 				error = unlocked_access(node, VWRITE, cred);
393 				if (error == EACCES &&
394 				    secpolicy_vnode_utime_modify(cred) == 0)
395 					error = 0;
396 			}
397 			if (error)
398 				goto out;
399 		}
400 	}
401 
402 	/*
403 	 * Check for optional attributes here by checking the following:
404 	 */
405 	if (mask & AT_XVATTR)
406 		error = secpolicy_xvattr(vp, (xvattr_t *)vap, ovap->va_uid,
407 		    cred, vp->v_type);
408 out:
409 	return (error);
410 }
411 
412 void
413 secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cred)
414 {
415 	if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0)
416 		return;
417 
418 	if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
419 		vap->va_mask |= AT_MODE;
420 		vap->va_mode &= ~(S_ISUID|S_ISGID);
421 	}
422 
423 	return;
424 }
425 
426 int
427 secpolicy_smb(cred_t *cr)
428 {
429 
430 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
431 }
432 
433 void
434 secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
435 {
436 
437 	printf("%s writeme\n", __func__);
438 }
439