[Auditing Dtrace Snippets] Pieces of dtrace useful for building audit logs and general operation auditing #tags: smb, nfs, audit, history, commands log, io audit
#!/usr/sbin/dtrace -qCs
#pragma D option aggsortkey
#pragma D option aggsortkeypos=0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://www.illumos.org/license/.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright (c) 2017-2018 RackTop Systems.
*
* Author: Sam Zaydel
*/
/*
* Operations we deemed frequent, like read/write are aggregated into 1ms slices,
* which in theory means we can still end-up with 1000 log entries each second.
* We may have to adjust that, depending on what we observe in the lab and testing
* more broadly.
*
* *** Grouping of Operations ***
* Grouped IOs are bucketed with timestamps which are computed as follows:
* walltimestamp - walltimestamp % GRANULARITY. The modulo method allows us
* to zero out as many zeros from the least significant to most significant
* number as we please, and therefore allow us to create aggregates with 1ms
* or 10ms or 100ms, or 1sec, etc. resolution. We likely will need to reduce
* granularity down to 100ms or 1sec, so as to protect us from ourselves.
*
* *** About Sorting ***
* Aggregations are sorted based on the order of keys, with 0th being the key used.
* The 0th position is currently timestamp, so if we want to continue to sort in
* this way, we need to make sure it either remains in the 0th position, or if we
* have to change its place, we need to adjust `aggsortkeypos`.
*
* *** Fields ***
* timestamp (hrtime_t) | timestamp, nanoseconds since epoch;
* opname (string) | type of operation, i.e. READ, WRITE, etc.
* proto+vers (int) | protocol and major+minor version enum, see [protovers]
* clientIP (string) | client-side IP address
* file/dir (string) | filesystem path of resource being accessed
* uid (unit32_t) | posix or pseudo (ephemeral) uid of authenticated user
* gid (unit32_t) | posix or pseudo (ephemeral) gid of authenticated user
* return code(int) | return code with cmd status 0 == OK | !0 == Error
* sum bytes (int) | number of bytes a command processed if not meta operation
*
*/
/*
* Notes:
* This script was changed post following git commit to support the changes
* in this commit. It will therefore not work correctly with system running
* code earlier than this changeset.
* Tue Sep 12 14:49:00 2017 +0300 eae5de5d4a (origin/vgusev/bsr_nfs41)
* NFS41-36 dtrace: resolve arguments for new stubs
* op-*-start and op-*-done [Vitaliy Gusev]
*/
vnode_t *nfsren_from[kthread_t *]; /* vnode pointer used with NFS rename op */
vnode_t *nfsren_to[kthread_t *]; /* vnode pointer used with NFS rename op */
smb_session_t *smbsess[kthread_t *];
string opname[string], createtyp[int];
inline const int METAOP = 0xffffffff; /* not a read or a write op */
inline const int GRANULARITY = 100000000; /* 1/10th of a second */
/*
* These are elements we use in each of the SMB clauses to capture
* relevant information about each operation.
*
* path args[2]->vp->v_path;
* uid args[1]->cr_uid;
* gid args[1]->cr_gid;
* io bytes args[3]->uio_resid;
* ipaddress args[0]->session->ip_addr_str;
* remoteport args[0]->session->s_remote_port;
*/
enum protovers {
NFS2 = 0, /* NFSv2 not used here, we don't track it */
NFS3 = 1, /* NFSv3 */
NFS4 = 2, /* NFSv4 */
NFS41 = 3, /* NFSv41 */
/* skipping for future expansion */
SMB11 = 7, /* SMBv1.1 */
SMB21 = 8, /* SMBv2.1 */
SMB3 = 9 /* Not yet implemented */
};
enum protovers smbvers[int]; /* Map smb version from dialect to enum value */
/* NFS file types, see usr/src/uts/common/nfs/nfs4_kprot.h */
enum nfs_ftype4 {
NF4REG = 1,
NF4DIR = 2,
NF4BLK = 3,
NF4CHR = 4,
NF4LNK = 5,
NF4SOCK = 6,
NF4FIFO = 7,
NF4ATTRDIR = 8,
NF4NAMEDATTR = 9
};
enum opentype4 {
OPEN4_NOCREATE = 0,
OPEN4_CREATE = 1
};
BEGIN {
smbvers[0xb] = SMB11;
smbvers[0x210] = SMB21;
createtyp[NF4DIR] = "MKDIR";
createtyp[NF4LNK] = "LINK";
createtyp[NF4REG] = "CREATE";
/* Lookup table used by both SMB and NFS clauses below */
opname["op-create-done"] = "CREATE";
opname["op-read-done"] = "READ";
opname["op-write-done"] = "WRITE";
opname["op-remove-done"] = "DELETE";
opname["op-rename-done"] = "RENAME";
opname["op-mkdir-start"] = "MKDIR";
opname["op-mkdir-done"] = "MKDIR";
opname["op-rmdir-done"] = "RMDIR";
opname["smb_fsop_read"] = "READ";
opname["smb_fsop_write"] = "WRITE";
opname["smb_fsop_remove"] = "DELETE";
opname["smb_fsop_create"] = "CREATE";
opname["smb_fsop_rmdir"] = "RMDIR";
opname["smb_fsop_mkdir"] = "MKDIR";
opname["smb_fsop_rename"] = "RENAME";
}
/* NFSv3 WRITE */
::rfs3_write:op-write-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->b = args[2]->data.data_len;
}
::rfs3_write:op-write-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
args[1]->noi_curpath,
args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv4 WRITE */
::rfs4_op_write:op-write-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->b = args[2]->data_len;
}
::rfs4_op_write:op-write-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
args[1]->noi_curpath, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv3/NFSv4 READ */
::rfs3_read:op-read-start,
::rfs4_op_read:op-read-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->vers = probefunc == "rfs4_op_read" ? NFS4 : NFS3;
this->b = args[2]->count;
}
::rfs3_read:op-read-done,
::rfs4_op_read:op-read-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], this->vers, args[0]->ci_remote,
args[1]->noi_curpath, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv3 REMOVE */
::rfs3_remove:op-remove-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->object.name);
}
::rfs3_remove:op-remove-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 REMOVE */
::rfs4_op_remove:op-remove-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->target.utf8string_val is strjoin(ed) with the
* remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p,
substr(args[2]->target.utf8string_val,
0, args[2]->target.utf8string_len)
);
}
::rfs4_op_remove:op-remove-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 CREATE */
::rfs3_create:op-create-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->where.name);
}
::rfs3_create:op-create-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 MKDIR */
::rfs3_mkdir:op-mkdir-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->where.name);
}
::rfs3_mkdir:op-mkdir-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 RMDIR */
::rfs3_rmdir:op-rmdir-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->object.name);
}
::rfs3_rmdir:op-rmdir-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 CREATE */
::rfs4_op_create:op-create-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/{
this->t = args[2]->type;
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->objname.utf8string_val is strjoin(ed) with the
* remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p,
substr(args[2]->objname.utf8string_val,
0, args[2]->objname.utf8string_len)
);
}
::rfs4_op_create:op-create-done
/
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, createtyp[this->t], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 CREATE (regular files) */
::rfs4_op_open:op-open-start
/args[2]->opentype == OPEN4_CREATE &&
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->iscreate = OPEN4_CREATE;
this->openargs = args[2];
this->ts = walltimestamp;
this->val = args[2]->claim.open_claim4_u.file.utf8string_val;
this->len = args[2]->claim.open_claim4_u.file.utf8string_len;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->claim.open_claim4_u.file.utf8string_val is strjoin(ed) with
* the remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p, substr(this->val, 0, this->len));
}
::rfs4_op_open:op-open-done
/ this->iscreate == OPEN4_CREATE &&
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
this->iscreate = 0;
@nfslog[this->ts, createtyp[NF4REG], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 RENAME (start) */
::rfs3_rename:op-rename-start {
in_rename[curthread] = 1; /* set flag triggering entry into zfs_rename */
this->ts = walltimestamp;
this->newn = args[2]->to.name;
this->oldn = args[2]->from.name;
}
/* NFSv4 RENAME (start) */
::rfs4_op_rename:op-rename-start {
in_rename[curthread] = 1; /* set flag triggering entry into zfs_rename */
this->ts = walltimestamp;
/* Store pointer and length of old and new value(s) of name */
this->newval = args[2]->newname.utf8string_val;
this->newlen = args[2]->newname.utf8string_len;
this->oldval = args[2]->oldname.utf8string_val;
this->oldlen = args[2]->oldname.utf8string_len;
/* Trim off anything > utf8string_val, to avoid junk in name */
this->newn = substr(this->newval, 0, this->newlen);
this->oldn = substr(this->oldval, 0, this->oldlen);
}
/*
* This probe is triggered when NFS asks the filesystem to rename,
* and it gives us access to pointers to vnodes, both from and to.
*/
::zfs_rename:entry /in_rename[curthread]/ {
/*
* Set these to 0 later, otherwise we will have issues with
* dropped dynamic variables after running for some period of time.
*/
nfsren_from[curthread] = args[0];
nfsren_to[curthread] = args[2];
}
/* NFSv3 RENAME (done) */
::rfs3_rename:op-rename-done /in_rename[curthread]/ {
/*
* We are expecting that v_path(s) will be valid here, but we experienced
* instances where the values were not valid, and to protect from that we
* add an override here in the cases where values are NULL or "".
*/
this->from = nfsren_from[curthread]->v_path == NULL ? "<NONE>" :
nfsren_from[curthread]->v_path == "" ? "<NONE>" :
nfsren_from[curthread]->v_path;
this->to = nfsren_to[curthread]->v_path == NULL ? "<NONE>" :
nfsren_to[curthread]->v_path == "" ? "<NONE>" :
nfsren_to[curthread]->v_path;
this->fp_old = strjoin(this->from, "/");
this->fp_old = strjoin(this->fp_old, this->oldn);
this->fp_new = strjoin(this->to, "/");
this->fp_new = strjoin(this->fp_new, this->newn);
this->oldnew = strjoin(this->fp_old, "|");
this->oldnew = strjoin(this->oldnew, this->fp_new);
in_rename[curthread] = 0;
nfsren_from[curthread] = 0;
nfsren_to[curthread] = 0;
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->oldnew, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 RENAME (done) */
::rfs4_op_rename:op-rename-done /in_rename[curthread]/ {
/*
* We are expecting that v_path(s) will be valid here, but we experienced
* instances where the values were not valid, and to protect from that we
* add an override here in the cases where values are NULL or "".
*/
this->from = nfsren_from[curthread]->v_path == NULL ? "<NONE>" :
nfsren_from[curthread]->v_path == "" ? "<NONE>" :
nfsren_from[curthread]->v_path;
this->to = nfsren_to[curthread]->v_path == NULL ? "<NONE>" :
nfsren_to[curthread]->v_path == "" ? "<NONE>" :
nfsren_to[curthread]->v_path;
this->fp_old = strjoin(this->from, "/");
this->fp_old = strjoin(this->fp_old, this->oldn);
this->fp_new = strjoin(this->to, "/");
this->fp_new = strjoin(this->fp_new, this->newn);
this->oldnew = strjoin(this->fp_old, "|");
this->oldnew = strjoin(this->oldnew, this->fp_new);
in_rename[curthread] = 0;
nfsren_from[curthread] = 0;
nfsren_to[curthread] = 0;
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
this->oldnew, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* SMB Read and Write */
::smb_fsop_write:entry,::smb_fsop_read:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = args[2]->vp->v_path;
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
this->b = args[3]->uio_resid;
}
::smb_fsop_write:return,::smb_fsop_read:return {
@smblog[this->ts, opname[probefunc], smbvers[this->v],
this->sess->ip_addr_str, stringof(this->p), this->cr_uid, this->cr_gid,
args[1]] = sum(this->b);
}
/* SMB Create and Remove */
::smb_fsop_create:entry,
::smb_fsop_mkdir:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->ts = walltimestamp;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
/*
* Because smb_fsop_remove and smb_fsop_rmdir have a 0
* in place of ptr to smb_request_t, we have to brab a handle
* here and then make sure to zero this out after this function
* returns. We do not check upon return for existence of value
* self->reqfree, because it does not really matter, since we
* are setting to 0 at that point.
*/
::smb_request_free:entry {
self->reqfree = args[0];
}
::smb_fsop_remove:entry,
::smb_fsop_rmdir:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->ts = walltimestamp;
this->v = self->reqfree->session->dialect;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
::smb_fsop_remove:return,
::smb_fsop_rmdir:return {
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v],
self->reqfree->session->ip_addr_str, stringof(this->p),
this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
::smb_request_free:return {
self->reqfree = 0;
}
::smb_fsop_mkdir:return,
::smb_fsop_create:return {
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v], this->sess->ip_addr_str,
stringof(this->p), this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
/* SMB Rename */
::smb_fsop_rename:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
self->in = 1;
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->new = strjoin(args[4]->vp->v_path, "/");
this->new = strjoin(this->new, args[5]);
this->oldnew = strjoin(this->p, "|");
this->oldnew = strjoin(this->oldnew, this->new);
this->ts = walltimestamp;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
::smb_fsop_rename:return /self->in/ {
self->in = 0;
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v], this->sess->ip_addr_str,
stringof(this->oldnew), this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
tick-1sec {
printa("%d,%s,%d,%s,%s,%d,%d,%d,0x%@x\n", @nfslog);
printa("%d,%s,%d,%s,%s,%d,%d,%d,0x%@x\n", @smblog);
trunc(@nfslog); trunc(@smblog);
}
#!/usr/sbin/dtrace -qCs
#pragma D option aggsortkey
#pragma D option aggsortkeypos=0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://www.illumos.org/license/.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright (c) 2017 RackTop Systems.
*
* Author: Sam Zaydel
*/
/*
* Operations we deemed frequent, like read/write are aggregated into 1ms slices,
* which in theory means we can still end-up with 1000 log entries each second.
* We may have to adjust that, depending on what we observe in the lab and testing
* more broadly.
*
* *** Grouping of Operations ***
* Grouped IOs are bucketed with timestamps which are computed as follows:
* walltimestamp - walltimestamp % GRANULARITY. The modulo method allows us
* to zero out as many zeros from the least significant to most significant
* number as we please, and therefore allow us to create aggregates with 1ms
* or 10ms or 100ms, or 1sec, etc. resolution. We likely will need to reduce
* granularity down to 100ms or 1sec, so as to protect us from ourselves.
*
* *** About Sorting ***
* Aggregations are sorted based on the order of keys, with 0th being the key used.
* The 0th position is currently timestamp, so if we want to continue to sort in
* this way, we need to make sure it either remains in the 0th position, or if we
* have to change its place, we need to adjust `aggsortkeypos`.
*
* *** Fields ***
* timestamp (hrtime_t) | timestamp, nanoseconds since epoch;
* opname (string) | type of operation, i.e. READ, WRITE, etc.
* proto+vers (int) | protocol and major+minor version enum, see [protovers]
* clientIP (string) | client-side IP address
* file/dir (string) | filesystem path of resource being accessed
* uid (unit32_t) | posix or pseudo (ephemeral) uid of authenticated user
* gid (unit32_t) | posix or pseudo (ephemeral) gid of authenticated user
* return code(int) | return code with cmd status 0 == OK | !0 == Error
* sum bytes (int) | number of bytes a command processed if not meta operation
*
*/
vnode_t *nfsren_from[kthread_t *]; /* vnode pointer used with NFS rename op */
vnode_t *nfsren_to[kthread_t *]; /* vnode pointer used with NFS rename op */
smb_session_t *smbsess[kthread_t *];
string opname[string], createtyp[int];
inline const int METAOP = 0xffffffff; /* not a read or a write op */
inline const int GRANULARITY = 100000000; /* 1/10th of a second */
/*
* These are elements we use in each of the SMB clauses to capture
* relevant information about each operation.
*
* path args[2]->vp->v_path;
* uid args[1]->cr_uid;
* gid args[1]->cr_gid;
* io bytes args[3]->uio_resid;
* ipaddress args[0]->session->ip_addr_str;
* remoteport args[0]->session->s_remote_port;
*/
enum protovers {
NFS2 = 0, /* NFSv2 not used here, we don't track it */
NFS3 = 1, /* NFSv3 */
NFS4 = 2, /* NFSv4 */
NFS41 = 3, /* NFSv41 */
/* skipping for future expansion */
SMB11 = 7, /* SMBv1.1 */
SMB21 = 8, /* SMBv2.1 */
SMB3 = 9 /* Not yet implemented */
};
enum protovers smbvers[int]; /* Map smb version from dialect to enum value */
/* NFS file types, see usr/src/uts/common/nfs/nfs4_kprot.h */
enum nfs_ftype4 {
NF4REG = 1,
NF4DIR = 2,
NF4BLK = 3,
NF4CHR = 4,
NF4LNK = 5,
NF4SOCK = 6,
NF4FIFO = 7,
NF4ATTRDIR = 8,
NF4NAMEDATTR = 9
};
enum opentype4 {
OPEN4_NOCREATE = 0,
OPEN4_CREATE = 1
};
BEGIN {
smbvers[0xb] = SMB11;
smbvers[0x210] = SMB21;
createtyp[NF4DIR] = "MKDIR";
createtyp[NF4LNK] = "LINK";
createtyp[NF4REG] = "CREATE";
/* Lookup table used by both SMB and NFS clauses below */
opname["op-create-done"] = "CREATE";
opname["op-read-done"] = "READ";
opname["op-write-done"] = "WRITE";
opname["op-remove-done"] = "DELETE";
opname["op-rename-done"] = "RENAME";
opname["op-mkdir-start"] = "MKDIR";
opname["op-mkdir-done"] = "MKDIR";
opname["op-rmdir-done"] = "RMDIR";
opname["smb_fsop_read"] = "READ";
opname["smb_fsop_write"] = "WRITE";
opname["smb_fsop_remove"] = "DELETE";
opname["smb_fsop_create"] = "CREATE";
opname["smb_fsop_rmdir"] = "RMDIR";
opname["smb_fsop_mkdir"] = "MKDIR";
opname["smb_fsop_rename"] = "RENAME";
}
/* NFSv3 WRITE */
::rfs3_write:op-write-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->b = args[2]->data.data_len;
}
::rfs3_write:op-write-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
args[1]->noi_curpath,
args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv4 WRITE */
::rfs4_op_write:op-write-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->b = args[2]->data_len;
}
::rfs4_op_write:op-write-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
args[1]->noi_curpath, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv3/NFSv4 READ */
::rfs3_read:op-read-start,
::rfs4_op_read:op-read-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->vers = probefunc == "rfs4_op_read" ? NFS4 : NFS3;
this->b = args[2]->count;
}
::rfs3_read:op-read-done,
::rfs4_op_read:op-read-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], this->vers, args[0]->ci_remote,
args[1]->noi_curpath, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(this->b);
}
/* NFSv3 REMOVE */
::rfs3_remove:op-remove-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->object.name);
}
::rfs3_remove:op-remove-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 REMOVE */
::rfs4_op_remove:op-remove-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->target.utf8string_val is strjoin(ed) with the
* remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p,
substr(args[2]->target.utf8string_val,
0, args[2]->target.utf8string_len)
);
}
::rfs4_op_remove:op-remove-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 CREATE */
::rfs3_create:op-create-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->where.name);
}
::rfs3_create:op-create-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 MKDIR */
::rfs3_mkdir:op-mkdir-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->where.name);
}
::rfs3_mkdir:op-mkdir-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 RMDIR */
::rfs3_rmdir:op-rmdir-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
this->p = strjoin(this->p, args[2]->object.name);
}
::rfs3_rmdir:op-rmdir-done
/substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 CREATE */
::rfs4_op_create:op-create-start
/substr(args[1]->noi_curpath, 0, 1) == "/"/{
this->t = args[2]->type;
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->objname.utf8string_val is strjoin(ed) with the
* remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p,
substr(args[2]->objname.utf8string_val,
0, args[2]->objname.utf8string_len)
);
}
::rfs4_op_create:op-create-done
/
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
@nfslog[this->ts, createtyp[this->t], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 CREATE (regular files) */
::rfs4_op_open:op-open-start
/args[2]->opentype == OPEN4_CREATE &&
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->iscreate = OPEN4_CREATE;
this->openargs = args[2];
this->ts = walltimestamp;
this->p = strjoin(args[1]->noi_curpath, "/");
/*
* Make sure that only actual length of the string in
* args[2]->objname.utf8string_val is strjoin(ed) with the
* remainder of the path. Otherwise we will pick-up crap, because
* utf8string_val is not properly terminated.
*/
this->p = strjoin(this->p,
substr(args[2]->open_claim4_u.file.utf8string_val,
0, args[2]->open_claim4_u.file.utf8string_len)
);
}
::rfs4_op_open:op-open-done
/ this->iscreate == OPEN4_CREATE &&
substr(args[1]->noi_curpath, 0, 1) == "/"/ {
this->res = args[2]->status;
this->iscreate = 0;
@nfslog[this->ts, createtyp[NF4REG], NFS4, args[0]->ci_remote,
this->p, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv3 RENAME (start) */
::rfs3_rename:op-rename-start {
in_rename[curthread] = 1; /* set flag triggering entry into zfs_rename */
this->ts = walltimestamp;
this->newn = args[2]->to.name;
this->oldn = args[2]->from.name;
}
/* NFSv4 RENAME (start) */
::rfs4_op_rename:op-rename-start {
in_rename[curthread] = 1; /* set flag triggering entry into zfs_rename */
this->ts = walltimestamp;
/* Store pointer and length of old and new value(s) of name */
this->newval = args[2]->newname.utf8string_val;
this->newlen = args[2]->newname.utf8string_len;
this->oldval = args[2]->oldname.utf8string_val;
this->oldlen = args[2]->oldname.utf8string_len;
/* Trim off anything > utf8string_val, to avoid junk in name */
this->newn = substr(this->newval, 0, this->newlen);
this->oldn = substr(this->oldval, 0, this->oldlen);
}
/*
* This probe is triggered when NFS asks the filesystem to rename,
* and it gives us access to pointers to vnodes, both from and to.
*/
::zfs_rename:entry /in_rename[curthread]/ {
/*
* Set these to 0 later, otherwise we will have issues with
* dropped dynamic variables after running for some period of time.
*/
nfsren_from[curthread] = args[0];
nfsren_to[curthread] = args[2];
}
/* NFSv3 RENAME (done) */
::rfs3_rename:op-rename-done /in_rename[curthread]/ {
/*
* We are expecting that v_path(s) will be valid here, but we experienced
* instances where the values were not valid, and to protect from that we
* add an override here in the cases where values are NULL or "".
*/
this->from = nfsren_from[curthread]->v_path == NULL ? "<NONE>" :
nfsren_from[curthread]->v_path == "" ? "<NONE>" :
nfsren_from[curthread]->v_path;
this->to = nfsren_to[curthread]->v_path == NULL ? "<NONE>" :
nfsren_to[curthread]->v_path == "" ? "<NONE>" :
nfsren_to[curthread]->v_path;
this->fp_old = strjoin(this->from, "/");
this->fp_old = strjoin(this->fp_old, this->oldn);
this->fp_new = strjoin(this->to, "/");
this->fp_new = strjoin(this->fp_new, this->newn);
this->oldnew = strjoin(this->fp_old, "|");
this->oldnew = strjoin(this->oldnew, this->fp_new);
in_rename[curthread] = 0;
nfsren_from[curthread] = 0;
nfsren_to[curthread] = 0;
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS3, args[0]->ci_remote,
this->oldnew, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* NFSv4 RENAME (done) */
::rfs4_op_rename:op-rename-done /in_rename[curthread]/ {
/*
* We are expecting that v_path(s) will be valid here, but we experienced
* instances where the values were not valid, and to protect from that we
* add an override here in the cases where values are NULL or "".
*/
this->from = nfsren_from[curthread]->v_path == NULL ? "<NONE>" :
nfsren_from[curthread]->v_path == "" ? "<NONE>" :
nfsren_from[curthread]->v_path;
this->to = nfsren_to[curthread]->v_path == NULL ? "<NONE>" :
nfsren_to[curthread]->v_path == "" ? "<NONE>" :
nfsren_to[curthread]->v_path;
this->fp_old = strjoin(this->from, "/");
this->fp_old = strjoin(this->fp_old, this->oldn);
this->fp_new = strjoin(this->to, "/");
this->fp_new = strjoin(this->fp_new, this->newn);
this->oldnew = strjoin(this->fp_old, "|");
this->oldnew = strjoin(this->oldnew, this->fp_new);
in_rename[curthread] = 0;
nfsren_from[curthread] = 0;
nfsren_to[curthread] = 0;
this->res = args[2]->status;
@nfslog[this->ts, opname[probename], NFS4, args[0]->ci_remote,
this->oldnew, args[1]->noi_cred->cr_uid,
args[1]->noi_cred->cr_gid, this->res] = sum(0);
}
/* SMB Read and Write */
::smb_fsop_write:entry,::smb_fsop_read:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = args[2]->vp->v_path;
this->realts = walltimestamp;
this->ts = this->realts - this->realts % GRANULARITY;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
this->b = args[3]->uio_resid;
}
::smb_fsop_write:return,::smb_fsop_read:return {
@smblog[this->ts, opname[probefunc], smbvers[this->v],
this->sess->ip_addr_str, stringof(this->p), this->cr_uid, this->cr_gid,
args[1]] = sum(this->b);
}
/* SMB Create and Remove */
::smb_fsop_create:entry,
::smb_fsop_mkdir:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->ts = walltimestamp;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
/*
* Because smb_fsop_remove and smb_fsop_rmdir have a 0
* in place of ptr to smb_request_t, we have to brab a handle
* here and then make sure to zero this out after this function
* returns. We do not check upon return for existence of value
* self->reqfree, because it does not really matter, since we
* are setting to 0 at that point.
*/
::smb_request_free:entry {
self->reqfree = args[0];
}
::smb_fsop_remove:entry,
::smb_fsop_rmdir:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->ts = walltimestamp;
this->v = self->reqfree->session->dialect;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
::smb_fsop_remove:return,
::smb_fsop_rmdir:return {
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v],
self->reqfree->session->ip_addr_str, stringof(this->p),
this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
::smb_request_free:return {
self->reqfree = 0;
}
::smb_fsop_mkdir:return,
::smb_fsop_create:return {
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v], this->sess->ip_addr_str,
stringof(this->p), this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
/* SMB Rename */
::smb_fsop_rename:entry
/substr(args[2]->vp->v_path, 0, 1) == "/"/ {
self->in = 1;
this->p = strjoin(args[2]->vp->v_path, "/");
this->p = strjoin(this->p, args[3]);
this->new = strjoin(args[4]->vp->v_path, "/");
this->new = strjoin(this->new, args[5]);
this->oldnew = strjoin(this->p, "|");
this->oldnew = strjoin(this->oldnew, this->new);
this->ts = walltimestamp;
this->v = args[0]->session->dialect;
this->sess = args[0]->session;
this->cr_gid = args[1]->cr_gid;
this->cr_uid = args[1]->cr_uid;
}
::smb_fsop_rename:return /self->in/ {
self->in = 0;
this->retcode = args[1];
@smblog[this->ts, opname[probefunc], smbvers[this->v], this->sess->ip_addr_str,
stringof(this->oldnew), this->cr_uid, this->cr_gid, this->retcode] = sum(0);
}
tick-1sec {
printa("%d,%s,%d,%s,%s,%d,%d,%d,0x%@x\n", @nfslog);
printa("%d,%s,%d,%s,%s,%d,%d,%d,0x%@x\n", @smblog);
trunc(@nfslog); trunc(@smblog);
}