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);
}