1168404Spjd/*- 2168404Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24168404Spjd * SUCH DAMAGE. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <sys/cdefs.h> 28168404Spjd__FBSDID("$FreeBSD$"); 29168404Spjd 30168404Spjd#include <sys/param.h> 31168404Spjd#include <sys/priv.h> 32168404Spjd#include <sys/vnode.h> 33185029Spjd#include <sys/mntent.h> 34168404Spjd#include <sys/mount.h> 35168404Spjd#include <sys/stat.h> 36185029Spjd#include <sys/jail.h> 37168404Spjd#include <sys/policy.h> 38185029Spjd#include <sys/zfs_vfsops.h> 39168404Spjd 40168404Spjdint 41219089Spjdsecpolicy_nfs(cred_t *cr) 42185029Spjd{ 43185029Spjd 44219089Spjd return (priv_check_cred(cr, PRIV_NFS_DAEMON, 0)); 45185029Spjd} 46185029Spjd 47185029Spjdint 48219089Spjdsecpolicy_zfs(cred_t *cr) 49168404Spjd{ 50168404Spjd 51219089Spjd return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); 52168404Spjd} 53168404Spjd 54168404Spjdint 55219089Spjdsecpolicy_sys_config(cred_t *cr, int checkonly __unused) 56168404Spjd{ 57168404Spjd 58219089Spjd return (priv_check_cred(cr, PRIV_ZFS_POOL_CONFIG, 0)); 59168404Spjd} 60168404Spjd 61168404Spjdint 62219089Spjdsecpolicy_zinject(cred_t *cr) 63168404Spjd{ 64168404Spjd 65219089Spjd return (priv_check_cred(cr, PRIV_ZFS_INJECT, 0)); 66168404Spjd} 67168404Spjd 68168404Spjdint 69219089Spjdsecpolicy_fs_unmount(cred_t *cr, struct mount *vfsp __unused) 70168404Spjd{ 71168404Spjd 72219089Spjd return (priv_check_cred(cr, PRIV_VFS_UNMOUNT, 0)); 73168404Spjd} 74168404Spjd 75185029Spjdint 76219089Spjdsecpolicy_fs_owner(struct mount *mp, cred_t *cr) 77185029Spjd{ 78185029Spjd 79185029Spjd if (zfs_super_owner) { 80219089Spjd if (cr->cr_uid == mp->mnt_cred->cr_uid && 81219089Spjd cr->cr_prison == mp->mnt_cred->cr_prison) { 82185029Spjd return (0); 83185029Spjd } 84185029Spjd } 85197860Spjd return (EPERM); 86185029Spjd} 87185029Spjd 88168404Spjd/* 89168404Spjd * This check is done in kern_link(), so we could just return 0 here. 90168404Spjd */ 91168404Spjdextern int hardlink_check_uid; 92168404Spjdint 93219089Spjdsecpolicy_basic_link(vnode_t *vp, cred_t *cr) 94168404Spjd{ 95168404Spjd 96168404Spjd if (!hardlink_check_uid) 97168404Spjd return (0); 98219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 99185029Spjd return (0); 100219089Spjd return (priv_check_cred(cr, PRIV_VFS_LINK, 0)); 101168404Spjd} 102168404Spjd 103168404Spjdint 104219089Spjdsecpolicy_vnode_stky_modify(cred_t *cr) 105168404Spjd{ 106168404Spjd 107168404Spjd return (EPERM); 108168404Spjd} 109168404Spjd 110168404Spjdint 111219089Spjdsecpolicy_vnode_remove(vnode_t *vp, cred_t *cr) 112168404Spjd{ 113168404Spjd 114219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 115185029Spjd return (0); 116219089Spjd return (priv_check_cred(cr, PRIV_VFS_ADMIN, 0)); 117168404Spjd} 118168404Spjd 119168404Spjdint 120219089Spjdsecpolicy_vnode_access(cred_t *cr, vnode_t *vp, uid_t owner, accmode_t accmode) 121168404Spjd{ 122168404Spjd 123219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 124185029Spjd return (0); 125185029Spjd 126219089Spjd if ((accmode & VREAD) && priv_check_cred(cr, PRIV_VFS_READ, 0) != 0) 127168404Spjd return (EACCES); 128184413Strasz if ((accmode & VWRITE) && 129219089Spjd priv_check_cred(cr, PRIV_VFS_WRITE, 0) != 0) { 130168404Spjd return (EACCES); 131168404Spjd } 132184413Strasz if (accmode & VEXEC) { 133168404Spjd if (vp->v_type == VDIR) { 134219089Spjd if (priv_check_cred(cr, PRIV_VFS_LOOKUP, 0) != 0) 135168404Spjd return (EACCES); 136168404Spjd } else { 137219089Spjd if (priv_check_cred(cr, PRIV_VFS_EXEC, 0) != 0) 138168404Spjd return (EACCES); 139168404Spjd } 140168404Spjd } 141168404Spjd return (0); 142168404Spjd} 143168404Spjd 144219089Spjd/* 145219089Spjd * Like secpolicy_vnode_access() but we get the actual wanted mode and the 146219089Spjd * current mode of the file, not the missing bits. 147219089Spjd */ 148168404Spjdint 149219089Spjdsecpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner, 150219089Spjd accmode_t curmode, accmode_t wantmode) 151168404Spjd{ 152219089Spjd accmode_t mode; 153168404Spjd 154219089Spjd mode = ~curmode & wantmode; 155219089Spjd 156219089Spjd if (mode == 0) 157168404Spjd return (0); 158219089Spjd 159219089Spjd return (secpolicy_vnode_access(cr, vp, owner, mode)); 160219089Spjd} 161219089Spjd 162219089Spjdint 163219089Spjdsecpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner) 164219089Spjd{ 165219089Spjd static int privs[] = { 166219089Spjd PRIV_VFS_ADMIN, 167219089Spjd PRIV_VFS_READ, 168219089Spjd PRIV_VFS_WRITE, 169219089Spjd PRIV_VFS_EXEC, 170219089Spjd PRIV_VFS_LOOKUP 171219089Spjd }; 172219089Spjd int i; 173219089Spjd 174219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 175185029Spjd return (0); 176219089Spjd 177219089Spjd /* Same as secpolicy_vnode_setdac */ 178219089Spjd if (owner == cr->cr_uid) 179219089Spjd return (0); 180219089Spjd 181219089Spjd for (i = 0; i < sizeof (privs)/sizeof (int); i++) { 182219089Spjd boolean_t allzone = B_FALSE; 183219089Spjd int priv; 184219089Spjd 185219089Spjd switch (priv = privs[i]) { 186219089Spjd case PRIV_VFS_EXEC: 187219089Spjd if (vp->v_type == VDIR) 188219089Spjd continue; 189219089Spjd break; 190219089Spjd case PRIV_VFS_LOOKUP: 191219089Spjd if (vp->v_type != VDIR) 192219089Spjd continue; 193219089Spjd break; 194219089Spjd } 195219089Spjd if (priv_check_cred(cr, priv, 0) == 0) 196219089Spjd return (0); 197219089Spjd } 198219089Spjd return (EPERM); 199168404Spjd} 200168404Spjd 201168404Spjdint 202219089Spjdsecpolicy_vnode_setdac(vnode_t *vp, cred_t *cr, uid_t owner) 203219089Spjd{ 204219089Spjd 205219089Spjd if (owner == cr->cr_uid) 206219089Spjd return (0); 207219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 208219089Spjd return (0); 209219089Spjd return (priv_check_cred(cr, PRIV_VFS_ADMIN, 0)); 210219089Spjd} 211219089Spjd 212219089Spjdint 213219089Spjdsecpolicy_vnode_setattr(cred_t *cr, vnode_t *vp, struct vattr *vap, 214168404Spjd const struct vattr *ovap, int flags, 215219089Spjd int unlocked_access(void *, int, cred_t *), void *node) 216168404Spjd{ 217168404Spjd int mask = vap->va_mask; 218168404Spjd int error; 219168404Spjd 220168404Spjd if (mask & AT_SIZE) { 221168404Spjd if (vp->v_type == VDIR) 222168404Spjd return (EISDIR); 223219089Spjd error = unlocked_access(node, VWRITE, cr); 224168404Spjd if (error) 225168404Spjd return (error); 226168404Spjd } 227168404Spjd if (mask & AT_MODE) { 228168404Spjd /* 229168404Spjd * If not the owner of the file then check privilege 230168404Spjd * for two things: the privilege to set the mode at all 231168404Spjd * and, if we're setting setuid, we also need permissions 232168404Spjd * to add the set-uid bit, if we're not the owner. 233168404Spjd * In the specific case of creating a set-uid root 234168404Spjd * file, we need even more permissions. 235168404Spjd */ 236219089Spjd error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid); 237168404Spjd if (error) 238168404Spjd return (error); 239219089Spjd error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cr); 240168404Spjd if (error) 241168404Spjd return (error); 242168404Spjd } else { 243168404Spjd vap->va_mode = ovap->va_mode; 244168404Spjd } 245168404Spjd if (mask & (AT_UID | AT_GID)) { 246219089Spjd error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid); 247168404Spjd if (error) 248168404Spjd return (error); 249168404Spjd 250168404Spjd /* 251168404Spjd * To change the owner of a file, or change the group of a file to a 252168404Spjd * group of which we are not a member, the caller must have 253168404Spjd * privilege. 254168404Spjd */ 255168404Spjd if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 256168404Spjd ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 257219089Spjd !groupmember(vap->va_gid, cr))) { 258219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) != 0) { 259219089Spjd error = priv_check_cred(cr, PRIV_VFS_CHOWN, 0); 260185029Spjd if (error) 261185029Spjd return (error); 262185029Spjd } 263168404Spjd } 264168404Spjd 265168404Spjd if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 266168404Spjd ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { 267219089Spjd secpolicy_setid_clear(vap, vp, cr); 268168404Spjd } 269168404Spjd } 270168404Spjd if (mask & (AT_ATIME | AT_MTIME)) { 271168404Spjd /* 272168404Spjd * From utimes(2): 273168404Spjd * If times is NULL, ... The caller must be the owner of 274168404Spjd * the file, have permission to write the file, or be the 275168404Spjd * super-user. 276168404Spjd * If times is non-NULL, ... The caller must be the owner of 277168404Spjd * the file or be the super-user. 278168404Spjd */ 279219089Spjd error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid); 280168404Spjd if (error && (vap->va_vaflags & VA_UTIMES_NULL)) 281219089Spjd error = unlocked_access(node, VWRITE, cr); 282168404Spjd if (error) 283168404Spjd return (error); 284168404Spjd } 285168404Spjd return (0); 286168404Spjd} 287168404Spjd 288168404Spjdint 289219089Spjdsecpolicy_vnode_create_gid(cred_t *cr) 290168404Spjd{ 291168404Spjd 292168404Spjd return (EPERM); 293168404Spjd} 294168404Spjd 295168404Spjdint 296219089Spjdsecpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cr, gid_t gid) 297168404Spjd{ 298219089Spjd 299219089Spjd if (groupmember(gid, cr)) 300185029Spjd return (0); 301219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 302185029Spjd return (0); 303219089Spjd return (priv_check_cred(cr, PRIV_VFS_SETGID, 0)); 304168404Spjd} 305168404Spjd 306168404Spjdint 307219089Spjdsecpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cr, 308185029Spjd boolean_t issuidroot __unused) 309168404Spjd{ 310168404Spjd 311219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 312185029Spjd return (0); 313219089Spjd return (priv_check_cred(cr, PRIV_VFS_RETAINSUGID, 0)); 314168404Spjd} 315168404Spjd 316168404Spjdvoid 317219089Spjdsecpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cr) 318168404Spjd{ 319168404Spjd 320219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 321185029Spjd return; 322185029Spjd 323168404Spjd if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { 324219089Spjd if (priv_check_cred(cr, PRIV_VFS_RETAINSUGID, 0)) { 325168404Spjd vap->va_mask |= AT_MODE; 326168404Spjd vap->va_mode &= ~(S_ISUID|S_ISGID); 327168404Spjd } 328168404Spjd } 329168404Spjd} 330168404Spjd 331168404Spjdint 332219089Spjdsecpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap, 333219089Spjd const struct vattr *ovap, cred_t *cr) 334168404Spjd{ 335168404Spjd int error; 336168404Spjd 337219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 338185029Spjd return (0); 339185029Spjd 340168404Spjd /* 341168404Spjd * Privileged processes may set the sticky bit on non-directories, 342168404Spjd * as well as set the setgid bit on a file with a group that the process 343168404Spjd * is not a member of. Both of these are allowed in jail(8). 344168404Spjd */ 345168404Spjd if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { 346219089Spjd if (priv_check_cred(cr, PRIV_VFS_STICKYFILE, 0)) 347168404Spjd return (EFTYPE); 348168404Spjd } 349168404Spjd /* 350168404Spjd * Check for privilege if attempting to set the 351168404Spjd * group-id bit. 352168404Spjd */ 353168404Spjd if ((vap->va_mode & S_ISGID) != 0) { 354219089Spjd error = secpolicy_vnode_setids_setgids(vp, cr, ovap->va_gid); 355168404Spjd if (error) 356168404Spjd return (error); 357168404Spjd } 358192694Strasz /* 359192694Strasz * Deny setting setuid if we are not the file owner. 360192694Strasz */ 361219089Spjd if ((vap->va_mode & S_ISUID) && ovap->va_uid != cr->cr_uid) { 362219089Spjd error = priv_check_cred(cr, PRIV_VFS_ADMIN, 0); 363192694Strasz if (error) 364192694Strasz return (error); 365192694Strasz } 366168404Spjd return (0); 367168404Spjd} 368185029Spjd 369185029Spjdint 370185029Spjdsecpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp) 371185029Spjd{ 372185029Spjd 373185029Spjd return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); 374185029Spjd} 375185029Spjd 376185029Spjdint 377219089Spjdsecpolicy_vnode_owner(vnode_t *vp, cred_t *cr, uid_t owner) 378185029Spjd{ 379185029Spjd 380219089Spjd if (owner == cr->cr_uid) 381185029Spjd return (0); 382219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 383185029Spjd return (0); 384185029Spjd 385185029Spjd /* XXX: vfs_suser()? */ 386219089Spjd return (priv_check_cred(cr, PRIV_VFS_MOUNT_OWNER, 0)); 387185029Spjd} 388185029Spjd 389185029Spjdint 390219089Spjdsecpolicy_vnode_chown(vnode_t *vp, cred_t *cr, uid_t owner) 391185029Spjd{ 392185029Spjd 393219089Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 394185029Spjd return (0); 395219089Spjd return (priv_check_cred(cr, PRIV_VFS_CHOWN, 0)); 396185029Spjd} 397185029Spjd 398185029Spjdvoid 399185029Spjdsecpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) 400185029Spjd{ 401185029Spjd 402185029Spjd if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) { 403185029Spjd MNT_ILOCK(vfsp); 404185029Spjd vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER; 405185029Spjd vfs_clearmntopt(vfsp, MNTOPT_SETUID); 406185029Spjd vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0); 407185029Spjd MNT_IUNLOCK(vfsp); 408185029Spjd } 409185029Spjd} 410185029Spjd 411185029Spjd/* 412185029Spjd * Check privileges for setting xvattr attributes 413185029Spjd */ 414185029Spjdint 415219089Spjdsecpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cr, 416197861Spjd vtype_t vtype) 417185029Spjd{ 418185029Spjd 419197861Spjd if (secpolicy_fs_owner(vp->v_mount, cr) == 0) 420197861Spjd return (0); 421185029Spjd return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); 422185029Spjd} 423209962Smm 424209962Smmint 425209962Smmsecpolicy_smb(cred_t *cr) 426209962Smm{ 427209962Smm 428209962Smm return (priv_check_cred(cr, PRIV_NETSMB, 0)); 429209962Smm} 430