aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorStephen Hemminger <shemming@brocade.com>2015-05-27 12:26:14 -0700
committerStephen Hemminger <shemming@brocade.com>2015-05-27 13:00:21 -0700
commitc079e121a73af5eb49e003b13607e8a690331df6 (patch)
tree2815b765d9f112cb473218680559315603781525 /lib
parentbde5baa5476cd8d7d33afc42170dc984f3717e14 (diff)
downloadplatform_external_iproute2-c079e121a73af5eb49e003b13607e8a690331df6.tar.gz
platform_external_iproute2-c079e121a73af5eb49e003b13607e8a690331df6.tar.bz2
platform_external_iproute2-c079e121a73af5eb49e003b13607e8a690331df6.zip
libnetlink: add size argument to rtnl_talk
There have been several instances where response from kernel has overrun the stack buffer from the caller. Avoid future problems by passing a size argument. Also drop the unused peer and group arguments to rtnl_talk.
Diffstat (limited to 'lib')
-rw-r--r--lib/libgenl.c2
-rw-r--r--lib/libnetlink.c40
2 files changed, 23 insertions, 19 deletions
diff --git a/lib/libgenl.c b/lib/libgenl.c
index ef3e5db6..acb14783 100644
--- a/lib/libgenl.c
+++ b/lib/libgenl.c
@@ -53,7 +53,7 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family)
addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME,
family, strlen(family) + 1);
- if (rtnl_talk(grth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(grth, &req.n, &req.n, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n");
return -2;
}
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 77e07ef7..901236e6 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -25,6 +25,10 @@
#include "libnetlink.h"
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
int rcvbuf = 1024 * 1024;
void rtnl_close(struct rtnl_handle *rth)
@@ -300,8 +304,8 @@ int rtnl_dump_filter(struct rtnl_handle *rth,
return rtnl_dump_filter_l(rth, a);
}
-int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
- unsigned groups, struct nlmsghdr *answer)
+int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
+ struct nlmsghdr *answer, size_t len)
{
int status;
unsigned seq;
@@ -317,12 +321,10 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
.msg_iov = &iov,
.msg_iovlen = 1,
};
- char buf[16384];
+ char buf[32768];
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pid = peer;
- nladdr.nl_groups = groups;
n->nlmsg_seq = seq = ++rtnl->seq;
@@ -330,7 +332,6 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
n->nlmsg_flags |= NLM_F_ACK;
status = sendmsg(rtnl->fd, &msg, 0);
-
if (status < 0) {
perror("Cannot talk to rtnetlink");
return -1;
@@ -339,7 +340,6 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
memset(buf,0,sizeof(buf));
iov.iov_base = buf;
-
while (1) {
iov.iov_len = sizeof(buf);
status = recvmsg(rtnl->fd, &msg, 0);
@@ -372,7 +372,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
exit(1);
}
- if (nladdr.nl_pid != peer ||
+ if (nladdr.nl_pid != 0 ||
h->nlmsg_pid != rtnl->local.nl_pid ||
h->nlmsg_seq != seq) {
/* Don't forget to skip that message. */
@@ -385,20 +385,22 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
if (l < sizeof(struct nlmsgerr)) {
fprintf(stderr, "ERROR truncated\n");
- } else {
- if (!err->error) {
- if (answer)
- memcpy(answer, h, h->nlmsg_len);
- return 0;
- }
-
- fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error));
- errno = -err->error;
+ } else if (!err->error) {
+ if (answer)
+ memcpy(answer, h,
+ MIN(len, h->nlmsg_len));
+ return 0;
}
+
+ fprintf(stderr, "RTNETLINK answers: %s\n",
+ strerror(-err->error));
+ errno = -err->error;
return -1;
}
+
if (answer) {
- memcpy(answer, h, h->nlmsg_len);
+ memcpy(answer, h,
+ MIN(len, h->nlmsg_len));
return 0;
}
@@ -407,10 +409,12 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
}
+
if (msg.msg_flags & MSG_TRUNC) {
fprintf(stderr, "Message truncated\n");
continue;
}
+
if (status) {
fprintf(stderr, "!!!Remnant of size %d\n", status);
exit(1);