[Devel] [PATCH RHEL7 COMMIT] ms/net: netlink -- Use ifinfomsg in dumping

Konstantin Khorenko khorenko at virtuozzo.com
Wed Jun 17 01:47:58 PDT 2015


The commit is pushed to "branch-rh7-3.10.0-123.1.2-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-123.1.2.vz7.5.14
------>
commit 19eaf0d1aa8e5e6e50d4c8205e59a3b94491b165
Author: Kirill Tkhai <ktkhai at odin.com>
Date:   Wed Jun 17 12:47:58 2015 +0400

    ms/net: netlink -- Use ifinfomsg in dumping
    
    Porting patch diff-ms-net-netlink-use-ifinfomsg-in-dumping-information-about-interfaces-v2
    from 2.6.32:
    
    Newer iproute2 package uses struct ifinfomsg to encode information about ext_filter_mask
    (see commit 63338dca45135c85c7f588bd5068e6e77ff816eb in iproute package) but the
    kernel is not updated and calculates the data offset incorrectly leading to messages
    
     | [10424.506841] netlink: 20 bytes leftover after parsing attributes.
     | [10424.506846] netlink: 20 bytes leftover after parsing attributes.
     | [10424.506865] netlink: 20 bytes leftover after parsing attributes.
    
    Introduce compat_parse_size helper which chooses the structure size to be parsed.
    
    Here is an example of request from the iproute2 (ip a)
    
     | \x28\x00\x00\x00
     | \x12\x00
     | \x01\x03
     | \x7f\xc7\x85\x53
     | \x00\x00\x00\x00
     | \x00
     | \x00
     | \x00\x00
     | \x00\x00\x00\x00
     | \x00\x00\x00\x00
     | \x00\x00\x00\x00
     | \x08\x00\x1d\x00\x01\x00\x00\x00
     |
     | struct nlmsghdr {
     |	__u32		nlmsg_len;				-> \x28\x00\x00\x00	(40)
     |	__u16		nlmsg_type;				-> \x12\x00		(18 - RTM_GETLINK)
     |	__u16		nlmsg_flags;				-> \x01\x03		(NLM_F_REQUEST | NLM_F_DUMP)
     |	__u32		nlmsg_seq;				-> \x13\x89\x85\x53
     |	__u32		nlmsg_pid;				-> \x00\x00\x00\x00
     | }
     |
     | struct ifinfomsg {
     |	unsigned char	ifi_family;				-> \x00
     |	unsigned char	__ifi_pad;				-> \x00
     |	unsigned short	ifi_type;				-> \x00\x00
     |	int		ifi_index;				-> \x00\x00\x00\x00
     |	unsigned	ifi_flags;				-> \x00\x00\x00\x00
     |	unsigned	ifi_change;				-> \x00\x00\x00\x00
     | };
    
    https://jira.sw.ru/browse/PSBM-26757
    
    v2: Actually there is a serious flawn in handling the netlink packets
        when fetching information about interfaces -- the @tb array allocated
        on the stack and (!) nlmsg_parse is not tested for error code thus
        it might leave unitialized if nlmsg_parse exit early (I already
        hit #GP once). So fix this problem at once.
    
    Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
    Acked-by: Kirill Tkhai <ktkhai at parallels.com>
    
    Note: the problem, which is described in v2 paragraph, has gone, because
    the code checks for nlmsg_parse() retval now.
    
    Made in scope of https://jira.sw.ru/browse/PSBM-33645
    
    Signed-off-by: Kirill Tkhai <ktkhai at odin.com>
    Acked-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 net/core/rtnetlink.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 40f13c1..d97abba 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1124,6 +1124,18 @@ static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
 	[IFLA_PORT_RESPONSE]	= { .type = NLA_U16, },
 };
 
+/*
+ * New iproute2 user-space tool send requests in struct ifinfomsg format,
+ * while old ones use struct rtgenmsg. So guess which one is passed depending
+ * on the payload size.
+ */
+static int compat_parse_size(const struct nlmsghdr *nlh)
+{
+	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct ifinfomsg)))
+		return sizeof(struct rtgenmsg);
+	return sizeof(struct ifinfomsg);
+}
+
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
@@ -1140,7 +1152,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 	rcu_read_lock();
 	cb->seq = net->dev_base_seq;
 
-	if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
+	if (nlmsg_parse(cb->nlh, compat_parse_size(cb->nlh), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 
 		if (tb[IFLA_EXT_MASK])
@@ -1943,7 +1955,7 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
 	u32 ext_filter_mask = 0;
 	u16 min_ifinfo_dump_size = 0;
 
-	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
+	if (nlmsg_parse(nlh, compat_parse_size(nlh), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 		if (tb[IFLA_EXT_MASK])
 			ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);



More information about the Devel mailing list