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):