diff options
-rw-r--r-- | epan/dissectors/packet-mp4.c | 100 |
1 files changed, 71 insertions, 29 deletions
diff --git a/epan/dissectors/packet-mp4.c b/epan/dissectors/packet-mp4.c index 1362fa7b6c..f8f4812f20 100644 --- a/epan/dissectors/packet-mp4.c +++ b/epan/dissectors/packet-mp4.c @@ -34,6 +34,7 @@ #include "config.h" #include <glib.h> +#include <epan/expert.h> #include <epan/packet.h> #define MAKE_TYPE_VAL(a, b, c, d) (a)<<24 | (b)<<16 | (c)<<8 | (d) @@ -45,14 +46,19 @@ static gint ett_mp4_box = -1; static int hf_mp4_box_size = -1; static int hf_mp4_box_type_str = -1; +static int hf_mp4_box_largesize = -1; static int hf_mp4_full_box_ver = -1; static int hf_mp4_ftyp_brand = -1; static int hf_mp4_ftyp_ver = -1; static int hf_mp4_ftyp_add_brand = -1; static int hf_mp4_mfhd_seq_num = -1; +static expert_field ei_mp4_box_too_large = EI_INIT; + /* a box must at least have a 32bit len field and a 32bit type */ -#define MIN_BOX_LEN 8 +#define MIN_BOX_SIZE 8 +/* an extended box has the first length field set to 1 */ +#define BOX_SIZE_EXTENDED 1 /* the box type is stored as four text characters it is in network byte order and contains only printable characters @@ -86,6 +92,7 @@ static int hf_mp4_mfhd_seq_num = -1; #define BOX_TYPE_TFHD MAKE_TYPE_VAL('t', 'f', 'h', 'd') #define BOX_TYPE_TRUN MAKE_TYPE_VAL('t', 'r', 'u', 'n') #define BOX_TYPE_MDAT MAKE_TYPE_VAL('m', 'd', 'a', 't') +#define BOX_TYPE_UDTA MAKE_TYPE_VAL('u', 'd', 't', 'a') static const value_string box_types[] = { @@ -116,14 +123,15 @@ static const value_string box_types[] = { { BOX_TYPE_TFHD, "Track Fragment Header Box" }, { BOX_TYPE_TRUN, "Track Fragment Run Box" }, { BOX_TYPE_MDAT, "Media Data Box" }, + { BOX_TYPE_UDTA, "User Data Box" }, { 0, NULL } }; -static int -dissect_mp4_mvhd_body(tvbuff_t *tvb, guint offset, guint len _U_, +static gint +dissect_mp4_mvhd_body(tvbuff_t *tvb, gint offset, gint len _U_, packet_info *pinfo _U_, proto_tree *tree) { - guint offset_start; + gint offset_start; offset_start = offset; proto_tree_add_item(tree, hf_mp4_full_box_ver, @@ -134,11 +142,11 @@ dissect_mp4_mvhd_body(tvbuff_t *tvb, guint offset, guint len _U_, return offset-offset_start; } -static int -dissect_mp4_mfhd_body(tvbuff_t *tvb, guint offset, guint len _U_, +static gint +dissect_mp4_mfhd_body(tvbuff_t *tvb, gint offset, gint len _U_, packet_info *pinfo _U_, proto_tree *tree) { - guint offset_start; + gint offset_start; offset_start = offset; proto_tree_add_item(tree, hf_mp4_full_box_ver, @@ -154,11 +162,11 @@ dissect_mp4_mfhd_body(tvbuff_t *tvb, guint offset, guint len _U_, } -static int -dissect_mp4_ftyp_body(tvbuff_t *tvb, guint offset, guint len, +static gint +dissect_mp4_ftyp_body(tvbuff_t *tvb, gint offset, gint len, packet_info *pinfo _U_, proto_tree *tree) { - guint offset_start; + gint offset_start; offset_start = offset; proto_tree_add_item(tree, hf_mp4_ftyp_brand, @@ -177,54 +185,73 @@ dissect_mp4_ftyp_body(tvbuff_t *tvb, guint offset, guint len, return offset-offset_start; } +/* dissect a box, return its (standard or extended) length or 0 for error */ static gint dissect_mp4_box(guint32 parent_box_type _U_, - tvbuff_t *tvb, guint offset, packet_info *pinfo, proto_tree *tree) + tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree) { - guint offset_start; - guint box_len; + gint offset_start; + guint64 box_size; guint32 box_type; guint8 *box_type_str; - proto_item *pi; + proto_item *type_pi, *size_pi, *ext_size_pi = NULL; proto_tree *box_tree; gint ret; + gint body_size; offset_start = offset; /* the following mechanisms are not supported for now - - extended size (size==1, largesize parameter) - size==0, indicating that the box extends to the end of the file - extended box types */ - box_len = tvb_get_ntohl(tvb, offset); - if (box_len<MIN_BOX_LEN) + box_size = (guint64)tvb_get_ntohl(tvb, offset); + if (box_size!=BOX_SIZE_EXTENDED && box_size<MIN_BOX_SIZE) return -1; box_type = tvb_get_ntohl(tvb, offset+4); box_type_str = tvb_get_ephemeral_string(tvb, offset+4, 4); - pi = proto_tree_add_text(tree, tvb, offset, box_len, "%s (%s)", + type_pi = proto_tree_add_text(tree, tvb, offset, -1, "%s (%s)", val_to_str_const(box_type, box_types, "unknown"), box_type_str); - box_tree = proto_item_add_subtree(pi, ett_mp4_box); + box_tree = proto_item_add_subtree(type_pi, ett_mp4_box); - proto_tree_add_item(box_tree, hf_mp4_box_size, + size_pi = proto_tree_add_item(box_tree, hf_mp4_box_size, tvb, offset, 4, ENC_BIG_ENDIAN); + if (box_size==BOX_SIZE_EXTENDED) + proto_item_append_text(size_pi, " (actual size is in largesize)"); + offset += 4; proto_tree_add_item(box_tree, hf_mp4_box_type_str, tvb, offset, 4, ENC_ASCII|ENC_NA); offset += 4; + if (box_size==BOX_SIZE_EXTENDED) { + box_size = tvb_get_ntoh64(tvb, offset); + ext_size_pi = proto_tree_add_item(box_tree, hf_mp4_box_largesize, + tvb, offset, 8, ENC_BIG_ENDIAN); + offset += 8; + } + + if (box_size > G_MAXINT) { + /* this should be ok for ext_size_pi==NULL */ + expert_add_info(pinfo, ext_size_pi, &ei_mp4_box_too_large); + return -1; + } + proto_item_set_len(type_pi, (gint)box_size); + body_size = (gint)box_size - (offset-offset_start); + /* XXX - check parent box if supplied */ switch (box_type) { case BOX_TYPE_FTYP: - dissect_mp4_ftyp_body(tvb, offset, box_len-8, pinfo, box_tree); + dissect_mp4_ftyp_body(tvb, offset, body_size, pinfo, box_tree); break; case BOX_TYPE_MVHD: - dissect_mp4_mvhd_body(tvb, offset, box_len-8, pinfo, box_tree); + dissect_mp4_mvhd_body(tvb, offset, body_size, pinfo, box_tree); break; case BOX_TYPE_MFHD: - dissect_mp4_mfhd_body(tvb, offset, box_len-8, pinfo, box_tree); + dissect_mp4_mfhd_body(tvb, offset, body_size, pinfo, box_tree); break; case BOX_TYPE_MOOV: case BOX_TYPE_MOOF: @@ -235,7 +262,8 @@ dissect_mp4_box(guint32 parent_box_type _U_, case BOX_TYPE_MINF: case BOX_TYPE_MVEX: case BOX_TYPE_DINF: - while (offset-offset_start<box_len) { + case BOX_TYPE_UDTA: + while (offset-offset_start<(gint)box_size) { ret = dissect_mp4_box(box_type, tvb, offset, pinfo, box_tree); if (ret<=0) break; @@ -246,14 +274,14 @@ dissect_mp4_box(guint32 parent_box_type _U_, break; } - return box_len; + return (gint)box_size; } static int dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { - guint offset = 0; + gint offset = 0; guint32 box_type; proto_item *pi; proto_tree *mp4_tree; @@ -261,10 +289,11 @@ dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) /* to make sure that we have an mp4 file, we check that it starts with a box of a known type - this should be safe as long as the dissector is only called for + please note that we do not allow the first box to be an extended box + this detection should be safe as long as the dissector is only called for the video/mp4 mime type when we read mp4 files directly, we might need stricter checks here */ - if (tvb_reported_length(tvb)<MIN_BOX_LEN) + if (tvb_reported_length(tvb)<MIN_BOX_SIZE) return 0; box_type = tvb_get_ntohl(tvb, 4); if (try_val_to_str(box_type, box_types) == NULL) @@ -274,7 +303,7 @@ dissect_mp4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) col_clear(pinfo->cinfo, COL_INFO); pi = proto_tree_add_protocol_format(tree, proto_mp4, - tvb, 0, tvb_reported_length(tvb), "MP4"); + tvb, 0, (gint)tvb_reported_length(tvb), "MP4"); mp4_tree = proto_item_add_subtree(pi, ett_mp4); while (tvb_reported_length_remaining(tvb, offset) > 0) { @@ -297,6 +326,9 @@ proto_register_mp4(void) { &hf_mp4_box_type_str, { "Box type", "mp4.box.type_str", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, + { &hf_mp4_box_largesize, + { "Box size (largesize)", "mp4.box.largesize", FT_UINT64, BASE_DEC, + NULL, 0, NULL, HFILL } }, { &hf_mp4_full_box_ver, { "Box version", "mp4.full_box.version", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, @@ -319,10 +351,20 @@ proto_register_mp4(void) &ett_mp4_box }; + static ei_register_info ei[] = { + { &ei_mp4_box_too_large, + { "mp4.box_too_large", PI_PROTOCOL, PI_WARN, + "box size too large, dissection of this box is not supported", EXPFILL }} + }; + + expert_module_t* expert_mp4; + proto_mp4 = proto_register_protocol("MP4 / ISOBMFF file format", "mp4", "mp4"); proto_register_field_array(proto_mp4, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + expert_mp4 = expert_register_protocol(proto_mp4); + expert_register_field_array(expert_mp4, ei, array_length(ei)); } void |