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