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 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, mvp, KAUTH_ARG(vfsp->mnt_flag), 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_vnode(cred, KAUTH_VNODE_ADD_LINK, vp, 148 /* XXX dvp, currently unused */ NULL, 0); 149 } 150 151 int 152 secpolicy_vnode_stky_modify(cred_t *cred) 153 { 154 155 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 156 } 157 158 int 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 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 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 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 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 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 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 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 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 244 secpolicy_vnode_create_gid(cred_t *cred) 245 { 246 247 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 248 } 249 250 int 251 secpolicy_vnode_utime_modify(cred_t *cred) 252 { 253 254 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 255 } 256 257 int 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 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 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 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 428 secpolicy_smb(cred_t *cr) 429 { 430 431 return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL); 432 } 433 434 void 435 secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) 436 { 437 438 printf("%s writeme\n", __func__); 439 } 440