forked from osmocom/wireshark
SMB2: handle chained compression
The compression header "reserved" field is now a flags field. If the flags have the CHAINED bit, the meaning of the offset field changes and becomes a length field. "old" compressed method: [COMPRESS_TRANSFORM_HEADER with Flags=0] [OPTIONAL UNCOMPRESSED DATA] [COMPRESSED DATA] new "chained" compressed method: [fist 8 bytes of COMPRESS_TRANSFORM_HEADER with Flags=CHAINED] [ sequence of [ COMPRESSION_PAYLOAD_HEADER ] [ COMPRESSED PAYLOAD ]
This commit is contained in:
parent
b2fd5bcfb9
commit
b0f5b2c174
|
@ -553,9 +553,11 @@ static int hf_smb2_transform_encrypted_data = -1;
|
||||||
static int hf_smb2_protocol_id = -1;
|
static int hf_smb2_protocol_id = -1;
|
||||||
static int hf_smb2_comp_transform_orig_size = -1;
|
static int hf_smb2_comp_transform_orig_size = -1;
|
||||||
static int hf_smb2_comp_transform_comp_alg = -1;
|
static int hf_smb2_comp_transform_comp_alg = -1;
|
||||||
static int hf_smb2_comp_transform_reserved = -1;
|
static int hf_smb2_comp_transform_flags = -1;
|
||||||
static int hf_smb2_comp_transform_offset = -1;
|
static int hf_smb2_comp_transform_offset = -1;
|
||||||
|
static int hf_smb2_comp_transform_length = -1;
|
||||||
static int hf_smb2_comp_transform_data = -1;
|
static int hf_smb2_comp_transform_data = -1;
|
||||||
|
static int hf_smb2_comp_transform_orig_payload_size = -1;
|
||||||
static int hf_smb2_truncated = -1;
|
static int hf_smb2_truncated = -1;
|
||||||
static int hf_smb2_pipe_fragments = -1;
|
static int hf_smb2_pipe_fragments = -1;
|
||||||
static int hf_smb2_pipe_fragment = -1;
|
static int hf_smb2_pipe_fragment = -1;
|
||||||
|
@ -728,6 +730,7 @@ static gint ett_smb2_read_flags = -1;
|
||||||
static gint ett_smb2_signature = -1;
|
static gint ett_smb2_signature = -1;
|
||||||
static gint ett_smb2_transform_flags = -1;
|
static gint ett_smb2_transform_flags = -1;
|
||||||
static gint ett_smb2_fscc_file_attributes = -1;
|
static gint ett_smb2_fscc_file_attributes = -1;
|
||||||
|
static gint ett_smb2_comp_payload = -1;
|
||||||
|
|
||||||
static expert_field ei_smb2_invalid_length = EI_INIT;
|
static expert_field ei_smb2_invalid_length = EI_INIT;
|
||||||
static expert_field ei_smb2_bad_response = EI_INIT;
|
static expert_field ei_smb2_bad_response = EI_INIT;
|
||||||
|
@ -986,6 +989,14 @@ static const value_string smb2_comp_alg_types[] = {
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SMB2_COMP_FLAG_NONE 0x0000
|
||||||
|
#define SMB2_COMP_FLAG_CHAINED 0x0001
|
||||||
|
static const value_string smb2_comp_transform_flags_vals[] = {
|
||||||
|
{ SMB2_COMP_FLAG_NONE, "None" },
|
||||||
|
{ SMB2_COMP_FLAG_CHAINED, "Chained" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
#define SMB2_RDMA_TRANSFORM_NONE 0x0000
|
#define SMB2_RDMA_TRANSFORM_NONE 0x0000
|
||||||
#define SMB2_RDMA_TRANSFORM_ENCRYPTION 0x0001
|
#define SMB2_RDMA_TRANSFORM_ENCRYPTION 0x0001
|
||||||
static const value_string smb2_rdma_transform_types[] = {
|
static const value_string smb2_rdma_transform_types[] = {
|
||||||
|
@ -10169,6 +10180,92 @@ decrypt_smb_payload(packet_info *pinfo,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Append tvb[offset:offset+length] to out
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
append_uncompress_data(wmem_array_t *out, tvbuff_t *tvb, int offset, guint length)
|
||||||
|
{
|
||||||
|
wmem_array_append(out, tvb_get_ptr(tvb, offset, length), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dissect_smb2_chained_comp_payload(packet_info *pinfo, proto_tree *tree,
|
||||||
|
tvbuff_t *tvb, int offset,
|
||||||
|
wmem_array_t *out,
|
||||||
|
gboolean *ok)
|
||||||
|
{
|
||||||
|
proto_tree *subtree;
|
||||||
|
proto_item *subitem;
|
||||||
|
guint alg, length, flags, orig_size = 0;
|
||||||
|
tvbuff_t *uncomp_tvb = NULL;
|
||||||
|
gboolean lz_based = FALSE;
|
||||||
|
|
||||||
|
*ok = TRUE;
|
||||||
|
|
||||||
|
subtree = proto_tree_add_subtree_format(tree, tvb, offset, 0, ett_smb2_comp_payload, &subitem, "COMPRESSION_PAYLOAD_HEADER");
|
||||||
|
proto_tree_add_item_ret_uint(subtree, hf_smb2_comp_transform_comp_alg, tvb, offset, 2, ENC_LITTLE_ENDIAN, &alg);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
proto_tree_add_item_ret_uint(subtree, hf_smb2_comp_transform_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN, &flags);
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
proto_tree_add_item_ret_uint(subtree, hf_smb2_comp_transform_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &length);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
proto_item_set_len(subitem, length);
|
||||||
|
|
||||||
|
lz_based = (SMB2_COMP_ALG_LZNT1 <= alg && alg <= SMB2_COMP_ALG_LZ77HUFF);
|
||||||
|
if (lz_based) {
|
||||||
|
proto_tree_add_item_ret_uint(subtree, hf_smb2_comp_transform_orig_payload_size,
|
||||||
|
tvb, offset, 4, ENC_LITTLE_ENDIAN, &orig_size);
|
||||||
|
offset += 4;
|
||||||
|
length -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > MAX_UNCOMPRESSED_SIZE) {
|
||||||
|
/* decompression error */
|
||||||
|
col_append_str(pinfo->cinfo, COL_INFO, "Comp. SMB3 (invalid)");
|
||||||
|
*ok = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (alg) {
|
||||||
|
case SMB2_COMP_ALG_NONE:
|
||||||
|
append_uncompress_data(out, tvb, offset, length);
|
||||||
|
break;
|
||||||
|
case SMB2_COMP_ALG_LZ77:
|
||||||
|
uncomp_tvb = tvb_uncompress_lz77(tvb, offset, length);
|
||||||
|
break;
|
||||||
|
case SMB2_COMP_ALG_LZ77HUFF:
|
||||||
|
uncomp_tvb = tvb_uncompress_lz77huff(tvb, offset, length);
|
||||||
|
break;
|
||||||
|
case SMB2_COMP_ALG_LZNT1:
|
||||||
|
uncomp_tvb = tvb_uncompress_lznt1(tvb, offset, length);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
col_append_str(pinfo->cinfo, COL_INFO, "Comp. SMB3 (unknown)");
|
||||||
|
uncomp_tvb = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lz_based) {
|
||||||
|
if (!uncomp_tvb || tvb_reported_length(uncomp_tvb) != orig_size) {
|
||||||
|
/* decompression error */
|
||||||
|
col_append_str(pinfo->cinfo, COL_INFO, "Comp. SMB3 (invalid)");
|
||||||
|
*ok = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
append_uncompress_data(out, uncomp_tvb, 0, tvb_reported_length(uncomp_tvb));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
proto_tree_add_item(subtree, hf_smb2_comp_transform_data, tvb, offset, length, ENC_NA);
|
||||||
|
offset += length;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
tvbuff_t *tvb, int offset,
|
tvbuff_t *tvb, int offset,
|
||||||
|
@ -10176,14 +10273,30 @@ dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
tvbuff_t **comp_tvb,
|
tvbuff_t **comp_tvb,
|
||||||
tvbuff_t **plain_tvb)
|
tvbuff_t **plain_tvb)
|
||||||
{
|
{
|
||||||
guint final_size;
|
|
||||||
guint8 *orig_data;
|
|
||||||
gint in_size;
|
gint in_size;
|
||||||
tvbuff_t *uncomp_tvb = NULL;
|
tvbuff_t *uncomp_tvb = NULL;
|
||||||
|
guint flags;
|
||||||
|
wmem_array_t *uncomp_data;
|
||||||
|
|
||||||
*comp_tvb = NULL;
|
*comp_tvb = NULL;
|
||||||
*plain_tvb = NULL;
|
*plain_tvb = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
"old" compressed method:
|
||||||
|
|
||||||
|
[COMPRESS_TRANSFORM_HEADER with Flags=0]
|
||||||
|
[OPTIONAL UNCOMPRESSED DATA]
|
||||||
|
[COMPRESSED DATA]
|
||||||
|
|
||||||
|
new "chained" compressed method:
|
||||||
|
|
||||||
|
[fist 8 bytes of COMPRESS_TRANSFORM_HEADER with Flags=CHAINED]
|
||||||
|
[ sequence of
|
||||||
|
[ COMPRESSION_PAYLOAD_HEADER ]
|
||||||
|
[ COMPRESSED PAYLOAD ]
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
/* SMB2_COMPRESSION_TRANSFORM marker */
|
/* SMB2_COMPRESSION_TRANSFORM marker */
|
||||||
proto_tree_add_item(tree, hf_smb2_protocol_id, tvb, offset, 4, ENC_BIG_ENDIAN);
|
proto_tree_add_item(tree, hf_smb2_protocol_id, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
@ -10191,10 +10304,31 @@ dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_orig_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &scti->orig_size);
|
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_orig_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &scti->orig_size);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
|
uncomp_data = wmem_array_sized_new(pinfo->pool, 1, 1024);
|
||||||
|
|
||||||
|
flags = tvb_get_letohs(tvb, offset+2);
|
||||||
|
if (flags & SMB2_COMP_FLAG_CHAINED) {
|
||||||
|
gboolean all_ok = TRUE;
|
||||||
|
|
||||||
|
*comp_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset));
|
||||||
|
do {
|
||||||
|
gboolean ok = FALSE;
|
||||||
|
|
||||||
|
offset = dissect_smb2_chained_comp_payload(pinfo, tree, tvb, offset, uncomp_data, &ok);
|
||||||
|
if (!ok)
|
||||||
|
all_ok = FALSE;
|
||||||
|
} while (tvb_reported_length_remaining(tvb, offset) > 8);
|
||||||
|
if (all_ok)
|
||||||
|
goto decompression_ok;
|
||||||
|
else
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_comp_alg, tvb, offset, 2, ENC_LITTLE_ENDIAN, &scti->alg);
|
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_comp_alg, tvb, offset, 2, ENC_LITTLE_ENDIAN, &scti->alg);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
proto_tree_add_item(tree, hf_smb2_comp_transform_reserved, tvb, offset, 2, ENC_NA);
|
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN, &flags);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN, &scti->comp_offset);
|
proto_tree_add_item_ret_uint(tree, hf_smb2_comp_transform_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN, &scti->comp_offset);
|
||||||
|
@ -10207,13 +10341,12 @@ dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc enough space for partial normal packet + uncompressed segment */
|
/*
|
||||||
final_size = scti->orig_size + scti->comp_offset;
|
* final uncompressed size is the partial normal packet + uncompressed segment
|
||||||
orig_data = (guint8*)wmem_alloc0(pinfo->pool, final_size);
|
* final_size = scti->orig_size + scti->comp_offset
|
||||||
|
*/
|
||||||
/* copy start of partial packet */
|
|
||||||
tvb_memcpy(tvb, orig_data, offset, scti->comp_offset);
|
|
||||||
|
|
||||||
|
append_uncompress_data(uncomp_data, tvb, offset, scti->comp_offset);
|
||||||
in_size = tvb_reported_length_remaining(tvb, offset + scti->comp_offset);
|
in_size = tvb_reported_length_remaining(tvb, offset + scti->comp_offset);
|
||||||
|
|
||||||
/* decompress compressed segment */
|
/* decompress compressed segment */
|
||||||
|
@ -10227,7 +10360,6 @@ dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
case SMB2_COMP_ALG_LZNT1:
|
case SMB2_COMP_ALG_LZNT1:
|
||||||
uncomp_tvb = tvb_uncompress_lznt1(tvb, offset + scti->comp_offset, in_size);
|
uncomp_tvb = tvb_uncompress_lznt1(tvb, offset + scti->comp_offset, in_size);
|
||||||
break;
|
break;
|
||||||
case SMB2_COMP_ALG_NONE:
|
|
||||||
default:
|
default:
|
||||||
col_append_str(pinfo->cinfo, COL_INFO, "Comp. SMB3 (unknown)");
|
col_append_str(pinfo->cinfo, COL_INFO, "Comp. SMB3 (unknown)");
|
||||||
uncomp_tvb = NULL;
|
uncomp_tvb = NULL;
|
||||||
|
@ -10241,10 +10373,14 @@ dissect_smb2_comp_transform_header(packet_info *pinfo, proto_tree *tree,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write decompressed segment at the end of partial packet */
|
/* write decompressed segment at the end of partial packet */
|
||||||
|
append_uncompress_data(uncomp_data, uncomp_tvb, 0, scti->orig_size);
|
||||||
|
|
||||||
tvb_memcpy(uncomp_tvb, orig_data + scti->comp_offset, 0, scti->orig_size);
|
decompression_ok:
|
||||||
col_append_str(pinfo->cinfo, COL_INFO, "Decomp. SMB3");
|
col_append_str(pinfo->cinfo, COL_INFO, "Decomp. SMB3");
|
||||||
*plain_tvb = tvb_new_child_real_data(tvb, orig_data, final_size, final_size);
|
*plain_tvb = tvb_new_child_real_data(tvb,
|
||||||
|
(guint8 *)wmem_array_get_raw(uncomp_data),
|
||||||
|
wmem_array_get_count(uncomp_data),
|
||||||
|
wmem_array_get_count(uncomp_data));
|
||||||
add_new_data_source(pinfo, *plain_tvb, "Decomp. SMB3");
|
add_new_data_source(pinfo, *plain_tvb, "Decomp. SMB3");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -13215,9 +13351,9 @@ proto_register_smb2(void)
|
||||||
VALS(smb2_comp_alg_types), 0, NULL, HFILL }
|
VALS(smb2_comp_alg_types), 0, NULL, HFILL }
|
||||||
},
|
},
|
||||||
|
|
||||||
{ &hf_smb2_comp_transform_reserved,
|
{ &hf_smb2_comp_transform_flags,
|
||||||
{ "Reserved", "smb2.header.comp_transform.reserved", FT_BYTES, BASE_NONE,
|
{ "Flags", "smb2.header.comp_transform.flags", FT_UINT16, BASE_HEX,
|
||||||
NULL, 0, NULL, HFILL }
|
VALS(smb2_comp_transform_flags_vals), 0, NULL, HFILL }
|
||||||
},
|
},
|
||||||
|
|
||||||
{ &hf_smb2_comp_transform_offset,
|
{ &hf_smb2_comp_transform_offset,
|
||||||
|
@ -13225,11 +13361,21 @@ proto_register_smb2(void)
|
||||||
NULL, 0, NULL, HFILL }
|
NULL, 0, NULL, HFILL }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ &hf_smb2_comp_transform_length,
|
||||||
|
{ "Length", "smb2.header.comp_transform.length", FT_UINT32, BASE_HEX,
|
||||||
|
NULL, 0, NULL, HFILL }
|
||||||
|
},
|
||||||
|
|
||||||
{ &hf_smb2_comp_transform_data,
|
{ &hf_smb2_comp_transform_data,
|
||||||
{ "CompressedData", "smb2.header.comp_transform.data", FT_BYTES, BASE_NONE,
|
{ "CompressedData", "smb2.header.comp_transform.data", FT_BYTES, BASE_NONE,
|
||||||
NULL, 0, NULL, HFILL }
|
NULL, 0, NULL, HFILL }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ &hf_smb2_comp_transform_orig_payload_size,
|
||||||
|
{ "OriginalPayloadSize", "smb2.header.comp_transform.orig_payload_size", FT_UINT32, BASE_DEC,
|
||||||
|
NULL, 0, NULL, HFILL }
|
||||||
|
},
|
||||||
|
|
||||||
{ &hf_smb2_protocol_id,
|
{ &hf_smb2_protocol_id,
|
||||||
{ "ProtocolId", "smb2.protocol_id", FT_UINT32, BASE_HEX,
|
{ "ProtocolId", "smb2.protocol_id", FT_UINT32, BASE_HEX,
|
||||||
NULL, 0, NULL, HFILL }
|
NULL, 0, NULL, HFILL }
|
||||||
|
@ -13579,6 +13725,7 @@ proto_register_smb2(void)
|
||||||
&ett_smb2_signature,
|
&ett_smb2_signature,
|
||||||
&ett_smb2_transform_flags,
|
&ett_smb2_transform_flags,
|
||||||
&ett_smb2_fscc_file_attributes,
|
&ett_smb2_fscc_file_attributes,
|
||||||
|
&ett_smb2_comp_payload,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ei_register_info ei[] = {
|
static ei_register_info ei[] = {
|
||||||
|
|
Loading…
Reference in New Issue