Reassemble PLP chunks.

Display the data in a PLP chunk as just raw bytes, and reassembled all
the chunks and extract the value from the reassembled data.

Showing the chunks as strings doesn't necessarily work - if the string
is an NVarChar string, a chunk might well have an odd number of octets,
meaning you're splitting one of the 16-bit UTF-16LE items in half.
Reassembling handles that, as well as just, in general, showing the
actual value rather than pieces of the value.

If the column is a string, append its value to the top-level item, just
as we do for non-PLP strings.

Also, if a length value was specified, report an error if it doesn't
match the total length of the reassembled chunks.

Change-Id: Iab80da052eb363ee08cd518afbe2556a5ab740b9
Reviewed-on: https://code.wireshark.org/review/33466
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot
Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
Guy Harris 2019-06-04 11:06:38 -07:00
parent 7cb77f5ca7
commit 7b12f11721
1 changed files with 97 additions and 12 deletions

View File

@ -1215,6 +1215,7 @@ static int hf_tds_type_varbyte_data_textptr = -1;
static int hf_tds_type_varbyte_data_text_ts = -1;
static int hf_tds_type_varbyte_plp_len = -1;
static int hf_tds_type_varbyte_plp_chunk_len = -1;
static int hf_tds_type_varbyte_plp_chunk = -1;
static int hf_tds_type_varbyte_column_name = -1;
/****************************** Top level TDS ******************************/
@ -1287,6 +1288,7 @@ static gint ett_tds5_curinfo_status = -1;
/* static expert_field ei_tds_type_info_type_undecoded = EI_INIT; */
static expert_field ei_tds_invalid_length = EI_INIT;
static expert_field ei_tds_token_length_invalid = EI_INIT;
static expert_field ei_tds_invalid_plp_length = EI_INIT;
static expert_field ei_tds_type_info_type = EI_INIT;
static expert_field ei_tds_all_headers_header_type = EI_INIT;
/* static expert_field ei_tds_token_stats = EI_INIT; */
@ -2103,40 +2105,117 @@ dissect_tds_type_varbyte(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto
if(plp_length == TDS_PLP_NULL)
proto_item_append_text(length_item, " (PLP_NULL)");
else {
if(plp_length == TDS_UNKNOWN_PLP_LEN)
tvbuff_t *combined_chunks_tvb;
guint combined_length;
if(plp_length == TDS_UNKNOWN_PLP_LEN) {
proto_item_append_text(length_item, " (UNKNOWN_PLP_LEN)");
}
/*
* XXX - composite tvbuffs with no compontents aren't supported,
* so we create the tvbuff when the first non-terminator chunk
* is found.
*/
combined_chunks_tvb = NULL;
while(TRUE) {
/*
* XXX - this needs to reassemble the chunks, making sure
* the total length of all the chunks isn't greater than
* the item length. The result of the reassembly is the data
* to dissect.
*/
length_item = proto_tree_add_item_ret_uint(sub_tree, hf_tds_type_varbyte_plp_chunk_len, tvb, *offset, 4, ENC_LITTLE_ENDIAN, &length);
*offset += 4;
if(length == TDS_PLP_TERMINATOR) {
proto_item_append_text(length_item, " (PLP_TERMINATOR)");
break;
}
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_plp_chunk, tvb, *offset, length, ENC_NA);
if (combined_chunks_tvb == NULL)
combined_chunks_tvb = tvb_new_composite();
/* Add this chunk to the composite tvbuff */
tvbuff_t *chunk_tvb = tvb_new_subset_length(tvb, *offset, length);
tvb_composite_append(combined_chunks_tvb, chunk_tvb);
*offset += length;
}
if (combined_chunks_tvb != NULL) {
tvb_composite_finalize(combined_chunks_tvb);
/*
* If a length was specified, report an error if it's not
* the same as the reassembled length.
*/
combined_length = tvb_reported_length(combined_chunks_tvb);
if(plp_length != TDS_UNKNOWN_PLP_LEN) {
if(plp_length != combined_length) {
expert_add_info(pinfo, length_item, &ei_tds_invalid_plp_length);
}
}
/*
* Now dissect the reassembled data.
*
* XXX - can we make this item cover multiple ranges?
* If so, do so.
*/
const guint8 *strval = NULL;
switch(data_type) {
case TDS_DATA_TYPE_BIGVARBIN: /* VarBinary */
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_bytes, tvb, *offset, length, ENC_NA);
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_bytes, combined_chunks_tvb, 0, combined_length, ENC_NA);
break;
case TDS_DATA_TYPE_BIGVARCHR: /* VarChar */
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_string, tvb, *offset, length, ENC_ASCII|ENC_NA);
proto_tree_add_item_ret_string(sub_tree,
hf_tds_type_varbyte_data_string,
combined_chunks_tvb, 0, combined_length, ENC_ASCII|ENC_NA,
wmem_packet_scope(), &strval);
if (strval) {
proto_item_append_text(item, " (%s)", strval);
}
break;
case TDS_DATA_TYPE_NVARCHAR: /* NVarChar */
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_string, tvb, *offset, length, ENC_UTF_16|ENC_LITTLE_ENDIAN);
proto_tree_add_item_ret_string(sub_tree,
hf_tds_type_varbyte_data_string,
combined_chunks_tvb, 0, combined_length, ENC_UTF_16|ENC_LITTLE_ENDIAN,
wmem_packet_scope(), &strval);
if (strval) {
proto_item_append_text(item, " (%s)", strval);
}
break;
case TDS_DATA_TYPE_XML: /* XML (introduced in TDS 7.2) */
case TDS_DATA_TYPE_UDT: /* CLR-UDT (introduced in TDS 7.2) */
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_bytes, tvb, *offset, length, ENC_NA);
proto_tree_add_item(sub_tree, hf_tds_type_varbyte_data_bytes, combined_chunks_tvb, 0, combined_length, ENC_NA);
break;
default:
/* no other data type sets plp = TRUE */
expert_add_info_format(pinfo, length_item, &ei_tds_invalid_plp_type, "This type should not use PLP");
}
} else {
/*
* If a length was specified, report an error if it's not
* zero.
*/
if(plp_length != TDS_UNKNOWN_PLP_LEN) {
if(plp_length != 0) {
expert_add_info(pinfo, length_item, &ei_tds_invalid_plp_length);
}
}
/*
* The data is empty.
*/
switch(data_type) {
case TDS_DATA_TYPE_BIGVARBIN: /* VarBinary */
proto_tree_add_bytes(sub_tree, hf_tds_type_varbyte_data_bytes, NULL, 0, 0, NULL);
break;
case TDS_DATA_TYPE_BIGVARCHR: /* VarChar */
proto_tree_add_string(sub_tree, hf_tds_type_varbyte_data_string, NULL, 0, 0, "");
break;
case TDS_DATA_TYPE_NVARCHAR: /* NVarChar */
proto_tree_add_string(sub_tree, hf_tds_type_varbyte_data_string, NULL, 0, 0, "");
break;
case TDS_DATA_TYPE_XML: /* XML (introduced in TDS 7.2) */
case TDS_DATA_TYPE_UDT: /* CLR-UDT (introduced in TDS 7.2) */
proto_tree_add_bytes(sub_tree, hf_tds_type_varbyte_data_bytes, NULL, 0, 0, NULL);
break;
default:
/* no other data type sets plp = TRUE */
expert_add_info_format(pinfo, length_item, &ei_tds_invalid_plp_type, "This type should not use PLP");
}
*offset += length;
}
}
}
@ -9935,6 +10014,11 @@ proto_register_tds(void)
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_tds_type_varbyte_plp_chunk,
{ "PLP chunk", "tds.type_varbyte.plp_chunk",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_tds_type_varbyte_column_name,
{ "Column name", "tds.type_varbyte.column.name",
FT_STRING, BASE_NONE, NULL, 0x0,
@ -10129,6 +10213,7 @@ proto_register_tds(void)
#endif
{ &ei_tds_invalid_length, { "tds.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
{ &ei_tds_token_length_invalid, { "tds.token.length.invalid", PI_PROTOCOL, PI_WARN, "Bogus token size", EXPFILL }},
{ &ei_tds_invalid_plp_length, { "tds.invalid_plp_length", PI_PROTOCOL, PI_NOTE, "PLP length doesn't equal the sum of the lengths of the chunks", EXPFILL }},
#if 0
{ &ei_tds_token_stats, { "tds.token.stats", PI_PROTOCOL, PI_NOTE, "Token stats", EXPFILL }},
#endif