Print this page
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs (cleanup)
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs (cleanup)
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs (part 2)
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs (part 2)
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-15035 Allow user ACE in ACL to match SID in token extra SIDs
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-10069 ZFS_READONLY is a little too strict
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
OS-158 zfs_zaccess_delete() comments do not accurately reflect delete permissions for ACLs
OS-40 zfs issues with inheritance flags during chmod(2) with aclmode=passthrough
OS-139 POSIX write should imply DELETE_CHILD on directories - and some additional considerations (fix lint)
OS-123 aclinherit=restricted masks inherited permissions by group perms (groupmask)
OS-139 POSIX write should imply DELETE_CHILD on directories - and some additional considerations
Fixup merge results
re #12585 rb4049 ZFS++ work port - refactoring to improve separation of open/closed code, bug fixes, performance improvements - open code
re #6815 rb1758 need WORM in nza-kernel (4.0)

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. ! * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/types.h> #include <sys/param.h> #include <sys/time.h>
*** 52,61 **** --- 52,63 ---- #include <sys/dnode.h> #include <sys/zap.h> #include <sys/sa.h> #include "fs/fs_subr.h" #include <acl/acl_common.h> + #include <c2/audit.h> + #include <c2/audit_kernel.h> #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE #define DENY ACE_ACCESS_DENIED_ACE_TYPE #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE #define MIN_ACE_TYPE ALLOW
*** 1186,1196 **** zfs_acl_locator_cb_t locate = { 0 }; uint64_t mode; sa_bulk_attr_t bulk[5]; uint64_t ctime[2]; int count = 0; - zfs_acl_phys_t acl_phys; mode = zp->z_mode; mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, zp->z_uid, zp->z_gid); --- 1188,1197 ----
*** 1233,1242 **** --- 1234,1244 ---- SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), NULL, &aclp->z_acl_count, sizeof (uint64_t)); } else { /* Painful legacy way */ zfs_acl_node_t *aclnode; uint64_t off = 0; + zfs_acl_phys_t acl_phys; uint64_t aoid; if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), &acl_phys, sizeof (acl_phys))) != 0) return (error);
*** 2081,2108 **** * working_mode is not a denied access mask upon exit if the function * is used in this manner. */ static int zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, ! boolean_t anyaccess, cred_t *cr) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; zfs_acl_t *aclp; int error; ! uid_t uid = crgetuid(cr); ! uint64_t who; uint16_t type, iflags; uint16_t entry_type; uint32_t access_mask; uint32_t deny_mask = 0; zfs_ace_hdr_t *acep = NULL; ! boolean_t checkit; ! uid_t gowner; ! uid_t fowner; - zfs_fuid_map_ids(zp, cr, &fowner, &gowner); - mutex_enter(&zp->z_acl_lock); error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); if (error != 0) { mutex_exit(&zp->z_acl_lock); --- 2083,2108 ---- * working_mode is not a denied access mask upon exit if the function * is used in this manner. */ static int zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, ! boolean_t anyaccess, cred_t *cr, boolean_t audit) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; zfs_acl_t *aclp; int error; ! uint64_t who; /* FUID from the ACE */ uint16_t type, iflags; uint16_t entry_type; uint32_t access_mask; uint32_t deny_mask = 0; + uint32_t sys_smask = 0; + uint32_t sys_fmask = 0; zfs_ace_hdr_t *acep = NULL; ! boolean_t checkit; /* ACE ID matches */ ! t_audit_data_t *tad; mutex_enter(&zp->z_acl_lock); error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); if (error != 0) { mutex_exit(&zp->z_acl_lock);
*** 2121,2196 **** if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) continue; /* Skip ACE if it does not affect any AoI */ mask_matched = (access_mask & *working_mode); ! if (!mask_matched) continue; entry_type = (iflags & ACE_TYPE_FLAGS); checkit = B_FALSE; switch (entry_type) { case ACE_OWNER: ! if (uid == fowner) ! checkit = B_TRUE; break; case OWNING_GROUP: ! who = gowner; /*FALLTHROUGH*/ case ACE_IDENTIFIER_GROUP: checkit = zfs_groupmember(zfsvfs, who, cr); break; case ACE_EVERYONE: checkit = B_TRUE; break; - /* USER Entry */ default: ! if (entry_type == 0) { ! uid_t newid; ! ! newid = zfs_fuid_map_id(zfsvfs, who, cr, ! ZFS_ACE_USER); ! if (newid != IDMAP_WK_CREATOR_OWNER_UID && ! uid == newid) ! checkit = B_TRUE; ! break; ! } else { mutex_exit(&zp->z_acl_lock); return (SET_ERROR(EIO)); } - } if (checkit) { ! if (type == DENY) { DTRACE_PROBE3(zfs__ace__denies, znode_t *, zp, zfs_ace_hdr_t *, acep, uint32_t, mask_matched); deny_mask |= mask_matched; ! } else { DTRACE_PROBE3(zfs__ace__allows, znode_t *, zp, zfs_ace_hdr_t *, acep, uint32_t, mask_matched); if (anyaccess) { mutex_exit(&zp->z_acl_lock); return (0); } - } *working_mode &= ~mask_matched; } ! /* Are we done? */ ! if (*working_mode == 0) break; } mutex_exit(&zp->z_acl_lock); /* Put the found 'denies' back on the working mode */ if (deny_mask) { *working_mode |= deny_mask; return (SET_ERROR(EACCES)); } else if (*working_mode) { --- 2121,2218 ---- if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) continue; /* Skip ACE if it does not affect any AoI */ mask_matched = (access_mask & *working_mode); ! if ((type == DENY || type == ALLOW) && !mask_matched) continue; + if (!audit && type != DENY && type != ALLOW) + continue; entry_type = (iflags & ACE_TYPE_FLAGS); checkit = B_FALSE; switch (entry_type) { case ACE_OWNER: ! who = zp->z_uid; ! /*FALLTHROUGH*/ ! case 0: /* USER Entry */ ! checkit = zfs_user_in_cred(zfsvfs, who, cr); break; case OWNING_GROUP: ! who = zp->z_gid; /*FALLTHROUGH*/ case ACE_IDENTIFIER_GROUP: checkit = zfs_groupmember(zfsvfs, who, cr); break; case ACE_EVERYONE: checkit = B_TRUE; break; default: ! /* ! * The zfs_acl_valid_ace_type check above ! * should make this case impossible. ! */ mutex_exit(&zp->z_acl_lock); return (SET_ERROR(EIO)); } if (checkit) { ! switch (type) { ! case DENY: DTRACE_PROBE3(zfs__ace__denies, znode_t *, zp, zfs_ace_hdr_t *, acep, uint32_t, mask_matched); deny_mask |= mask_matched; ! *working_mode &= ~mask_matched; ! break; ! case ACE_SYSTEM_AUDIT_ACE_TYPE: ! case ACE_SYSTEM_ALARM_ACE_TYPE: ! DTRACE_PROBE3(zfs__ace__audit, ! znode_t *, zp, ! zfs_ace_hdr_t *, acep, ! uint32_t, access_mask); ! if ((iflags & ! ACE_SUCCESSFUL_ACCESS_ACE_FLAG) != 0) ! sys_smask |= access_mask; ! if ((iflags & ACE_FAILED_ACCESS_ACE_FLAG) != 0) ! sys_fmask |= access_mask; ! break; ! case ALLOW: ! default: DTRACE_PROBE3(zfs__ace__allows, znode_t *, zp, zfs_ace_hdr_t *, acep, uint32_t, mask_matched); if (anyaccess) { mutex_exit(&zp->z_acl_lock); return (0); } *working_mode &= ~mask_matched; + break; } + } ! /* ! * Are we done? If auditing, process the entire list ! * to gather all audit ACEs ! */ ! if (!audit && *working_mode == 0) break; } mutex_exit(&zp->z_acl_lock); + if (audit) { + tad = T2A(curthread); + tad->tad_sacl_mask.tas_smask = sys_smask; + tad->tad_sacl_mask.tas_fmask = sys_fmask; + } + /* Put the found 'denies' back on the working mode */ if (deny_mask) { *working_mode |= deny_mask; return (SET_ERROR(EACCES)); } else if (*working_mode) {
*** 2207,2217 **** boolean_t zfs_has_access(znode_t *zp, cred_t *cr) { uint32_t have = ACE_ALL_PERMS; ! if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { uid_t owner; owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0); } --- 2229,2239 ---- boolean_t zfs_has_access(znode_t *zp, cred_t *cr) { uint32_t have = ACE_ALL_PERMS; ! if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, B_FALSE) != 0) { uid_t owner; owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0); }
*** 2222,2231 **** --- 2244,2254 ---- zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; int err; + boolean_t audit = B_FALSE; *working_mode = v4_mode; *check_privs = B_TRUE; /*
*** 2267,2277 **** (ZTOV(zp)->v_type != VDIR) && (zp->z_pflags & ZFS_READONLY)) { return (SET_ERROR(EPERM)); } ! return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); } static int zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, cred_t *cr) --- 2290,2309 ---- (ZTOV(zp)->v_type != VDIR) && (zp->z_pflags & ZFS_READONLY)) { return (SET_ERROR(EPERM)); } ! if (cr != zone_kcred() && AU_ZONE_AUDITING(NULL)) { ! t_audit_data_t *tad = T2A(curthread); ! if (tad->tad_sacl_ctrl != SACL_AUDIT_NONE && ! auditev(AUE_SACL, cr) != 0) { ! audit = B_TRUE; ! tad->tad_sacl_ctrl = SACL_AUDIT_NONE; ! } ! } ! ! return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr, audit)); } static int zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, cred_t *cr)
*** 2440,2449 **** --- 2472,2485 ---- VN_RELE(ZTOV(xzp)); return (error); } if (error && (flags & V_APPEND)) { + /* + * If zfs_zaccess_common checked aces, then we won't audit here. + * Otherwise, we'll try and get audit masks here. + */ error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); } if (error && check_privs) { mode_t checkmode = 0;
*** 2606,2615 **** --- 2642,2652 ---- uint32_t dzp_working_mode = 0; uint32_t zp_working_mode = 0; int dzp_error, zp_error; boolean_t dzpcheck_privs; boolean_t zpcheck_privs; + t_audit_data_t *tad; if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) return (SET_ERROR(EPERM)); /*
*** 2646,2655 **** --- 2683,2697 ---- * Case 2b is handled with wanted_dirperms. */ wanted_dirperms = ACE_DELETE_CHILD; if (zfs_write_implies_delete_child) wanted_dirperms |= ACE_WRITE_DATA; + /* never audit the parent directory access check */ + if (AU_ZONE_AUDITING(NULL)) { + tad = T2A(curthread); + tad->tad_sacl_ctrl = SACL_AUDIT_NONE; + } dzp_error = zfs_zaccess_common(dzp, wanted_dirperms, &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); if (dzp_error == EACCES) { /* We hit a DENY ACE. */ if (!dzpcheck_privs)
*** 2732,2748 **** --- 2774,2800 ---- zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, znode_t *tzp, cred_t *cr) { int add_perm; int error; + t_audit_data_t *tad; + sacl_audit_ctrl_t do_audit; if (szp->z_pflags & ZFS_AV_QUARANTINED) return (SET_ERROR(EACCES)); add_perm = (ZTOV(szp)->v_type == VDIR) ? ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; + if (AU_ZONE_AUDITING(NULL)) { + tad = T2A(curthread); + do_audit = tad->tad_sacl_ctrl; + } else { + tad = NULL; + do_audit = SACL_AUDIT_NONE; + } + /* * Rename permissions are combination of delete permission + * add file/subdir permission. */
*** 2750,2772 **** * first make sure we do the delete portion. * * If that succeeds then check for add_file/add_subdir permissions */ ! if (error = zfs_zaccess_delete(sdzp, szp, cr)) return (error); /* * If we have a tzp, see if we can delete it? */ if (tzp) { ! if (error = zfs_zaccess_delete(tdzp, tzp, cr)) return (error); } /* * Now check for add permissions */ error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); return (error); } --- 2802,2846 ---- * first make sure we do the delete portion. * * If that succeeds then check for add_file/add_subdir permissions */ ! if (do_audit == SACL_AUDIT_NO_SRC) ! tad->tad_sacl_ctrl = SACL_AUDIT_NONE; ! error = zfs_zaccess_delete(sdzp, szp, cr); ! ! if (do_audit == SACL_AUDIT_ALL) { ! tad->tad_sacl_mask_src = tad->tad_sacl_mask; ! tad->tad_sacl_mask.tas_smask = 0; ! tad->tad_sacl_mask.tas_fmask = 0; ! } ! if (error != 0) return (error); + if (do_audit != SACL_AUDIT_NONE) + tad->tad_sacl_ctrl = do_audit; + /* * If we have a tzp, see if we can delete it? */ if (tzp) { ! error = zfs_zaccess_delete(tdzp, tzp, cr); ! if (do_audit != SACL_AUDIT_NONE) { ! tad->tad_sacl_mask_dest = tad->tad_sacl_mask; ! tad->tad_sacl_mask.tas_smask = 0; ! tad->tad_sacl_mask.tas_fmask = 0; ! } ! if (error != 0) return (error); + if (do_audit != SACL_AUDIT_NONE) + tad->tad_sacl_ctrl = do_audit; } /* * Now check for add permissions */ error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); + /* do_audit: leave directory audit info in sacl_mask. */ + return (error); }