1 /* $NetBSD: policy.c,v 1.2 2010/06/24 13:03:05 hannken 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 #include <sys/param.h> 59 #include <sys/priv.h> 60 #include <sys/vnode.h> 61 #include <sys/mount.h> 62 #include <sys/stat.h> 63 #include <sys/policy.h> 64 65 int 66 secpolicy_zfs(kauth_cred_t cred) 67 { 68 69 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 70 } 71 72 int 73 secpolicy_sys_config(kauth_cred_t cred, int checkonly __unused) 74 { 75 76 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 77 } 78 79 int 80 secpolicy_zinject(kauth_cred_t cred) 81 { 82 83 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 84 } 85 86 int 87 secpolicy_fs_mount(kauth_cred_t cred, vnode_t *mvp, struct mount *vfsp) 88 { 89 90 return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, 91 KAUTH_REQ_SYSTEM_MOUNT_NEW, vfsp, NULL, NULL); 92 } 93 94 int 95 secpolicy_fs_unmount(kauth_cred_t cred, struct mount *vfsp) 96 { 97 98 return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, 99 KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, vfsp, NULL, NULL); 100 } 101 102 /* 103 * This check is done in kern_link(), so we could just return 0 here. 104 */ 105 int 106 secpolicy_basic_link(kauth_cred_t cred) 107 { 108 109 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 110 } 111 112 int 113 secpolicy_vnode_stky_modify(kauth_cred_t cred) 114 { 115 116 return (EPERM); 117 } 118 119 int 120 secpolicy_vnode_remove(kauth_cred_t cred) 121 { 122 123 return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 124 } 125 126 127 int 128 secpolicy_vnode_owner(cred_t *cred, uid_t owner) 129 { 130 uid_t uid; 131 132 uid = crgetuid(cred); 133 134 if (owner == uid) 135 return (0); 136 137 return 0; 138 // return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, 139 // KAUTH_REQ_SYSTEM_MOUNT_NEW, vfsp, NULL, NULL); 140 } 141 142 int 143 secpolicy_vnode_access(kauth_cred_t cred, struct vnode *vp, uint64_t owner, 144 int mode) 145 { 146 int error; 147 148 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 149 error = VOP_ACCESS(vp, mode, cred); 150 VOP_UNLOCK(vp); 151 return error; 152 } 153 154 /* 155 * Check privileges for setting xvattr attributes 156 */ 157 int 158 secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 159 { 160 /* return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, 161 KAUTH_REQ_SYSTEM_MOUNT_UPDATE, vfsp, NULL, NULL);*/ 162 return 0; 163 } 164 165 int 166 secpolicy_vnode_setid_retain(kauth_cred_t cred, boolean_t issuidroot __unused) 167 { 168 169 return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)); 170 } 171 172 int 173 secpolicy_vnode_setids_setgids(kauth_cred_t cred, gid_t gid) 174 { 175 176 if (!groupmember(gid, cred)) 177 return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 178 NULL)); 179 return (0); 180 } 181 182 int 183 secpolicy_vnode_chown(struct kauth_cred *cred, boolean_t check_self) 184 { 185 186 return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 187 NULL)); 188 /* return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0)); */ 189 } 190 191 int 192 secpolicy_vnode_create_gid(struct kauth_cred *cred) 193 { 194 195 return (EPERM); 196 } 197 198 int 199 secpolicy_vnode_setdac(struct kauth_cred *cred, uid_t owner) 200 { 201 202 return 0; 203 /*return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));*/ 204 } 205 206 int 207 secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, 208 const struct vattr *ovap, kauth_cred_t cred) 209 { 210 /* 211 * Privileged processes may set the sticky bit on non-directories, 212 * as well as set the setgid bit on a file with a group that the process 213 * is not a member of. Both of these are allowed in jail(8). 214 */ 215 if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 216 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0) 217 return (EFTYPE); 218 } 219 /* 220 * Check for privilege if attempting to set the 221 * group-id bit. 222 */ 223 if ((vap->va_mode & S_ISGID) != 0) 224 return (secpolicy_vnode_setids_setgids(cred, ovap->va_gid)); 225 226 return (0); 227 } 228 229 int 230 secpolicy_vnode_setattr(kauth_cred_t cred, struct vnode *vp, struct vattr *vap, 231 const struct vattr *ovap, int flags, 232 int unlocked_access(void *, int, kauth_cred_t ), void *node) 233 { 234 235 return 0; 236 } 237 238 void 239 secpolicy_setid_clear(struct vattr *vap, kauth_cred_t cred) 240 { 241 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0) 242 return; 243 244 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 245 vap->va_mask |= AT_MODE; 246 vap->va_mode &= ~(S_ISUID|S_ISGID); 247 } 248 249 return; 250 } 251 252 #ifdef notyet 253 int 254 secpolicy_vnode_setdac(kauth_cred_t cred, uid_t owner) 255 { 256 257 if (owner == cred->cr_uid) 258 return (0); 259 return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); 260 } 261 262 int 263 secpolicy_vnode_setattr(kauth_cred_t cred, struct vnode *vp, struct vattr *vap, 264 const struct vattr *ovap, int flags, 265 int unlocked_access(void *, int, kauth_cred_t ), void *node) 266 { 267 int mask = vap->va_mask; 268 int error; 269 270 if (mask & AT_SIZE) { 271 if (vp->v_type == VDIR) 272 return (EISDIR); 273 error = unlocked_access(node, VWRITE, cred); 274 if (error) 275 return (error); 276 } 277 if (mask & AT_MODE) { 278 /* 279 * If not the owner of the file then check privilege 280 * for two things: the privilege to set the mode at all 281 * and, if we're setting setuid, we also need permissions 282 * to add the set-uid bit, if we're not the owner. 283 * In the specific case of creating a set-uid root 284 * file, we need even more permissions. 285 */ 286 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 287 if (error) 288 return (error); 289 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); 290 if (error) 291 return (error); 292 } else { 293 vap->va_mode = ovap->va_mode; 294 } 295 if (mask & (AT_UID | AT_GID)) { 296 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 297 if (error) 298 return (error); 299 300 /* 301 * To change the owner of a file, or change the group of a file to a 302 * group of which we are not a member, the caller must have 303 * privilege. 304 */ 305 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 306 ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 307 !groupmember(vap->va_gid, cred))) { 308 error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); 309 if (error) 310 return (error); 311 } 312 313 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 314 ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 315 secpolicy_setid_clear(vap, cred); 316 } 317 } 318 if (mask & (AT_ATIME | AT_MTIME)) { 319 /* 320 * From utimes(2): 321 * If times is NULL, ... The caller must be the owner of 322 * the file, have permission to write the file, or be the 323 * super-user. 324 * If times is non-NULL, ... The caller must be the owner of 325 * the file or be the super-user. 326 */ 327 error = secpolicy_vnode_setdac(cred, ovap->va_uid); 328 if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 329 error = unlocked_access(node, VWRITE, cred); 330 if (error) 331 return (error); 332 } 333 return (0); 334 } 335 336 int 337 secpolicy_vnode_create_gid(kauth_cred_t cred) 338 { 339 340 return (EPERM); 341 } 342 343 int 344 secpolicy_vnode_setid_retain(kauth_cred_t cred, boolean_t issuidroot __unused) 345 { 346 347 return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); 348 } 349 350 void 351 secpolicy_setid_clear(struct vattr *vap, kauth_cred_t cred) 352 { 353 354 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) 355 return; 356 357 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 358 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 359 vap->va_mask |= AT_MODE; 360 vap->va_mode &= ~(S_ISUID|S_ISGID); 361 } 362 } 363 } 364 #endif 365