]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
Fix stale data pointers when constructing messages
authorThomas Graf <tgr@deb.localdomain>
Mon, 14 Jan 2008 15:17:56 +0000 (16:17 +0100)
committerThomas Graf <tgr@deb.localdomain>
Mon, 14 Jan 2008 15:17:56 +0000 (16:17 +0100)
Patrick McHardy reported a problem where pointers to the
payload of a netlink message as returned by f.e. the
nesting helpers become stale when the payload data
chunk is reallocated.

In order to avoid further problems, the payload chunk is
no longer extended on the fly. Instead the allocation is
made during netlink message object allocation time with
a default size of a page which should be fine for the
majority of all users. Additionally the functions
nlmsg_alloc_size() and nlmsg_set_default_size() have been
added to allocate messages of a particular length and to
modify the default message size.

include/netlink-types.h
include/netlink/msg.h
lib/attr.c
lib/msg.c
lib/nl.c

index f273da39af9b066ec2148103b4afeac3d34b56b5..f7c6437316b73655776fa251ce6d67521184a21a 100644 (file)
@@ -137,6 +137,7 @@ struct nl_msg
        struct sockaddr_nl      nm_dst;
        struct ucred            nm_creds;
        struct nlmsghdr *       nm_nlh;
+       size_t                  nm_size;
 };
 
 struct rtnl_link_map
