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