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,11 +19,11 @@
* 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.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
@@ -52,10 +52,12 @@
#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,11 +1188,10 @@
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);
@@ -1233,10 +1234,11 @@
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,28 +2083,26 @@
* 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 anyaccess, cred_t *cr, boolean_t audit)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
zfs_acl_t *aclp;
int error;
- uid_t uid = crgetuid(cr);
- uint64_t who;
+ 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;
- uid_t gowner;
- uid_t fowner;
+ boolean_t checkit; /* ACE ID matches */
+ t_audit_data_t *tad;
- 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);
@@ -2121,76 +2121,98 @@
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)
+ 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:
- if (uid == fowner)
- checkit = B_TRUE;
+ who = zp->z_uid;
+ /*FALLTHROUGH*/
+ case 0: /* USER Entry */
+ checkit = zfs_user_in_cred(zfsvfs, who, cr);
break;
case OWNING_GROUP:
- who = gowner;
+ who = zp->z_gid;
/*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 {
+ /*
+ * 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) {
- if (type == DENY) {
+ 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;
- } else {
+ *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 (*working_mode == 0)
+ /*
+ * 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,11 +2229,11 @@
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) {
+ 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,10 +2244,11 @@
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,11 +2290,20 @@
(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));
+ 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,10 +2472,14 @@
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,10 +2642,11 @@
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,10 +2683,15 @@
* 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,17 +2774,27 @@
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,23 +2802,45 @@
* 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))
+ 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) {
- if (error = zfs_zaccess_delete(tdzp, tzp, cr))
+ 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);
}