1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 25 * Copyright 2013, Joyent, Inc. All rights reserved. 26 * Copyright (C) 2016 Lawrence Livermore National Security, LLC. 27 * Copyright (c) 2025, Rob Norris <robn@despairlabs.com> 28 * 29 * For Linux the vast majority of this enforcement is already handled via 30 * the standard Linux VFS permission checks. However certain administrative 31 * commands which bypass the standard mechanisms may need to make use of 32 * this functionality. 33 */ 34 35 #include <sys/policy.h> 36 #include <linux/security.h> 37 #include <linux/vfs_compat.h> 38 39 static int 40 priv_policy_ns(const cred_t *cr, int capability, int err, 41 struct user_namespace *ns) 42 { 43 /* 44 * The passed credentials cannot be directly verified because Linux 45 * only provides an interface to check the *current* process 46 * credentials. In order to handle this we check if the passed in 47 * creds match the current process credentials or the kcred. If not, 48 * we swap the passed credentials into the current task, perform the 49 * check, and then revert it before returning. 50 */ 51 const cred_t *old = 52 (cr != CRED() && cr != kcred) ? override_creds(cr) : NULL; 53 54 #if defined(CONFIG_USER_NS) 55 if (ns ? ns_capable(ns, capability) : capable(capability)) 56 #else 57 if (capable(capability)) 58 #endif 59 err = 0; 60 61 if (old) 62 revert_creds(old); 63 64 return (err); 65 } 66 67 static int 68 priv_policy(const cred_t *cr, int capability, int err) 69 { 70 return (priv_policy_ns(cr, capability, err, cr->user_ns)); 71 } 72 73 static int 74 priv_policy_user(const cred_t *cr, int capability, int err) 75 { 76 /* 77 * All priv_policy_user checks are preceded by kuid/kgid_has_mapping() 78 * checks. If we cannot do them, we shouldn't be using ns_capable() 79 * since we don't know whether the affected files are valid in our 80 * namespace. 81 */ 82 #if defined(CONFIG_USER_NS) 83 return (priv_policy_ns(cr, capability, err, cr->user_ns)); 84 #else 85 return (priv_policy_ns(cr, capability, err, NULL)); 86 #endif 87 } 88 89 /* 90 * Checks for operations that are either client-only or are used by 91 * both clients and servers. 92 */ 93 int 94 secpolicy_nfs(const cred_t *cr) 95 { 96 return (priv_policy(cr, CAP_SYS_ADMIN, EPERM)); 97 } 98 99 /* 100 * Catch all system configuration. 101 */ 102 int 103 secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 104 { 105 return (priv_policy(cr, CAP_SYS_ADMIN, EPERM)); 106 } 107 108 /* 109 * Like secpolicy_vnode_access() but we get the actual wanted mode and the 110 * current mode of the file, not the missing bits. 111 * 112 * Enforced in the Linux VFS. 113 */ 114 int 115 secpolicy_vnode_access2(const cred_t *cr, struct inode *ip, uid_t owner, 116 mode_t curmode, mode_t wantmode) 117 { 118 return (0); 119 } 120 121 /* 122 * This is a special routine for ZFS; it is used to determine whether 123 * any of the privileges in effect allow any form of access to the 124 * file. There's no reason to audit this or any reason to record 125 * this. More work is needed to do the "KPLD" stuff. 126 */ 127 int 128 secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) 129 { 130 if (crgetuid(cr) == owner) 131 return (0); 132 133 if (zpl_inode_owner_or_capable(zfs_init_idmap, ip)) 134 return (0); 135 136 #if defined(CONFIG_USER_NS) 137 if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) 138 return (EPERM); 139 #endif 140 141 if (priv_policy_user(cr, CAP_DAC_OVERRIDE, EPERM) == 0) 142 return (0); 143 144 if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, EPERM) == 0) 145 return (0); 146 147 return (EPERM); 148 } 149 150 /* 151 * Determine if subject can chown owner of a file. 152 */ 153 int 154 secpolicy_vnode_chown(const cred_t *cr, uid_t owner) 155 { 156 if (crgetuid(cr) == owner) 157 return (0); 158 159 #if defined(CONFIG_USER_NS) 160 if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) 161 return (EPERM); 162 #endif 163 164 return (priv_policy_user(cr, CAP_FOWNER, EPERM)); 165 } 166 167 /* 168 * Determine if subject can change group ownership of a file. 169 */ 170 int 171 secpolicy_vnode_create_gid(const cred_t *cr) 172 { 173 return (priv_policy(cr, CAP_SETGID, EPERM)); 174 } 175 176 /* 177 * Policy determines whether we can remove an entry from a directory, 178 * regardless of permission bits. 179 */ 180 int 181 secpolicy_vnode_remove(const cred_t *cr) 182 { 183 return (priv_policy(cr, CAP_FOWNER, EPERM)); 184 } 185 186 /* 187 * Determine that subject can modify the mode of a file. allzone privilege 188 * needed when modifying root owned object. 189 */ 190 int 191 secpolicy_vnode_setdac(const cred_t *cr, uid_t owner) 192 { 193 if (crgetuid(cr) == owner) 194 return (0); 195 196 #if defined(CONFIG_USER_NS) 197 if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) 198 return (EPERM); 199 #endif 200 201 return (priv_policy_user(cr, CAP_FOWNER, EPERM)); 202 } 203 204 /* 205 * Are we allowed to retain the set-uid/set-gid bits when 206 * changing ownership or when writing to a file? 207 * "issuid" should be true when set-uid; only in that case 208 * root ownership is checked (setgid is assumed). 209 * 210 * Enforced in the Linux VFS. 211 */ 212 int 213 secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr, 214 boolean_t issuidroot) 215 { 216 return (priv_policy_user(cr, CAP_FSETID, EPERM)); 217 } 218 219 /* 220 * Determine that subject can set the file setgid flag. 221 */ 222 int 223 secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zidmap_t *mnt_ns, 224 struct user_namespace *fs_ns) 225 { 226 gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid); 227 #if defined(CONFIG_USER_NS) 228 if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid))) 229 return (EPERM); 230 #endif 231 if (crgetgid(cr) != gid && !groupmember(gid, cr)) 232 return (priv_policy_user(cr, CAP_FSETID, EPERM)); 233 234 return (0); 235 } 236 237 /* 238 * Determine if the subject can inject faults in the ZFS fault injection 239 * framework. Requires all privileges. 240 */ 241 int 242 secpolicy_zinject(const cred_t *cr) 243 { 244 return (priv_policy(cr, CAP_SYS_ADMIN, EACCES)); 245 } 246 247 /* 248 * Determine if the subject has permission to manipulate ZFS datasets 249 * (not pools). Equivalent to the SYS_MOUNT privilege. 250 */ 251 int 252 secpolicy_zfs(const cred_t *cr) 253 { 254 return (priv_policy(cr, CAP_SYS_ADMIN, EACCES)); 255 } 256 257 void 258 secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 259 { 260 if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 261 secpolicy_vnode_setid_retain(NULL, cr, 262 (vap->va_mode & S_ISUID) != 0 && 263 (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 264 vap->va_mask |= AT_MODE; 265 vap->va_mode &= ~(S_ISUID|S_ISGID); 266 } 267 } 268 269 /* 270 * Determine that subject can set the file setid flags. 271 */ 272 static int 273 secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zidmap_t *mnt_ns, 274 struct user_namespace *fs_ns) 275 { 276 owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner); 277 278 if (crgetuid(cr) == owner) 279 return (0); 280 281 #if defined(CONFIG_USER_NS) 282 if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) 283 return (EPERM); 284 #endif 285 286 return (priv_policy_user(cr, CAP_FSETID, EPERM)); 287 } 288 289 /* 290 * Determine that subject can make a file a "sticky". 291 * 292 * Enforced in the Linux VFS. 293 */ 294 static int 295 secpolicy_vnode_stky_modify(const cred_t *cr) 296 { 297 return (0); 298 } 299 300 int 301 secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap, 302 const vattr_t *ovap, cred_t *cr, zidmap_t *mnt_ns, 303 struct user_namespace *fs_ns) 304 { 305 int error; 306 307 if ((vap->va_mode & S_ISUID) != 0 && 308 (error = secpolicy_vnode_setid_modify(cr, 309 ovap->va_uid, mnt_ns, fs_ns)) != 0) { 310 return (error); 311 } 312 313 /* 314 * Check privilege if attempting to set the 315 * sticky bit on a non-directory. 316 */ 317 if (!S_ISDIR(ip->i_mode) && (vap->va_mode & S_ISVTX) != 0 && 318 secpolicy_vnode_stky_modify(cr) != 0) { 319 vap->va_mode &= ~S_ISVTX; 320 } 321 322 /* 323 * Check for privilege if attempting to set the 324 * group-id bit. 325 */ 326 if ((vap->va_mode & S_ISGID) != 0 && 327 secpolicy_vnode_setids_setgids(cr, ovap->va_gid, 328 mnt_ns, fs_ns) != 0) { 329 vap->va_mode &= ~S_ISGID; 330 } 331 332 return (0); 333 } 334 335 /* 336 * Check privileges for setting xvattr attributes 337 */ 338 int 339 secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, mode_t type) 340 { 341 return (secpolicy_vnode_chown(cr, owner)); 342 } 343 344 /* 345 * Check privileges for setattr attributes. 346 * 347 * Enforced in the Linux VFS. 348 */ 349 int 350 secpolicy_vnode_setattr(cred_t *cr, struct inode *ip, struct vattr *vap, 351 const struct vattr *ovap, int flags, 352 int unlocked_access(void *, int, cred_t *), void *node) 353 { 354 return (0); 355 } 356 357 /* 358 * Check privileges for links. 359 * 360 * Enforced in the Linux VFS. 361 */ 362 int 363 secpolicy_basic_link(const cred_t *cr) 364 { 365 return (0); 366 } 367