naccyde / rpms / iproute

Forked from rpms/iproute 5 months ago
Clone

Blame SOURCES/0224-iplink-Check-address-length-via-netlink.patch

049c96
From 7bfe1d25875b2fef1cfd679fdd8c4a999928bb80 Mon Sep 17 00:00:00 2001
049c96
From: Jakub Sitnicki <jkbs@redhat.com>
049c96
Date: Wed, 27 Jul 2016 15:56:19 +0200
049c96
Subject: [PATCH] iplink: Check address length via netlink
049c96
049c96
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1253767
049c96
          https://bugzilla.redhat.com/show_bug.cgi?id=1271580
049c96
Upstream Status: iproute2.git commit 8fe58d5
049c96
Conflicts:
049c96
* context in iplink_parse_vf() because we don't have
049c96
  6c5ffb9a2c3d ("iplink: cleanup whitespace and checkpatch issues")
049c96
049c96
commit 8fe58d58941f440140986f444c3d040b5e350c87
049c96
Author: Phil Sutter <phil@nwl.cc>
049c96
Date:   Thu Jun 16 16:19:40 2016 +0200
049c96
049c96
    iplink: Check address length via netlink
049c96
049c96
    This is a feature which was lost during the conversion to netlink
049c96
    interface: If the device exists and a user tries to change the link
049c96
    layer address, query the kernel for the old address first and reject the
049c96
    new one if sizes differ.
049c96
049c96
    This patch adds the same check when setting VF address by assuming same
049c96
    length as PF device.
049c96
049c96
    Note that at least for VFs the check can't be done in kernel space since
049c96
    struct ifla_vf_mac lacks a length field and due to netlink padding the
049c96
    exact size can't be communicated to the kernel.
049c96
049c96
    Signed-off-by: Phil Sutter <phil@nwl.cc>
049c96
---
049c96
 ip/iplink.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
049c96
 1 file changed, 50 insertions(+), 2 deletions(-)
049c96
049c96
diff --git a/ip/iplink.c b/ip/iplink.c
049c96
index 7b070f4..a8bcc09 100644
049c96
--- a/ip/iplink.c
049c96
+++ b/ip/iplink.c
049c96
@@ -232,6 +232,36 @@ struct iplink_req {
049c96
 	char			buf[1024];
049c96
 };
049c96
 
049c96
+static int nl_get_ll_addr_len(unsigned int dev_index)
049c96
+{
049c96
+	int len;
049c96
+	struct iplink_req req = {
049c96
+		.n = {
049c96
+			.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
049c96
+			.nlmsg_type = RTM_GETLINK,
049c96
+			.nlmsg_flags = NLM_F_REQUEST
049c96
+		},
049c96
+		.i = {
049c96
+			.ifi_family = preferred_family,
049c96
+			.ifi_index = dev_index,
049c96
+		}
049c96
+	};
049c96
+	struct rtattr *tb[IFLA_MAX+1];
049c96
+
049c96
+	if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
049c96
+		return -1;
049c96
+
049c96
+	len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
049c96
+	if (len < 0)
049c96
+		return -1;
049c96
+
049c96
+	parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
049c96
+	if (!tb[IFLA_ADDRESS])
049c96
+		return -1;
049c96
+
049c96
+	return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
049c96
+}
049c96
+
049c96
 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
049c96
 			   struct iplink_req *req, int dev_index)
049c96
 {
049c96
@@ -269,11 +299,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
049c96
 		NEXT_ARG();
049c96
 		if (matches(*argv, "mac") == 0) {
049c96
 			struct ifla_vf_mac ivm = { 0 };
049c96
+			int halen = nl_get_ll_addr_len(dev_index);
049c96
 			NEXT_ARG();
049c96
 			ivm.vf = vf;
049c96
 			len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
049c96
 			if (len < 0)
049c96
 				return -1;
049c96
+			if (halen > 0 && len != halen) {
049c96
+				fprintf(stderr,
049c96
+					"Invalid address length %d - must be %d bytes\n",
049c96
+					len, halen);
049c96
+				return -1;
049c96
+			}
049c96
 			addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
049c96
 		} else if (matches(*argv, "vlan") == 0) {
049c96
 			struct ifla_vf_vlan ivv;
049c96
@@ -416,6 +453,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
049c96
 	int numrxqueues = -1;
049c96
 	int dev_index = 0;
049c96
 	int link_netnsid = -1;
049c96
+	int addr_len = 0;
049c96
 
049c96
 	*group = -1;
049c96
 	ret = argc;
049c96
@@ -435,10 +473,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
049c96
 			*link = *argv;
049c96
 		} else if (matches(*argv, "address") == 0) {
049c96
 			NEXT_ARG();
049c96
-			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
049c96
+			addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
049c96
 			if (len < 0)
049c96
 				return -1;
049c96
-			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
049c96
+			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len);
049c96
 		} else if (matches(*argv, "broadcast") == 0 ||
049c96
 				strcmp(*argv, "brd") == 0) {
049c96
 			NEXT_ARG();
049c96
@@ -635,6 +673,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
049c96
 		argc--; argv++;
049c96
 	}
049c96
 
049c96
+	if (dev_index && addr_len) {
049c96
+		int halen = nl_get_ll_addr_len(dev_index);
049c96
+		if (halen >= 0 && halen != addr_len) {
049c96
+			fprintf(stderr,
049c96
+			        "Invalid address length %d - must be %d bytes\n",
049c96
+			        addr_len, halen);
049c96
+			return -1;
049c96
+		}
049c96
+	}
049c96
+
049c96
 	return ret - argc;
049c96
 }
049c96
 
049c96
-- 
049c96
1.8.3.1
049c96