xref: /netbsd-src/external/cddl/osnet/sys/kern/policy.c (revision 41fac1e5ad2093e1aa4fa9d01a013715fa402576)
1 /*	$NetBSD: policy.c,v 1.10 2022/03/30 16:34:27 christos 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
secpolicy_nfs(cred_t * cr)90 secpolicy_nfs(cred_t *cr)
91 {
92 
93 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
94 }
95 
96 int
secpolicy_zfs(cred_t * cred)97 secpolicy_zfs(cred_t *cred)
98 {
99 
100 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
101 }
102 
103 int
secpolicy_sys_config(cred_t * cred,int checkonly __unused)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
secpolicy_zinject(cred_t * cred)111 secpolicy_zinject(cred_t *cred)
112 {
113 
114 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
115 }
116 
117 int
secpolicy_fs_mount(cred_t * cred,vnode_t * mvp,struct mount * vfsp)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, mvp, KAUTH_ARG(vfsp->mnt_flag), NULL);
123 }
124 
125 int
secpolicy_fs_unmount(cred_t * cred,struct mount * vfsp)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
secpolicy_fs_owner(struct mount * mp,cred_t * cr)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
secpolicy_basic_link(vnode_t * vp,cred_t * cred)144 secpolicy_basic_link(vnode_t *vp, cred_t *cred)
145 {
146 
147 	return kauth_authorize_vnode(cred, KAUTH_VNODE_ADD_LINK, vp,
148 	    /* XXX dvp, currently unused */ NULL, 0);
149 }
150 
151 int
secpolicy_vnode_stky_modify(cred_t * cred)152 secpolicy_vnode_stky_modify(cred_t *cred)
153 {
154 
155 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
156 }
157 
158 int
secpolicy_vnode_remove(vnode_t * vp,cred_t * cred)159 secpolicy_vnode_remove(vnode_t *vp, cred_t *cred)
160 {
161 
162 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
163 }
164 
165 
166 int
secpolicy_vnode_owner(vnode_t * vp,cred_t * cred,uid_t owner)167 secpolicy_vnode_owner(vnode_t *vp, cred_t *cred, uid_t owner)
168 {
169 
170 	if (owner == kauth_cred_getuid(cred))
171 		return (0);
172 
173 	if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
174 		return (0);
175 
176 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
177 }
178 
179 int
secpolicy_vnode_access(cred_t * cred,vnode_t * vp,uid_t owner,accmode_t mode)180 secpolicy_vnode_access(cred_t *cred, vnode_t *vp, uid_t owner,
181     accmode_t mode)
182 {
183 
184 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
185 }
186 
187 /*
188  * Like secpolicy_vnode_access() but we get the actual wanted mode and the
189  * current mode of the file, not the missing bits.
190  */
191 int
secpolicy_vnode_access2(cred_t * cr,vnode_t * vp,uid_t owner,accmode_t curmode,accmode_t wantmode)192 secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
193     accmode_t curmode, accmode_t wantmode)
194 {
195 	accmode_t mode;
196 
197 	mode = ~curmode & wantmode;
198 
199 	if (mode == 0)
200 		return (0);
201 
202 	return (secpolicy_vnode_access(cr, vp, owner, mode));
203 }
204 
205 int
secpolicy_vnode_any_access(cred_t * cr,vnode_t * vp,uid_t owner)206 secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
207 {
208 
209 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
210 }
211 
212 int
secpolicy_xvattr(vnode_t * vp,xvattr_t * xvap,uid_t owner,cred_t * cred,vtype_t vtype)213 secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cred, vtype_t vtype)
214 {
215 
216 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
217 }
218 
219 int
secpolicy_vnode_setid_retain(vnode_t * vp,cred_t * cred,boolean_t issuidroot __unused)220 secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cred, boolean_t issuidroot __unused)
221 {
222 
223 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
224 }
225 
226 int
secpolicy_vnode_setids_setgids(vnode_t * vp,cred_t * cred,gid_t gid)227 secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cred, gid_t gid)
228 {
229 
230 	if (groupmember(gid, cred))
231 		return (0);
232 
233 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
234 }
235 
236 int
secpolicy_vnode_chown(vnode_t * vp,cred_t * cred,uid_t owner)237 secpolicy_vnode_chown(vnode_t *vp, cred_t *cred, uid_t owner)
238 {
239 
240 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
241 }
242 
243 int
secpolicy_vnode_create_gid(cred_t * cred)244 secpolicy_vnode_create_gid(cred_t *cred)
245 {
246 
247 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
248 }
249 
250 int
secpolicy_vnode_utime_modify(cred_t * cred)251 secpolicy_vnode_utime_modify(cred_t *cred)
252 {
253 
254 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
255 }
256 
257 int
secpolicy_vnode_setdac(vnode_t * vp,cred_t * cred,uid_t owner)258 secpolicy_vnode_setdac(vnode_t *vp, cred_t *cred, uid_t owner)
259 {
260 
261 	if (owner == kauth_cred_getuid(cred))
262 		return (0);
263 
264 	return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
265 }
266 
267 int
secpolicy_setid_setsticky_clear(vnode_t * vp,struct vattr * vap,const struct vattr * ovap,cred_t * cred)268 secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
269     const struct vattr *ovap, cred_t *cred)
270 {
271 	/*
272 	 * Privileged processes may set the sticky bit on non-directories,
273 	 * as well as set the setgid bit on a file with a group that the process
274 	 * is not a member of. Both of these are allowed in jail(8).
275 	 */
276 	if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
277 		if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL))
278 			return (EFTYPE);
279 	}
280 	/*
281 	 * Check for privilege if attempting to set the
282 	 * group-id bit.
283 	 */
284 	if ((vap->va_mode & S_ISGID) != 0)
285 		return (secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid));
286 
287 	return (0);
288 }
289 
290 /*
291  * XXX Copied from illumos.  Should not be here; should be under
292  * external/cddl/osnet/dist.  Not sure why it is even in illumos's
293  * policy.c rather than somewhere in vnode.c or something.
294  */
295 int
secpolicy_vnode_setattr(cred_t * cred,vnode_t * vp,struct vattr * vap,const struct vattr * ovap,int flags,int unlocked_access (void *,int,cred_t *),void * node)296 secpolicy_vnode_setattr(cred_t *cred, vnode_t *vp, struct vattr *vap,
297     const struct vattr *ovap, int flags,
298     int unlocked_access(void *, int, cred_t *), void *node)
299 {
300 	int mask = vap->va_mask;
301 	int error = 0;
302 	boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
303 
304 	if (mask & AT_SIZE) {
305 		if (vp->v_type == VDIR) {
306 			error = EISDIR;
307 			goto out;
308 		}
309 
310 		/*
311 		 * If ATTR_NOACLCHECK is set in the flags, then we don't
312 		 * perform the secondary unlocked_access() call since the
313 		 * ACL (if any) is being checked there.
314 		 */
315 		if (skipaclchk == B_FALSE) {
316 			error = unlocked_access(node, VWRITE, cred);
317 			if (error)
318 				goto out;
319 		}
320 	}
321 	if (mask & AT_MODE) {
322 		/*
323 		 * If not the owner of the file then check privilege
324 		 * for two things: the privilege to set the mode at all
325 		 * and, if we're setting setuid, we also need permissions
326 		 * to add the set-uid bit, if we're not the owner.
327 		 * In the specific case of creating a set-uid root
328 		 * file, we need even more permissions.
329 		 */
330 		if ((error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid)) != 0)
331 			goto out;
332 
333 		if ((error = secpolicy_setid_setsticky_clear(vp, vap,
334 		    ovap, cred)) != 0)
335 			goto out;
336 	} else
337 		vap->va_mode = ovap->va_mode;
338 
339 	if (mask & (AT_UID|AT_GID)) {
340 		boolean_t checkpriv = B_FALSE;
341 
342 		/*
343 		 * Chowning files.
344 		 *
345 		 * If you are the file owner:
346 		 *	chown to other uid		FILE_CHOWN_SELF
347 		 *	chown to gid (non-member) 	FILE_CHOWN_SELF
348 		 *	chown to gid (member) 		<none>
349 		 *
350 		 * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also
351 		 * acceptable but the first one is reported when debugging.
352 		 *
353 		 * If you are not the file owner:
354 		 *	chown from root			PRIV_FILE_CHOWN + zone
355 		 *	chown from other to any		PRIV_FILE_CHOWN
356 		 *
357 		 */
358 		if (kauth_cred_getuid(cred) != ovap->va_uid) {
359 			checkpriv = B_TRUE;
360 		} else {
361 			if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
362 			    ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
363 			    !groupmember(vap->va_gid, cred))) {
364 				checkpriv = B_TRUE;
365 			}
366 		}
367 		/*
368 		 * If necessary, check privilege to see if update can be done.
369 		 */
370 		if (checkpriv &&
371 		    (error = secpolicy_vnode_chown(vp, cred, ovap->va_uid)) != 0) {
372 			goto out;
373 		}
374 
375 		/*
376 		 * If the file has either the set UID or set GID bits
377 		 * set and the caller can set the bits, then leave them.
378 		 */
379 		secpolicy_setid_clear(vap, vp, cred);
380 	}
381 	if (mask & (AT_ATIME|AT_MTIME)) {
382 		/*
383 		 * If not the file owner and not otherwise privileged,
384 		 * always return an error when setting the
385 		 * time other than the current (ATTR_UTIME flag set).
386 		 * If setting the current time (ATTR_UTIME not set) then
387 		 * unlocked_access will check permissions according to policy.
388 		 */
389 		if (kauth_cred_getuid(cred) != ovap->va_uid) {
390 			if (flags & ATTR_UTIME)
391 				error = secpolicy_vnode_utime_modify(cred);
392 			else if (skipaclchk == B_FALSE) {
393 				error = unlocked_access(node, VWRITE, cred);
394 				if (error == EACCES &&
395 				    secpolicy_vnode_utime_modify(cred) == 0)
396 					error = 0;
397 			}
398 			if (error)
399 				goto out;
400 		}
401 	}
402 
403 	/*
404 	 * Check for optional attributes here by checking the following:
405 	 */
406 	if (mask & AT_XVATTR)
407 		error = secpolicy_xvattr(vp, (xvattr_t *)vap, ovap->va_uid,
408 		    cred, vp->v_type);
409 out:
410 	return (error);
411 }
412 
413 void
secpolicy_setid_clear(struct vattr * vap,vnode_t * vp,cred_t * cred)414 secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cred)
415 {
416 	if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0)
417 		return;
418 
419 	if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
420 		vap->va_mask |= AT_MODE;
421 		vap->va_mode &= ~(S_ISUID|S_ISGID);
422 	}
423 
424 	return;
425 }
426 
427 int
secpolicy_smb(cred_t * cr)428 secpolicy_smb(cred_t *cr)
429 {
430 
431 	return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
432 }
433 
434 void
secpolicy_fs_mount_clearopts(cred_t * cr,struct mount * vfsp)435 secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
436 {
437 
438 	printf("%s writeme\n", __func__);
439 }
440