Wireshark-dev: [Wireshark-dev] [PATCH 01/16] NFS: Fix NFSv3 READDIRPLUS filename snooping
From: Pali Rohár <pali@xxxxxxxxxx>
Date: Fri, 13 Sep 2024 23:08:36 +0200
--- epan/dissectors/packet-nfs.c | 109 ++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 15 deletions(-) diff --git a/epan/dissectors/packet-nfs.c b/epan/dissectors/packet-nfs.c index 4d6ec8503f88..59920f2c4bce 100644 --- a/epan/dissectors/packet-nfs.c +++ b/epan/dissectors/packet-nfs.c @@ -1042,6 +1042,7 @@ typedef struct nfs_name_snoop_key { const unsigned char *fh; } nfs_name_snoop_key_t; +static GHashTable *nfs_name_snoop_readdir; static GHashTable *nfs_name_snoop_unmatched; static GHashTable *nfs_name_snoop_matched; @@ -1184,6 +1185,10 @@ nfs_name_snoop_value_destroy(void *value) static void nfs_name_snoop_init(void) { + nfs_name_snoop_readdir = + g_hash_table_new_full(nfs_name_snoop_unmatched_hash, + nfs_name_snoop_unmatched_equal, + NULL, nfs_name_snoop_value_destroy); nfs_name_snoop_unmatched = g_hash_table_new_full(nfs_name_snoop_unmatched_hash, nfs_name_snoop_unmatched_equal, @@ -1197,6 +1202,7 @@ nfs_name_snoop_init(void) static void nfs_name_snoop_cleanup(void) { + g_hash_table_destroy(nfs_name_snoop_readdir); g_hash_table_destroy(nfs_name_snoop_unmatched); g_hash_table_destroy(nfs_name_snoop_matched); } @@ -1298,6 +1304,60 @@ nfs_name_snoop_add_fh(int xid, tvbuff_t *tvb, int fh_offset, int fh_length) g_hash_table_replace(nfs_name_snoop_matched, key, nns); } +static void +nfs_name_snoop_readdir_add_parent_fh(int xid, tvbuff_t *tvb, int fh_offset, int fh_length) +{ + nfs_name_snoop_t *nns; + unsigned char *fh; + + fh = (unsigned char *)tvb_memdup(NULL, tvb, fh_offset, fh_length); + + nns = g_new0(nfs_name_snoop_t, 1); + nns->parent_len = fh_length; + nns->parent = fh; + + g_hash_table_insert(nfs_name_snoop_readdir, GINT_TO_POINTER(xid), nns); +} + +static void +nfs_name_snoop_readdir_add_child_fh_name(int xid, tvbuff_t *tvb, int fh_offset, int fh_length, const char *name) +{ + nfs_name_snoop_t *readdir_nns; + unsigned char *fh; + nfs_name_snoop_t *nns; + nfs_name_snoop_key_t *key; + + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) + return; + + readdir_nns = (nfs_name_snoop_t *)g_hash_table_lookup(nfs_name_snoop_readdir, GINT_TO_POINTER(xid)); + if (!readdir_nns) + return; + + fh = (unsigned char *)tvb_memdup(NULL, tvb, fh_offset, fh_length); + + nns = g_new(nfs_name_snoop_t, 1); + nns->fh_length = fh_length; + nns->fh = fh; + nns->parent_len = readdir_nns->parent_len; + nns->parent = g_malloc(readdir_nns->parent_len); + memcpy(nns->parent, readdir_nns->parent, readdir_nns->parent_len); + nns->name_len = (int)strlen(name); + nns->name = g_strdup(name); + nns->full_name_len = 0; + nns->full_name = NULL; + nns->fs_cycle = false; + + key = wmem_new(wmem_file_scope(), nfs_name_snoop_key_t); + key->key = 0; + key->fh_length = nns->fh_length; + key->fh = nns->fh; + + g_hash_table_replace(nfs_name_snoop_matched, key, nns); + + /* do not remove entry from the nfs_name_snoop_readdir as it is used for more child names, not just this one */ +} + #define NFS_MAX_FS_DEPTH 100 static void @@ -3794,12 +3854,12 @@ dissect_nfs3_fh(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, /* are we snooping fh to filenames ?*/ if ((!pinfo->fd->visited) && nfs_file_name_snooping) { - /* NFS v3 LOOKUP, CREATE, MKDIR, READDIRPLUS + /* NFS v3 LOOKUP, CREATE, MKDIR calls might give us a mapping*/ if ( ((civ->prog == 100003) &&((civ->vers == 3) &&(!civ->request) - &&((civ->proc == 3)||(civ->proc == 8)||(civ->proc == 9)||(civ->proc == 17)))) + &&((civ->proc == 3)||(civ->proc == 8)||(civ->proc == 9)))) || civ->vers == 4 ) { fh_length = tvb_get_ntohl(tvb, offset); @@ -3808,6 +3868,17 @@ dissect_nfs3_fh(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, fh_length); } + /* NFS v3 READDIRPLUS calls might give us a mapping */ + if ( (civ->prog == 100003) + &&(civ->vers == 3) + &&(civ->request) + &&((civ->proc == 17)) + ) { + fh_length = tvb_get_ntohl(tvb, offset); + fh_offset = offset+4; + nfs_name_snoop_readdir_add_parent_fh(civ->xid, tvb, fh_offset, fh_length); + } + /* MOUNT v3 MNT replies might give us a filehandle */ if ( (civ->prog == 100005) &&(civ->vers == 3) @@ -5654,6 +5725,10 @@ dissect_nfs3_entryplus(tvbuff_t *tvb, int offset, packet_info *pinfo, { proto_item *entry_item; proto_tree *entry_tree; + int fh_follows_offset; + bool fh_follows; + int fh_offset; + int fh_length; int old_offset = offset; const char *name = NULL; rpc_call_info_value *civ = (rpc_call_info_value *)data; @@ -5665,29 +5740,33 @@ dissect_nfs3_entryplus(tvbuff_t *tvb, int offset, packet_info *pinfo, offset = dissect_nfs3_filename(tvb, offset, entry_tree, hf_nfs3_readdirplus_entry_name, &name); + proto_item_set_text(entry_item, "Entry: name %s", name); + + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name); + + offset = dissect_rpc_uint64(tvb, entry_tree, hf_nfs3_readdirplus_entry_cookie, + offset); + + offset = dissect_nfs3_post_op_attr(tvb, offset, pinfo, entry_tree, "name_attributes"); + /* are we snooping fh to filenames ?*/ if ((!pinfo->fd->visited) && nfs_file_name_snooping) { - /* v3 READDIRPLUS replies will give us a mapping */ + /* v3 READDIRPLUS replies might give us a mapping */ if ( (civ->prog == 100003) &&(civ->vers == 3) &&(!civ->request) &&((civ->proc == 17)) ) { - nfs_name_snoop_add_name(civ->xid, tvb, 0, 0, - 0/*parent offset*/, 0/*parent len*/, - name); + fh_follows_offset = offset; + fh_follows = tvb_get_ntohl(tvb, fh_follows_offset); + if (fh_follows == true) { + fh_length = tvb_get_ntohl(tvb, fh_follows_offset+4); + fh_offset = fh_follows_offset+4+4; + nfs_name_snoop_readdir_add_child_fh_name(civ->xid, tvb, fh_offset, fh_length, name); + } } } - proto_item_set_text(entry_item, "Entry: name %s", name); - - col_append_fstr(pinfo->cinfo, COL_INFO, " %s", name); - - offset = dissect_rpc_uint64(tvb, entry_tree, hf_nfs3_readdirplus_entry_cookie, - offset); - - offset = dissect_nfs3_post_op_attr(tvb, offset, pinfo, entry_tree, "name_attributes"); - offset = dissect_nfs3_post_op_fh(tvb, offset, pinfo, entry_tree, "name_handle", civ); /* now we know, that a readdirplus entry is shorter */ -- 2.20.1
- References:
- [Wireshark-dev] [PATCH 00/16] NFS: Improve dissector
- From: Pali Rohár
- [Wireshark-dev] [PATCH 00/16] NFS: Improve dissector
- Prev by Date: [Wireshark-dev] [PATCH 00/16] NFS: Improve dissector
- Next by Date: [Wireshark-dev] [PATCH 05/16] NFS: Dissect NFS4 GSS OID
- Previous by thread: [Wireshark-dev] [PATCH 00/16] NFS: Improve dissector
- Next by thread: [Wireshark-dev] [PATCH 05/16] NFS: Dissect NFS4 GSS OID
- Index(es):