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@redhat.com>
Reported-by: Jiri Benc <jbenc@redhat.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
- * 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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
{
size_t total_size = NLA_HDRLEN + size;
struct nlattr* nla = nl_msg_put_uninit(msg, total_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;
nla->nla_len = total_size;
nla->nla_type = type;
return nla + 1;
bool
nl_attr_oversized(size_t payload_size)
{
bool
nl_attr_oversized(size_t payload_size)
{
- return NL_ATTR_SIZE(payload_size) > UINT16_MAX;
+ return payload_size > UINT16_MAX - NLA_HDRLEN;
- * 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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg);
/* Sizes of various attribute types, in bytes, including the attribute header
struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg);
/* Sizes of various attribute types, in bytes, including the attribute header
+ * 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))
#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))