Commit 55ae7edb by Shuai Zhang Committed by Stéphane Graber

audit: added capacity and reserve() to nlmsg

There are now two (permitted) ways to add data to netlink message: 1. put_xxx() 2. call nlmsg_reserve() to get a pointer to newly reserved room within the original netlink message, then write or memcpy data to that area. Both of them guarantee adding requested length data do not overflow the pre-allocated message buffer by checking against its cap field first. And there may be no need to access nlmsg_len outside nl module, because both put_xxx() and nlmsg_reserve() have alread did that for us. Signed-off-by: 's avatarShuai Zhang <zs.broccoli@gmail.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent f38788b4
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
extern size_t nlmsg_len(const struct nlmsg *nlmsg) extern size_t nlmsg_len(const struct nlmsg *nlmsg)
{ {
return nlmsg->nlmsghdr.nlmsg_len - NLMSG_HDRLEN; return nlmsg->nlmsghdr->nlmsg_len - NLMSG_HDRLEN;
} }
extern void *nlmsg_data(struct nlmsg *nlmsg) extern void *nlmsg_data(struct nlmsg *nlmsg)
...@@ -53,13 +53,16 @@ static int nla_put(struct nlmsg *nlmsg, int attr, ...@@ -53,13 +53,16 @@ static int nla_put(struct nlmsg *nlmsg, int attr,
{ {
struct rtattr *rta; struct rtattr *rta;
size_t rtalen = RTA_LENGTH(len); size_t rtalen = RTA_LENGTH(len);
size_t tlen = NLMSG_ALIGN(nlmsg->nlmsghdr->nlmsg_len) + RTA_ALIGN(rtalen);
rta = NLMSG_TAIL(&nlmsg->nlmsghdr); if (tlen > nlmsg->cap)
rta->rta_type = attr; return -ENOMEM;
rta->rta_len = rtalen;
memcpy(RTA_DATA(rta), data, len); rta = NLMSG_TAIL(nlmsg->nlmsghdr);
nlmsg->nlmsghdr.nlmsg_len = rta->rta_type = attr;
NLMSG_ALIGN(nlmsg->nlmsghdr.nlmsg_len) + RTA_ALIGN(rtalen); rta->rta_len = rtalen;
memcpy(RTA_DATA(rta), data, len);
nlmsg->nlmsghdr->nlmsg_len = tlen;
return 0; return 0;
} }
...@@ -91,7 +94,7 @@ extern int nla_put_attr(struct nlmsg *nlmsg, int attr) ...@@ -91,7 +94,7 @@ extern int nla_put_attr(struct nlmsg *nlmsg, int attr)
struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr) struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
{ {
struct rtattr *rtattr = NLMSG_TAIL(&nlmsg->nlmsghdr); struct rtattr *rtattr = NLMSG_TAIL(nlmsg->nlmsghdr);
if (nla_put_attr(nlmsg, attr)) if (nla_put_attr(nlmsg, attr))
return NULL; return NULL;
...@@ -101,7 +104,7 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr) ...@@ -101,7 +104,7 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr) void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr)
{ {
attr->rta_len = (void *)NLMSG_TAIL(&nlmsg->nlmsghdr) - (void *)attr; attr->rta_len = (void *)NLMSG_TAIL(nlmsg->nlmsghdr) - (void *)attr;
} }
extern struct nlmsg *nlmsg_alloc(size_t size) extern struct nlmsg *nlmsg_alloc(size_t size)
...@@ -109,18 +112,48 @@ extern struct nlmsg *nlmsg_alloc(size_t size) ...@@ -109,18 +112,48 @@ extern struct nlmsg *nlmsg_alloc(size_t size)
struct nlmsg *nlmsg; struct nlmsg *nlmsg;
size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size); size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size);
nlmsg = (struct nlmsg *)malloc(len); nlmsg = (struct nlmsg *)malloc(sizeof(struct nlmsg));
if (!nlmsg) if (!nlmsg)
return NULL; return NULL;
memset(nlmsg, 0, len); nlmsg->nlmsghdr = (struct nlmsghdr *)malloc(len);
nlmsg->nlmsghdr.nlmsg_len = NLMSG_HDRLEN; if (!nlmsg->nlmsghdr)
goto errout;
memset(nlmsg->nlmsghdr, 0, len);
nlmsg->cap = len;
nlmsg->nlmsghdr->nlmsg_len = NLMSG_HDRLEN;
return nlmsg; return nlmsg;
errout:
free(nlmsg);
return NULL;
}
extern void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len)
{
void *buf;
size_t nlmsg_len = nlmsg->nlmsghdr->nlmsg_len;
size_t tlen = NLMSG_ALIGN(len);
if (nlmsg_len + tlen > nlmsg->cap)
return NULL;
buf = nlmsg->nlmsghdr + nlmsg_len;
nlmsg->nlmsghdr->nlmsg_len += tlen;
if (tlen > len)
memset(buf + len, 0, tlen - len);
return buf;
} }
extern void nlmsg_free(struct nlmsg *nlmsg) extern void nlmsg_free(struct nlmsg *nlmsg)
{ {
if (!nlmsg)
return;
free(nlmsg->nlmsghdr);
free(nlmsg); free(nlmsg);
} }
...@@ -130,7 +163,7 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) ...@@ -130,7 +163,7 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer)
struct sockaddr_nl nladdr; struct sockaddr_nl nladdr;
struct iovec iov = { struct iovec iov = {
.iov_base = answer, .iov_base = answer,
.iov_len = answer->nlmsghdr.nlmsg_len, .iov_len = answer->nlmsghdr->nlmsg_len,
}; };
struct msghdr msg = { struct msghdr msg = {
...@@ -157,7 +190,7 @@ again: ...@@ -157,7 +190,7 @@ again:
return 0; return 0;
if (msg.msg_flags & MSG_TRUNC && if (msg.msg_flags & MSG_TRUNC &&
ret == answer->nlmsghdr.nlmsg_len) ret == answer->nlmsghdr->nlmsg_len)
return -EMSGSIZE; return -EMSGSIZE;
return ret; return ret;
...@@ -168,7 +201,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) ...@@ -168,7 +201,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
struct sockaddr_nl nladdr; struct sockaddr_nl nladdr;
struct iovec iov = { struct iovec iov = {
.iov_base = (void*)nlmsg, .iov_base = (void*)nlmsg,
.iov_len = nlmsg->nlmsghdr.nlmsg_len, .iov_len = nlmsg->nlmsghdr->nlmsg_len,
}; };
struct msghdr msg = { struct msghdr msg = {
.msg_name = &nladdr, .msg_name = &nladdr,
...@@ -206,7 +239,7 @@ extern int netlink_transaction(struct nl_handler *handler, ...@@ -206,7 +239,7 @@ extern int netlink_transaction(struct nl_handler *handler,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) { if (answer->nlmsghdr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer); struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer);
return err->error; return err->error;
} }
......
...@@ -53,14 +53,16 @@ struct nl_handler { ...@@ -53,14 +53,16 @@ struct nl_handler {
}; };
/* /*
* struct nlmsg : the netlink message structure, it consists just * struct nlmsg : the netlink message structure. This message is to be used to
* on a definition for a nlmsghdr. This message is to be used to
* be allocated with netlink_alloc. * be allocated with netlink_alloc.
* @nlmsghdr : a pointer to a netlink message header, this field *
* _must_ be always the first field of this structure * @nlmsghdr: a pointer to a netlink message header
* @cap: capacity of the netlink message, this is the initially allocated size
* and later operations (e.g. reserve and put) can not exceed this limit.
*/ */
struct nlmsg { struct nlmsg {
struct nlmsghdr nlmsghdr; struct nlmsghdr *nlmsghdr;
ssize_t cap;
}; };
/* /*
...@@ -220,6 +222,16 @@ void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr); ...@@ -220,6 +222,16 @@ void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr);
struct nlmsg *nlmsg_alloc(size_t size); struct nlmsg *nlmsg_alloc(size_t size);
/* /*
* Reserve room for additional data at the tail of a netlink message
*
* @nlmsg: the netlink message
* @len: length of additional data to reserve room for
*
* Returns a pointer to newly reserved room or NULL
*/
void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len);
/*
* nlmsg_free : free a previously allocate message * nlmsg_free : free a previously allocate message
* *
* @nlmsg: the netlink message to be freed * @nlmsg: the netlink message to be freed
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment