[ovs-dev] [PATCH 1/2] netlink: Refine calculation of maximum-length attributes.

Ben Pfaff blp at nicira.com
Sun Jan 11 21:50:24 UTC 2015


Until now the Netlink code has considered an attribute to exceed the
maximum length if the *padded* size of the attribute exceeds 65535 bytes.
For example, an attribute with a 65529-byte payload, together with 4-byte
header and 3 bytes of padding, takes up 65536 bytes and therefore the
existing code rejected it.

However, the restriction on Netlink attribute sizes is to ensure that the
length fits in the 16-bit nla_len field.  This field includes the 4-byte
header but not the padding, so a 65529-byte payload is acceptable because,
with the header but not the padding, it comes to only 65533 bytes.

Thus, this commit relaxes the restriction on Netlink attribute sizes by
omitting padding from size checks.  It also changes one piece of code that
inlined a size check to use the central function nl_attr_oversized().

This change should fix an assertion failure when OVS userspace passes a
maximum-size (65529+ byte) packet back to the kernel.

Reported-by: Shuping Cui <scui at redhat.com>
Reported-by: Jiri Benc <jbenc at redhat.com>
Signed-off-by: Ben Pfaff <blp at nicira.com>
Acked-by: Jesse Gross <jesse at nicira.com>
---
 lib/netlink.c |  6 +++---
 lib/netlink.h | 11 +++++++++--
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lib/netlink.c b/lib/netlink.c
index b6f7d45..52fc7dd 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -214,7 +214,7 @@ nl_msg_put_unspec_uninit(struct ofpbuf *msg, uint16_t type, size_t size)
 {
     size_t total_size = NLA_HDRLEN + size;
     struct nlattr* nla = nl_msg_put_uninit(msg, total_size);
-    ovs_assert(NLA_ALIGN(total_size) <= UINT16_MAX);
+    ovs_assert(!nl_attr_oversized(size));
     nla->nla_len = total_size;
     nla->nla_type = type;
     return nla + 1;
@@ -489,7 +489,7 @@ nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
 bool
 nl_attr_oversized(size_t payload_size)
 {
-    return NL_ATTR_SIZE(payload_size) > UINT16_MAX;
+    return payload_size > UINT16_MAX - NLA_HDRLEN;
 }
 
 /* Attributes. */
diff --git a/lib/netlink.h b/lib/netlink.h
index f9234da..6068f5d 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -94,7 +94,14 @@ void nl_msg_push_string(struct ofpbuf *, uint16_t type, const char *value);
 struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg);
 
 /* Sizes of various attribute types, in bytes, including the attribute header
- * and padding. */
+ * and padding.
+ *
+ * A minimum-size attribute is 4 bytes long: 4 bytes of header, no bytes of
+ * payload, no padding.
+ *
+ * A maximum-size attribute is 65536 bytes long: 4 bytes of header, 65531 bytes
+ * of payload, 1 byte of padding.  (Thus, NL_ATTR_SIZE() of a maximum length
+ * attribute payload does not fit in 16 bits.) */
 #define NL_ATTR_SIZE(PAYLOAD_SIZE) (NLA_HDRLEN + NLA_ALIGN(PAYLOAD_SIZE))
 #define NL_A_U8_SIZE   NL_ATTR_SIZE(sizeof(uint8_t))
 #define NL_A_U16_SIZE  NL_ATTR_SIZE(sizeof(uint16_t))
-- 
2.1.3




More information about the dev mailing list