index 263503af3d60b2ace0ce6677cf0fd93be125c6fd..5d0ecd2da9a37d9ff38ca234e10110f678888ca9 100644 (file)
@@ -74,7 +74,9 @@ extern int              nlmsg_validate(struct nlmsghdr *, int, int,
 #define nlmsg_build(ptr)               nlmsg_inherit(ptr)
 
 extern struct nl_msg *   nlmsg_alloc(void);
+extern struct nl_msg *   nlmsg_alloc_size(size_t);
 extern struct nl_msg *   nlmsg_alloc_simple(int, int);
+extern void              nlmsg_set_default_size(size_t);
 extern struct nl_msg *   nlmsg_inherit(struct nlmsghdr *);
 extern struct nl_msg *   nlmsg_convert(struct nlmsghdr *);
 extern void *            nlmsg_reserve(struct nl_msg *, size_t, int);
index aa77ca5d70cfbdb0549388476b578e582d800db2..8d9fdfac8f8f1ca5188342c64fa49a6c4a62c2f7 100644 (file)
@@ -481,9 +481,8 @@ struct nlattr *nla_reserve(struct nl_msg *n, int attrtype, int attrlen)
        
        tlen = NLMSG_ALIGN(n->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
 
-       n->nm_nlh = realloc(n->nm_nlh, tlen);
-       if (!n->nm_nlh) {
-               nl_errno(ENOMEM);
+       if ((tlen + n->nm_nlh->nlmsg_len) > n->nm_size) {
+               nl_errno(ENOBUFS);
                return NULL;
        }
 
index 3ae890911ab42678ea6ecf35c2ee8665e016e92b..80b689f29f00544b28d558fa153149fcf273e4de 100644 (file)
--- a/lib/msg.c
+++ b/lib/msg.c
 #include <netlink/attr.h>
 #include <linux/socket.h>
 
+static size_t default_msg_size;
+
+static void __init init_msg_size(void)
+{
+       default_msg_size = getpagesize();
+}
+
 /**
  * @name Size Calculations
  * @{
@@ -369,9 +376,10 @@ static struct nl_msg *__nlmsg_alloc(size_t len)
                goto errout;
 
        nm->nm_protocol = -1;
-       nm->nm_nlh->nlmsg_len = len;
+       nm->nm_size = len;
+       nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
 
-       NL_DBG(2, "msg %p: Allocated new message, nlmsg_len=%zu\n", nm, len);
+       NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
 
        return nm;
 errout:
@@ -381,25 +389,34 @@ errout:
 }
 
 /**
- * Allocate a new netlink message
+ * Allocate a new netlink message with the default maximum payload size.
  *
- * Allocates a new netlink message without any further payload.
+ * Allocates a new netlink message without any further payload. The
+ * maximum payload size defaults to PAGESIZE or as otherwise specified
+ * with nlmsg_set_default_size().
  *
  * @return Newly allocated netlink message or NULL.
  */
 struct nl_msg *nlmsg_alloc(void)
 {
-       return __nlmsg_alloc(nlmsg_total_size(0));
+       return __nlmsg_alloc(default_msg_size);
+}
+
+/**
+ * Allocate a new netlink message with maximum payload size specified.
+ */
+struct nl_msg *nlmsg_alloc_size(size_t max)
+{
+       return __nlmsg_alloc(max);
 }
 
 /**
  * Allocate a new netlink message and inherit netlink message header
  * @arg hdr            Netlink message header template
  *
- * Allocates a new netlink message with a tailroom for the netlink
- * message header. If \a hdr is not NULL it will be used as a
- * template for the netlink message header, otherwise the header
- * is left blank.
+ * Allocates a new netlink message and inherits the original message
+ * header. If \a hdr is not NULL it will be used as a template for
+ * the netlink message header, otherwise the header is left blank.
  * 
  * @return Newly allocated netlink message or NULL
  */ 
@@ -442,6 +459,18 @@ struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
        return msg;
 }
 
+/**
+ * Set the default maximum message payload size for allocated messages
+ * @arg max            Size of payload in bytes.
+ */
+void nlmsg_set_default_size(size_t max)
+{
+       if (max < nlmsg_total_size(0))
+               max = nlmsg_total_size(0);
+
+       default_msg_size = max;
+}
+
 /**
  * Convert a netlink message received from a netlink socket to a nl_msg
  * @arg hdr            Netlink message received from netlink socket.
@@ -477,35 +506,31 @@ errout:
  * existing netlink message. Eventual padding required will
  * be zeroed out.
  *
- * @note All existing pointers into the old data section may have
- *       become obsolete and illegal to reference after this call.
- *
  * @return Pointer to start of additional data tailroom or NULL.
  */
 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
 {
-       void *tmp;
+       void *buf = n->nm_nlh;
+       size_t nlmsg_len = n->nm_nlh->nlmsg_len;
        size_t tlen;
 
        tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
 
-       tmp = realloc(n->nm_nlh, n->nm_nlh->nlmsg_len + tlen);
-       if (!tmp) {
-               nl_errno(ENOMEM);
+       if ((tlen + nlmsg_len) > n->nm_size) {
+               nl_errno(ENOBUFS);
                return NULL;
        }
 
-       n->nm_nlh = tmp;
-       tmp += n->nm_nlh->nlmsg_len;
+       buf += nlmsg_len;
        n->nm_nlh->nlmsg_len += tlen;
 
        if (tlen > len)
-               memset(tmp + len, 0, tlen - len);
+               memset(buf + len, 0, tlen - len);
 
        NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
                  n, len, pad, n->nm_nlh->nlmsg_len);
 
-       return tmp;
+       return buf;
 }
 
 /**
@@ -518,9 +543,6 @@ void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
  * Extends the netlink message as needed and appends the data of given
  * length to the message. 
  *
- * @note All existing pointers into the old data section may have
- *       become obsolete and illegal to reference after this call.
- *
  * @return 0 on success or a negative error code
  */
 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
index fd69de7349d4e29b6d0b22963dc7c8ae3501ae95..b425302b5fbcd910135841cbdb109b81bfde9b62 100644 (file)
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -417,10 +417,15 @@ int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf,
        if (!msg)
                return nl_errno(ENOMEM);
 
-       if (buf && size)
-               nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
+       if (buf && size) {
+               err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
+               if (err < 0)
+                       goto errout;
+       }
+       
 
        err = nl_send_auto_complete(handle, msg);
+errout:
        nlmsg_free(msg);
 
        return err;