netlink: fully dissect NLA Type, add length restriction

NLA types consist of a type and two flags, add new fields for this.

Add a new parameter to restrict the data consumed by the
dissect_netlink_attributes function, this is needed when implementing
nested attributes using another call to this function. This also avoids
adding padding to the payload and matches the comment in
include/uapi/linux/netlink.h (Linux 4.7).

Change-Id: I34dbfa466081b6c6c4580941aff568bd120b4210
Reviewed-on: https://code.wireshark.org/review/17030
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Peter Wu 2016-08-11 23:30:06 +02:00 committed by Michael Mann
parent 5ae7076b3e
commit 620f5721b1
5 changed files with 69 additions and 33 deletions

View File

@ -310,7 +310,7 @@ dissect_nfq_config_attrs(tvbuff_t *tvb, void *data _U_, proto_tree *tree, int nl
static header_field_info hfi_nfq_config_attr NETLINK_NETFILTER_HFI_INIT =
{ "Type", "netlink-netfilter.queue.config_attr", FT_UINT16, BASE_DEC,
VALS(nfq_config_attr_vals), 0x00, NULL, HFILL };
VALS(nfq_config_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
/* QUEUE - Packet and verdict */
@ -592,7 +592,7 @@ dissect_nfq_attrs(tvbuff_t *tvb, void *data _U_, proto_tree *tree, int nla_type,
static header_field_info hfi_nfq_attr NETLINK_NETFILTER_HFI_INIT =
{ "Type", "netlink-netfilter.queue.attr", FT_UINT16, BASE_DEC,
VALS(nfq_attr_vals), 0x00, NULL, HFILL };
VALS(nfq_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
/* QUEUE - main */
@ -605,11 +605,11 @@ dissect_netfilter_queue(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tre
switch (type) {
case WS_NFQNL_MSG_CONFIG:
return dissect_netlink_attributes(tvb, &hfi_nfq_config_attr, ett_nfq_config_attr, info, tree, offset, dissect_nfq_config_attrs);
return dissect_netlink_attributes(tvb, &hfi_nfq_config_attr, ett_nfq_config_attr, info, tree, offset, -1, dissect_nfq_config_attrs);
case WS_NFQNL_MSG_PACKET:
case WS_NFQNL_MSG_VERDICT:
return dissect_netlink_attributes(tvb, &hfi_nfq_attr, ett_nfq_attr, info, tree, offset, dissect_nfq_attrs);
return dissect_netlink_attributes(tvb, &hfi_nfq_attr, ett_nfq_attr, info, tree, offset, -1, dissect_nfq_attrs);
case WS_NFQNL_MSG_VERDICT_BATCH:
/* TODO */

View File

@ -334,7 +334,7 @@ dissect_netlink_route_attributes(tvbuff_t *tvb, header_field_info *hfi_type, str
*/
/* XXX, nice */
return dissect_netlink_attributes(tvb, hfi_type, ett_netlink_route_attr, info, tree, offset, (netlink_attributes_cb_t *) cb);
return dissect_netlink_attributes(tvb, hfi_type, ett_netlink_route_attr, info, tree, offset, -1, (netlink_attributes_cb_t *) cb);
}
/* Interface */

View File

@ -350,7 +350,7 @@ static const value_string netlink_sock_diag_unix_attr_vals[] = {
static header_field_info hfi_netlink_sock_diag_unix_attr NETLINK_SOCK_DIAG_HFI_INIT =
{ "Type", "netlink-sock_diag.unix_attr", FT_UINT16, BASE_DEC,
VALS(netlink_sock_diag_unix_attr_vals), 0x00, NULL, HFILL };
VALS(netlink_sock_diag_unix_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
static header_field_info hfi_netlink_sock_diag_unix_name NETLINK_SOCK_DIAG_HFI_INIT =
{ "Name", "netlink-sock_diag.unix_name", FT_STRINGZ, STR_ASCII,
@ -442,7 +442,7 @@ dissect_sock_diag_unix_reply(tvbuff_t *tvb, netlink_sock_diag_info_t *info, prot
sock_diag_proto_tree_add_cookie(tree, info, tvb, offset);
offset += 8;
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_unix_attr, ett_netlink_sock_diag_attr, info, tree, offset, dissect_netlink_unix_sock_diag_reply_attrs);
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_unix_attr, ett_netlink_sock_diag_attr, info, tree, offset, -1, dissect_netlink_unix_sock_diag_reply_attrs);
}
/* AF_UNIX request */
@ -539,7 +539,7 @@ static const value_string netlink_sock_diag_inet_attr_vals[] = {
static header_field_info hfi_netlink_sock_diag_inet_attr NETLINK_SOCK_DIAG_HFI_INIT =
{ "Type", "netlink-sock_diag.inet_attr", FT_UINT16, BASE_DEC,
VALS(netlink_sock_diag_inet_attr_vals), 0x00, NULL, HFILL };
VALS(netlink_sock_diag_inet_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
static int
dissect_sock_diag_inet_attributes(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
@ -699,7 +699,7 @@ dissect_sock_diag_inet_reply(tvbuff_t *tvb, netlink_sock_diag_info_t *info, prot
proto_tree_add_item(tree, &hfi_netlink_sock_diag_inode, tvb, offset, 4, info->encoding);
offset += 4;
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_inet_attr, ett_netlink_sock_diag_attr, info, tree, offset, dissect_sock_diag_inet_attributes);
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_inet_attr, ett_netlink_sock_diag_attr, info, tree, offset, -1, dissect_sock_diag_inet_attributes);
}
/* AF_INET request */
@ -742,7 +742,7 @@ static const value_string netlink_sock_diag_netlink_vals[] = {
static header_field_info hfi_netlink_sock_diag_netlink_attr NETLINK_SOCK_DIAG_HFI_INIT =
{ "Type", "netlink-sock_diag.netlink_attr", FT_UINT16, BASE_DEC,
VALS(netlink_sock_diag_netlink_vals), 0x00, NULL, HFILL };
VALS(netlink_sock_diag_netlink_vals), NLA_TYPE_MASK, NULL, HFILL };
static int
dissect_sock_diag_netlink_attributes(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
@ -815,7 +815,7 @@ dissect_sock_diag_netlink_reply(tvbuff_t *tvb, netlink_sock_diag_info_t *info, p
sock_diag_proto_tree_add_cookie(tree, info, tvb, offset);
offset += 8;
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_netlink_attr, ett_netlink_sock_diag_attr, info, tree, offset, dissect_sock_diag_netlink_attributes);
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_netlink_attr, ett_netlink_sock_diag_attr, info, tree, offset, -1, dissect_sock_diag_netlink_attributes);
}
/* AF_NETLINK request */
@ -917,7 +917,7 @@ static const value_string netlink_sock_diag_packet_vals[] = {
static header_field_info hfi_netlink_sock_diag_packet_attr NETLINK_SOCK_DIAG_HFI_INIT =
{ "Type", "netlink-sock_diag.netlink_attr", FT_UINT16, BASE_DEC,
VALS(netlink_sock_diag_packet_vals), 0x00, NULL, HFILL };
VALS(netlink_sock_diag_packet_vals), NLA_TYPE_MASK, NULL, HFILL };
/* AF_PACKET */
@ -943,7 +943,7 @@ dissect_sock_diag_packet_reply(tvbuff_t *tvb, netlink_sock_diag_info_t *info, pr
sock_diag_proto_tree_add_cookie(tree, info, tvb, offset);
offset += 8;
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_packet_attr, ett_netlink_sock_diag_attr, info, tree, offset, dissect_netlink_packet_sock_diag_reply_attrs);
return dissect_netlink_attributes(tvb, &hfi_netlink_sock_diag_packet_attr, ett_netlink_sock_diag_attr, info, tree, offset, -1, dissect_netlink_packet_sock_diag_reply_attrs);
}
/* AF_PACKET request */

View File

@ -166,6 +166,18 @@ static header_field_info hfi_netlink_hdr_pid NETLINK_HFI_INIT =
{ "Port ID", "netlink.hdr_pid", FT_UINT32, BASE_DEC,
NULL, 0x00, "Sender port ID", HFILL };
static header_field_info hfi_netlink_attr_type NETLINK_HFI_INIT =
{ "Type", "netlink.attr_type", FT_UINT16, BASE_HEX,
NULL, 0x0000, "Netlink Attribute type", HFILL };
static header_field_info hfi_netlink_attr_type_nested NETLINK_HFI_INIT =
{ "Nested", "netlink.attr_type.nested", FT_UINT16, BASE_DEC,
NULL, NLA_F_NESTED, "Carries nested attributes", HFILL };
static header_field_info hfi_netlink_attr_type_net_byteorder NETLINK_HFI_INIT =
{ "Network byte order", "netlink.attr_type.net_byteorder", FT_UINT16, BASE_DEC,
NULL, NLA_F_NET_BYTEORDER, "Payload stored in network byte order", HFILL };
static header_field_info hfi_netlink_attr_len NETLINK_HFI_INIT =
{ "Len", "netlink.attr_len", FT_UINT16, BASE_DEC,
NULL, 0x00, NULL, HFILL };
@ -179,6 +191,7 @@ static gint ett_netlink_cooked = -1;
static gint ett_netlink_msghdr = -1;
static gint ett_netlink_msg = -1;
static gint ett_netlink_hdr_flags = -1;
static gint ett_netlink_attr_type = -1;
static dissector_table_t netlink_dissector_table;
@ -214,17 +227,23 @@ static const int *netlink_header_new_flags[] = {
int
dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, proto_tree *tree, int offset, netlink_attributes_cb_t cb)
dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, proto_tree *tree, int offset, int length, netlink_attributes_cb_t cb)
{
int padding = (4 - offset) & 3;
/* align to 4 */
offset = (offset + 3) & ~3;
offset += padding;
if (length == -1) {
length = tvb_captured_length_remaining(tvb, offset);
} else {
length -= padding;
}
while (tvb_captured_length_remaining(tvb, offset) >= 4) {
guint16 rta_len, rta_type;
int end_offset;
while (length >= 4) {
guint16 rta_len, rta_type, type;
proto_item *ti;
proto_tree *attr_tree;
proto_item *ti, *type_item;
proto_tree *attr_tree, *type_tree;
rta_len = tvb_get_letohs(tvb, offset);
if (rta_len < 4) {
@ -232,35 +251,44 @@ dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett,
break;
}
end_offset = (offset + rta_len + 3) & ~3;
/* Padding could be missing from the last attribute. */
end_offset = MIN(end_offset, (int)tvb_captured_length(tvb));
/* XXX expert info when rta_len < length? */
rta_len = MIN(rta_len, length);
attr_tree = proto_tree_add_subtree(tree, tvb, offset, end_offset - offset, ett, &ti, "Attribute");
attr_tree = proto_tree_add_subtree(tree, tvb, offset, rta_len, ett, &ti, "Attribute");
proto_tree_add_item(attr_tree, &hfi_netlink_attr_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
rta_type = tvb_get_letohs(tvb, offset);
proto_tree_add_item(attr_tree, hfi_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
type = rta_type & NLA_TYPE_MASK;
type_item = proto_tree_add_item(attr_tree, &hfi_netlink_attr_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
type_tree = proto_item_add_subtree(type_item, ett_netlink_attr_type);
proto_tree_add_item(type_tree, &hfi_netlink_attr_type_nested, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(type_tree, &hfi_netlink_attr_type_net_byteorder, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(type_tree, hfi_type, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (rta_type & NLA_F_NESTED)
proto_item_append_text(type_item, ", Nested");
if (hfi_type->strings) {
/* XXX, export hf_try_val_to_str */
const char *rta_str = try_val_to_str(rta_type, (const value_string *) hfi_type->strings);
const char *rta_str = try_val_to_str(type, (const value_string *) hfi_type->strings);
if (rta_str)
if (rta_str) {
proto_item_append_text(type_item, ", %s (%d)", rta_str, type);
proto_item_append_text(ti, ": %s", rta_str);
}
}
if (!cb(tvb, data, attr_tree, rta_type, offset, rta_len - 4)) {
/* not handled */
}
if (end_offset <= offset)
break;
offset = end_offset;
/* Assume offset already aligned, next offset is rta_len plus alignment. */
rta_len = MIN((rta_len + 3) & ~3, length);
offset += rta_len - 4; /* Header was already skipped */
length -= rta_len;
}
return offset;
@ -439,6 +467,9 @@ proto_register_netlink(void)
/* Netlink message attribute */
&hfi_netlink_attr_len,
&hfi_netlink_attr_type,
&hfi_netlink_attr_type_nested,
&hfi_netlink_attr_type_net_byteorder,
/* Netlink message payloads */
&hfi_netlink_error,
@ -449,7 +480,8 @@ proto_register_netlink(void)
&ett_netlink_cooked,
&ett_netlink_msghdr,
&ett_netlink_msg,
&ett_netlink_hdr_flags
&ett_netlink_hdr_flags,
&ett_netlink_attr_type,
};
int proto_netlink;

View File

@ -93,6 +93,10 @@ struct packet_netlink_data {
typedef int netlink_attributes_cb_t(tvbuff_t *, void *data, proto_tree *, int nla_type, int offset, int len);
int dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, proto_tree *tree, int offset, netlink_attributes_cb_t cb);
int dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, proto_tree *tree, int offset, int length, netlink_attributes_cb_t cb);
#define NLA_F_NESTED 0x8000
#define NLA_F_NET_BYTEORDER 0x4000
#define NLA_TYPE_MASK 0x3fff
#endif /* __PACKET_NETLINK_H__ */