From b93691b15c2c1182084c5e9e5fea3cbdabce53db Mon Sep 17 00:00:00 2001 From: Devin Trejo Date: Wed, 10 Jan 2018 12:06:10 -0500 Subject: [PATCH] Add nfs_proc_symlink, nfs_proc_link, nfs_proc_sattr. --- scripts/base/init-bare.bro | 61 ++++++++++++ src/analyzer/protocol/rpc/NFS.cc | 139 +++++++++++++++++++++++++++ src/analyzer/protocol/rpc/NFS.h | 8 ++ src/analyzer/protocol/rpc/events.bif | 88 ++++++++++++++++- src/types.bif | 20 +++- 5 files changed, 311 insertions(+), 5 deletions(-) diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index f2ea2ed29a..287c213091 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2157,6 +2157,18 @@ export { rpc_auxgids: index_vec; }; + ## NFS file attributes. Field names are based on RFC 1813. + ## + ## .. bro:see:: nfs_proc_sattr + type sattr_t: record { + mode: count &optional; ##< Mode + uid: count &optional; ##< User ID. + gid: count &optional; ##< Group ID. + size: count &optional; ##< Size. + atime: time_how_t &optional; ##< Time of last access. + mtime: time_how_t &optional; ##< Time of last modification. + }; + ## NFS file attributes. Field names are based on RFC 1813. ## ## .. bro:see:: nfs_proc_getattr @@ -2177,6 +2189,14 @@ export { ctime: time; ##< Time of creation. }; + ## NFS symlinkdata attributes. Field names are based on RFC 1813 + ## + ## .. bro:see:: nfs_proc_symlink + type symlinkdata_t: record { + symlink_attributes: sattr_t; ##< The initial attributes for the symbolic link + nfspath: string &optional; ##< The string containing the symbolic link data. + }; + ## NFS *readdir* arguments. ## ## .. bro:see:: nfs_proc_readdir @@ -2195,6 +2215,30 @@ export { dst_fname : string; }; + ## NFS *symlink* arguments. + ## + ## .. bro:see:: nfs_proc_symlink + type symlinkargs_t: record { + link : diropargs_t; ##< The location of the link to be created. + symlinkdata: symlinkdata_t; ##< The symbolic link to be created. + }; + + ## NFS *link* arguments. + ## + ## .. bro:see:: nfs_proc_link + type linkargs_t: record { + fh : string; ##< The file handle for the existing file system object. + link : diropargs_t; ##< The location of the link to be created. + }; + + ## NFS *sattr* arguments. + ## + ## .. bro:see:: nfs_proc_sattr + type sattrargs_t: record { + fh : string; ##< The file handle for the existing file system object. + new_attributes: sattr_t; ##< The new attributes for the file. + }; + ## NFS lookup reply. If the lookup failed, *dir_attr* may be set. If the ## lookup succeeded, *fh* is always set and *obj_attr* and *dir_attr* ## may be set. @@ -2253,6 +2297,23 @@ export { mtime: time; ##< Modification time. }; + ## NFS *link* reply. + ## + ## .. bro:see:: nfs_proc_link + type link_reply_t: record { + post_attr: fattr_t &optional; ##< Optional post-operation attributes of the file system object identified by file + preattr: wcc_attr_t &optional; ##< Optional attributes associated w/ file. + postattr: fattr_t &optional; ##< Optional attributes associated w/ file. + }; + + ## NFS *sattr* reply. If the request fails, *pre|post* attr may be set. + ## If the request succeeds, *pre|post* attr are set. + ## + type sattr_reply_t: record { + dir_pre_attr: wcc_attr_t &optional; ##< Optional attributes associated w/ dir. + dir_post_attr: fattr_t &optional; ##< Optional attributes associated w/ dir. + }; + ## NFS *write* reply. If the request fails, *pre|post* attr may be set. ## If the request succeeds, *pre|post* attr may be set and all other ## fields are set. diff --git a/src/analyzer/protocol/rpc/NFS.cc b/src/analyzer/protocol/rpc/NFS.cc index 03cd91e573..f03e47ab8b 100644 --- a/src/analyzer/protocol/rpc/NFS.cc +++ b/src/analyzer/protocol/rpc/NFS.cc @@ -31,6 +31,10 @@ int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n) callarg = nfs3_fh(buf, n); break; + case BifEnum::NFS3::PROC_SETATTR: + callarg = nfs3_sattrargs(buf, n); + break; + case BifEnum::NFS3::PROC_LOOKUP: callarg = nfs3_diropargs(buf, n); break; @@ -43,6 +47,14 @@ int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n) callarg = nfs3_fh(buf, n); break; + case BifEnum::NFS3::PROC_SYMLINK: + callarg = nfs3_symlinkargs(buf, n); + break; + + case BifEnum::NFS3::PROC_LINK: + callarg = nfs3_linkargs(buf, n); + break; + case BifEnum::NFS3::PROC_WRITE: callarg = nfs3_writeargs(buf, n); break; @@ -159,6 +171,11 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status, event = nfs_proc_getattr; break; + case BifEnum::NFS3::PROC_SETATTR: + reply = nfs3_sattr_reply(buf, n, nfs_status); + event = nfs_proc_sattr; + break; + case BifEnum::NFS3::PROC_LOOKUP: reply = nfs3_lookup_reply(buf, n, nfs_status); event = nfs_proc_lookup; @@ -176,6 +193,16 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status, event = nfs_proc_readlink; break; + case BifEnum::NFS3::PROC_SYMLINK: + reply = nfs3_newobj_reply(buf, n, nfs_status); + event = nfs_proc_symlink; + break; + + case BifEnum::NFS3::PROC_LINK: + reply = nfs3_link_reply(buf, n, nfs_status); + event = nfs_proc_link; + break; + case BifEnum::NFS3::PROC_WRITE: reply = nfs3_write_reply(buf, n, nfs_status); event = nfs_proc_write; @@ -334,6 +361,56 @@ StringVal* NFS_Interp::nfs3_fh(const u_char*& buf, int& n) return new StringVal(new BroString(fh, fh_n, 0)); } + +RecordVal* NFS_Interp::nfs3_sattr(const u_char*& buf, int& n) + { + RecordVal* attrs = new RecordVal(BifType::Record::NFS3::sattr_t); + + attrs->Assign(0, 0); // mode + int mode_set_it = extract_XDR_uint32(buf, n); + if ( mode_set_it ) + attrs->Assign(0, ExtractUint32(buf, n)); // mode + + attrs->Assign(1, 0); // uid + int uid_set_it = extract_XDR_uint32(buf, n); + if ( uid_set_it ) + attrs->Assign(1, ExtractUint32(buf, n)); // uid + + attrs->Assign(2, 0); // gid + int gid_set_it = extract_XDR_uint32(buf, n); + if ( gid_set_it ) + attrs->Assign(2, ExtractUint32(buf, n)); // gid + + attrs->Assign(3, 0); // size + int size_set_it = extract_XDR_uint32(buf, n); + if ( size_set_it ) + attrs->Assign(3, ExtractTime(buf, n)); // size + + attrs->Assign(4, nfs3_time_how(buf, n)); // time_how + + attrs->Assign(5, nfs3_time_how(buf, n)); // time_how + + return attrs; + } + +RecordVal* NFS_Interp::nfs3_sattr_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status) + { + RecordVal* rep = new RecordVal(BifType::Record::NFS3::sattr_reply_t); + + if ( status == BifEnum::NFS3::NFS3ERR_OK ) + { + rep->Assign(0, nfs3_pre_op_attr(buf, n)); + rep->Assign(1, nfs3_post_op_attr(buf, n)); + } + else + { + rep->Assign(1, 0); + rep->Assign(2, 0); + } + + return rep; + } + RecordVal* NFS_Interp::nfs3_fattr(const u_char*& buf, int& n) { RecordVal* attrs = new RecordVal(BifType::Record::NFS3::fattr_t); @@ -356,6 +433,12 @@ RecordVal* NFS_Interp::nfs3_fattr(const u_char*& buf, int& n) return attrs; } +EnumVal* NFS_Interp::nfs3_time_how(const u_char*& buf, int& n) + { + BifEnum::NFS3::time_how_t t = (BifEnum::NFS3::time_how_t)extract_XDR_uint32(buf, n); + return new EnumVal(t, BifType::Enum::NFS3::time_how_t); + } + EnumVal* NFS_Interp::nfs3_ftype(const u_char*& buf, int& n) { BifEnum::NFS3::file_type_t t = (BifEnum::NFS3::file_type_t)extract_XDR_uint32(buf, n); @@ -394,6 +477,16 @@ RecordVal *NFS_Interp::nfs3_diropargs(const u_char*& buf, int& n) return diropargs; } +RecordVal *NFS_Interp::nfs3_symlinkdata(const u_char*& buf, int& n) + { + RecordVal *symlinkdata = new RecordVal(BifType::Record::NFS3::symlinkdata_t); + + symlinkdata->Assign(0, nfs3_sattr(buf, n)); + symlinkdata->Assign(1, nfs3_nfspath(buf, n)); + + return symlinkdata; + } + RecordVal *NFS_Interp::nfs3_renameopargs(const u_char*& buf, int& n) { RecordVal *renameopargs = new RecordVal(BifType::Record::NFS3::renameopargs_t); @@ -511,6 +604,52 @@ RecordVal* NFS_Interp::nfs3_readlink_reply(const u_char*& buf, int& n, BifEnum:: return rep; } +RecordVal* NFS_Interp::nfs3_link_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status) + { + RecordVal *rep = new RecordVal(BifType::Record::NFS3::link_reply_t); + + if (status == BifEnum::NFS3::NFS3ERR_OK) + { + rep->Assign(0, nfs3_post_op_attr(buf, n)); + + // wcc_data + rep->Assign(1, nfs3_pre_op_attr(buf, n)); + rep->Assign(2, nfs3_post_op_attr(buf, n)); + } + + return rep; + } + +RecordVal* NFS_Interp::nfs3_symlinkargs(const u_char*& buf, int& n) + { + RecordVal *symlinkargs = new RecordVal(BifType::Record::NFS3::symlinkargs_t); + + symlinkargs->Assign(0, nfs3_diropargs(buf, n)); + symlinkargs->Assign(1, nfs3_symlinkdata(buf, n)); + + return symlinkargs; + } + +RecordVal* NFS_Interp::nfs3_sattrargs(const u_char*& buf, int& n) + { + RecordVal *sattrargs = new RecordVal(BifType::Record::NFS3::sattrargs_t); + + sattrargs->Assign(0, nfs3_fh(buf, n)); + sattrargs->Assign(1, nfs3_sattr(buf, n)); + + return sattrargs; + } + +RecordVal* NFS_Interp::nfs3_linkargs(const u_char*& buf, int& n) + { + RecordVal *linkargs = new RecordVal(BifType::Record::NFS3::linkargs_t); + + linkargs->Assign(0, nfs3_fh(buf, n)); + linkargs->Assign(1, nfs3_diropargs(buf, n)); + + return linkargs; + } + RecordVal *NFS_Interp::nfs3_writeargs(const u_char*& buf, int& n) { uint32_t bytes; diff --git a/src/analyzer/protocol/rpc/NFS.h b/src/analyzer/protocol/rpc/NFS.h index 85fb10ab49..3a6da1f765 100644 --- a/src/analyzer/protocol/rpc/NFS.h +++ b/src/analyzer/protocol/rpc/NFS.h @@ -34,11 +34,17 @@ protected: // are based on the type names of RFC 1813. StringVal* nfs3_fh(const u_char*& buf, int& n); RecordVal* nfs3_fattr(const u_char*& buf, int& n); + RecordVal* nfs3_sattr(const u_char*& buf, int& n); EnumVal* nfs3_ftype(const u_char*& buf, int& n); + EnumVal* nfs3_time_how(const u_char*& buf, int& n); RecordVal* nfs3_wcc_attr(const u_char*& buf, int& n); RecordVal* nfs3_diropargs(const u_char*&buf, int &n); + RecordVal* nfs3_symlinkdata(const u_char*& buf, int& n); RecordVal* nfs3_renameopargs(const u_char*&buf, int &n); StringVal* nfs3_filename(const u_char*& buf, int& n); + RecordVal* nfs3_linkargs(const u_char*& buf, int& n); + RecordVal* nfs3_symlinkargs(const u_char*& buf, int& n); + RecordVal* nfs3_sattrargs(const u_char*& buf, int& n); StringVal* nfs3_nfspath(const u_char*& buf, int& n) { return nfs3_filename(buf,n); @@ -46,10 +52,12 @@ protected: RecordVal* nfs3_post_op_attr(const u_char*&buf, int &n); // Return 0 or an fattr RecordVal* nfs3_pre_op_attr(const u_char*&buf, int &n); // Return 0 or an wcc_attr + RecordVal* nfs3_sattr_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status); RecordVal* nfs3_lookup_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status); RecordVal* nfs3_readargs(const u_char*& buf, int& n); RecordVal* nfs3_read_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status, bro_uint_t offset); RecordVal* nfs3_readlink_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status); + RecordVal* nfs3_link_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status); RecordVal* nfs3_writeargs(const u_char*& buf, int& n); EnumVal* nfs3_stable_how(const u_char*& buf, int& n); RecordVal* nfs3_write_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status); diff --git a/src/analyzer/protocol/rpc/events.bif b/src/analyzer/protocol/rpc/events.bif index 881faface1..f2ad7bc3f5 100644 --- a/src/analyzer/protocol/rpc/events.bif +++ b/src/analyzer/protocol/rpc/events.bif @@ -49,6 +49,34 @@ event nfs_proc_null%(c: connection, info: NFS3::info_t%); ## register a port for it or add a DPD payload signature. event nfs_proc_getattr%(c: connection, info: NFS3::info_t, fh: string, attrs: NFS3::fattr_t%); +## Generated for NFSv3 request/reply dialogues of type *sattr*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## +## NFS is a service running on top of RPC. See `Wikipedia +## `__ for more +## information about the service. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## rep: The attributes returned in the reply. The values may not be +## valid if the request was unsuccessful. +## +## .. bro:see:: nfs_proc_create nfs_proc_lookup nfs_proc_mkdir +## nfs_proc_not_implemented nfs_proc_null nfs_proc_read nfs_proc_readdir +## nfs_proc_readlink nfs_proc_remove nfs_proc_rmdir nfs_proc_write nfs_reply_status +## rpc_call rpc_dialogue rpc_reply file_mode +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event nfs_proc_sattr%(c: connection, info: NFS3::info_t, req: NFS3::sattrargs_t, rep: NFS3::sattr_reply_t%); + ## Generated for NFSv3 request/reply dialogues of type *lookup*. The event is ## generated once we have either seen both the request and its corresponding ## reply, or an unanswered request has timed out. @@ -124,8 +152,8 @@ event nfs_proc_read%(c: connection, info: NFS3::info_t, req: NFS3::readargs_t, r ## ## .. bro:see:: nfs_proc_create nfs_proc_getattr nfs_proc_lookup nfs_proc_mkdir ## nfs_proc_not_implemented nfs_proc_null nfs_proc_read nfs_proc_readdir -## nfs_proc_remove nfs_proc_rmdir nfs_proc_write nfs_reply_status rpc_call -## rpc_dialogue rpc_reply +## nfs_proc_remove nfs_proc_rmdir nfs_proc_write nfs_reply_status +## nfs_proc_symlink rpc_call rpc_dialogue rpc_reply ## ## .. todo:: Bro's current default configuration does not activate the protocol ## analyzer that generates this event; the corresponding script has not yet @@ -133,6 +161,62 @@ event nfs_proc_read%(c: connection, info: NFS3::info_t, req: NFS3::readargs_t, r ## register a port for it or add a DPD payload signature. event nfs_proc_readlink%(c: connection, info: NFS3::info_t, fh: string, rep: NFS3::readlink_reply_t%); +## Generated for NFSv3 request/reply dialogues of type *symlink*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## +## NFS is a service running on top of RPC. See `Wikipedia +## `__ for more +## information about the service. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## rep: The attributes returned in the reply. The values may not be +## valid if the request was unsuccessful. +## +## .. bro:see:: nfs_proc_create nfs_proc_lookup nfs_proc_mkdir +## nfs_proc_not_implemented nfs_proc_null nfs_proc_read nfs_proc_readdir +## nfs_proc_readlink nfs_proc_remove nfs_proc_rmdir nfs_proc_write nfs_reply_status +## nfs_proc_link rpc_call rpc_dialogue rpc_reply file_mode +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event nfs_proc_symlink%(c: connection, info: NFS3::info_t, req: NFS3::symlinkargs_t, rep: NFS3::newobj_reply_t%); + +## Generated for NFSv3 request/reply dialogues of type *link*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## +## NFS is a service running on top of RPC. See `Wikipedia +## `__ for more +## information about the service. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## rep: The response returned in the reply. The values may not be valid if the +## request was unsuccessful. +## +## .. bro:see:: nfs_proc_create nfs_proc_getattr nfs_proc_lookup nfs_proc_mkdir +## nfs_proc_not_implemented nfs_proc_null nfs_proc_read nfs_proc_readdir +## nfs_proc_remove nfs_proc_rmdir nfs_proc_write nfs_reply_status rpc_call +## nfs_proc_symlink rpc_dialogue rpc_reply +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event nfs_proc_link%(c: connection, info: NFS3::info_t, req: NFS3::linkargs_t, rep: NFS3::link_reply_t%); + ## Generated for NFSv3 request/reply dialogues of type *write*. The event is ## generated once we have either seen both the request and its corresponding ## reply, or an unanswered request has timed out. diff --git a/src/types.bif b/src/types.bif index 20995ef105..0befcb941e 100644 --- a/src/types.bif +++ b/src/types.bif @@ -18,7 +18,7 @@ module NFS3; enum proc_t %{ # NFSv3 procedures PROC_NULL = 0, # done PROC_GETATTR = 1, # done - PROC_SETATTR = 2, # not implemented + PROC_SETATTR = 2, # done PROC_LOOKUP = 3, # done PROC_ACCESS = 4, # not implemented PROC_READLINK = 5, # done @@ -26,12 +26,12 @@ enum proc_t %{ # NFSv3 procedures PROC_WRITE = 7, # done PROC_CREATE = 8, # partial PROC_MKDIR = 9, # partial - PROC_SYMLINK = 10, # not implemented + PROC_SYMLINK = 10, # done PROC_MKNOD = 11, # not implemented PROC_REMOVE = 12, # done PROC_RMDIR = 13, # done PROC_RENAME = 14, # done - PROC_LINK = 15, # not implemented + PROC_LINK = 15, # done PROC_READDIR = 16, # done PROC_READDIRPLUS = 17, # done PROC_FSSTAT = 18, # not implemented @@ -74,6 +74,12 @@ enum status_t %{ # NFSv3 return status NFS3ERR_UNKNOWN = 0xffffffff, %} +enum time_how_t %{ + DONT_CHANGE = 0, + SET_TO_SERVER_TIME = 1, + SET_TO_CLIENT_TIME = 2, +%} + enum file_type_t %{ FTYPE_REG = 1, FTYPE_DIR = 2, @@ -84,6 +90,7 @@ enum file_type_t %{ FTYPE_FIFO = 7, %} + enum stable_how_t %{ UNSTABLE = 0, DATA_SYNC = 1, @@ -100,12 +107,19 @@ enum createmode_t %{ # defined in init-bare.bro. type info_t: record; type fattr_t: record; +type sattr_t: record; +type symlinkdata_t: record; type diropargs_t: record; +type symlinkargs_t: record; +type sattrargs_t: record; +type linkargs_t: record; type renameopargs_t: record; +type sattr_reply_t: record; type lookup_reply_t: record; type readargs_t: record; type read_reply_t: record; type readlink_reply_t: record; +type link_reply_t: record; type writeargs_t: record; type wcc_attr_t: record; type write_reply_t: record;