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