From f3c7ec6a2a19bffdfa5218f984bda53582ecb8dc Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 7 Jan 2015 13:19:41 -0800 Subject: [PATCH] netlink: Refine calculation of maximum-length attributes. 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 Reported-by: Jiri Benc Signed-off-by: Ben Pfaff Acked-by: Jesse Gross --- 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 c08a5574e..f092d5b1a 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; @@ -488,7 +488,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 f9234da1b..6068f5dfd 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.20.1