From 59e3f63d49e544e62f6ff51786594dace8aa9175 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 11 Feb 2016 15:17:02 +0100
Subject: [PATCH] libnetlink: add size argument to rtnl_talk
This is a combination of 2 commits:
commit c079e121a73af5eb49e003b13607e8a690331df6
Author: Stephen Hemminger <shemming@brocade.com>
Date: Wed May 27 12:26:14 2015 -0700
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.
commit ed108cfc0260b6b751647982b77d6363b1defb15
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Thu Dec 3 17:13:48 2015 +0100
libnetlink: don't confuse variables in rtnl_talk()
There is two variables named 'len' in rtnl_talk. In fact, commit
c079e121a73a didn't work. For example, it was possible to trigger
a seg fault with this command:
$ ip link set gre2 type ip6gre hoplimit 32
Let's rename the argument len to maxlen.
Fixes: c079e121a73a ("libnetlink: add size argument to rtnl_talk")
Reported-by: Thomas Faivre <thomas.faivre@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
bridge/fdb.c | 2 +-
bridge/link.c | 2 +-
bridge/mdb.c | 2 +-
bridge/vlan.c | 2 +-
genl/ctrl.c | 4 ++--
include/libnetlink.h | 4 ++--
ip/ipaddress.c | 4 ++--
ip/ipaddrlabel.c | 4 ++--
ip/ipl2tp.c | 8 ++++----
ip/iplink.c | 4 ++--
ip/ipneigh.c | 2 +-
ip/ipnetns.c | 4 ++--
ip/ipntable.c | 2 +-
ip/iproute.c | 8 ++++----
ip/iprule.c | 4 ++--
ip/iptoken.c | 2 +-
ip/link_gre.c | 2 +-
ip/link_gre6.c | 2 +-
ip/link_ip6tnl.c | 2 +-
ip/link_iptnl.c | 2 +-
ip/link_vti.c | 2 +-
ip/link_vti6.c | 2 +-
ip/tcp_metrics.c | 4 ++--
ip/xfrm_policy.c | 14 +++++++-------
ip/xfrm_state.c | 12 ++++++------
lib/libgenl.c | 2 +-
lib/libnetlink.c | 40 ++++++++++++++++++++++------------------
tc/m_action.c | 6 +++---
tc/tc_class.c | 2 +-
tc/tc_filter.c | 2 +-
tc/tc_qdisc.c | 2 +-
31 files changed, 79 insertions(+), 75 deletions(-)
diff --git a/bridge/fdb.c b/bridge/fdb.c
index 615541e2cea2e..3c6c371c02552 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -326,7 +326,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
return -1;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/bridge/link.c b/bridge/link.c
index 38dfaea2e1808..19d06420aa818 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -364,7 +364,7 @@ static int brlink_modify(int argc, char **argv)
addattr_nest_end(&req.n, nest);
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/bridge/mdb.c b/bridge/mdb.c
index 81d479b9a3407..1cd03e011ded0 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -224,7 +224,7 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/bridge/vlan.c b/bridge/vlan.c
index 83c40880f0425..54e10d0d94b22 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -95,7 +95,7 @@ static int vlan_modify(int cmd, int argc, char **argv)
addattr_nest_end(&req.n, afspec);
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/genl/ctrl.c b/genl/ctrl.c
index 48cbc3562ad8d..25968839a91b5 100644
--- a/genl/ctrl.c
+++ b/genl/ctrl.c
@@ -67,7 +67,7 @@ int genl_ctrl_resolve_family(const char *family)
addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
- if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
+ if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n");
goto errout;
}
@@ -341,7 +341,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
goto ctrl_done;
}
- if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
+ if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
fprintf(stderr, "Error talking to the kernel\n");
goto ctrl_done;
}
diff --git a/include/libnetlink.h b/include/libnetlink.h
index ae933364761c1..95f41d979828f 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -54,8 +54,8 @@ extern int rtnl_dump_filter_l(struct rtnl_handle *rth,
const struct rtnl_dump_filter_arg *arg);
extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter,
void *arg);
-extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
- unsigned groups, struct nlmsghdr *answer);
+extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
+ struct nlmsghdr *answer, size_t len);
extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int);
extern int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int);
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 30fda4f8b30ec..94ff53898a915 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1036,7 +1036,7 @@ static int restore_handler(const struct sockaddr_nl *nl,
ll_init_map(&rth);
- ret = rtnl_talk(&rth, n, 0, 0, n);
+ ret = rtnl_talk(&rth, n, n, sizeof(*n));
if ((ret < 0) && (errno == EEXIST))
ret = 0;
@@ -1590,7 +1590,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
sizeof(cinfo));
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
index db4dc28df6d29..564bd4203ab3b 100644
--- a/ip/ipaddrlabel.c
+++ b/ip/ipaddrlabel.c
@@ -182,7 +182,7 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv)
if (req.ifal.ifal_family == AF_UNSPEC)
req.ifal.ifal_family = AF_INET6;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2;
return 0;
@@ -209,7 +209,7 @@ static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, vo
if (rtnl_open(&rth2, 0) < 0)
return -1;
- if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth2, n, NULL, 0) < 0)
return -2;
rtnl_close(&rth2);
diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c
index 5cd863224fda0..2f7c9bf1c737f 100644
--- a/ip/ipl2tp.c
+++ b/ip/ipl2tp.c
@@ -119,7 +119,7 @@ static int create_tunnel(struct l2tp_parm *p)
addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
}
- if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
@@ -132,7 +132,7 @@ static int delete_tunnel(struct l2tp_parm *p)
addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
- if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
@@ -166,7 +166,7 @@ static int create_session(struct l2tp_parm *p)
if (p->ifname && p->ifname[0])
addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
- if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
@@ -179,7 +179,7 @@ static int delete_session(struct l2tp_parm *p)
addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
- if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
diff --git a/ip/iplink.c b/ip/iplink.c
index 86ea23e6beaf7..052f0474bc1c1 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -605,7 +605,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
req.i.ifi_index = 0;
addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
}
@@ -680,7 +680,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
return -1;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/ip/ipneigh.c b/ip/ipneigh.c
index d76e035c449c9..39a8b4b236e37 100644
--- a/ip/ipneigh.c
+++ b/ip/ipneigh.c
@@ -174,7 +174,7 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
return -1;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 00b6cc488b3b5..2c848bc0f14b2 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -113,7 +113,7 @@ static int get_netnsid_from_name(const char *name)
return fd;
addattr32(&req.n, 1024, NETNSA_FD, fd);
- if (rtnl_talk(&rtnsh, &req.n, 0, 0, &answer.n) < 0) {
+ if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
close(fd);
return -2;
}
@@ -698,7 +698,7 @@ static int set_netnsid_from_name(const char *name, int nsid)
addattr32(&req.n, 1024, NETNSA_FD, fd);
addattr32(&req.n, 1024, NETNSA_NSID, nsid);
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
err = -2;
close(fd);
diff --git a/ip/ipntable.c b/ip/ipntable.c
index 4aeb71f7f4f89..b88c67b3fa9ab 100644
--- a/ip/ipntable.c
+++ b/ip/ipntable.c
@@ -313,7 +313,7 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv)
RTA_PAYLOAD(parms_rta));
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
diff --git a/ip/iproute.c b/ip/iproute.c
index 20980aba45bdc..4e63f3780237e 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -1029,7 +1029,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
return 0;
@@ -1486,7 +1486,7 @@ static int iproute_get(int argc, char **argv)
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
if (connected && !from_ok) {
@@ -1527,7 +1527,7 @@ static int iproute_get(int argc, char **argv)
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
}
@@ -1549,7 +1549,7 @@ static int restore_handler(const struct sockaddr_nl *nl,
ll_init_map(&rth);
- ret = rtnl_talk(&rth, n, 0, 0, n);
+ ret = rtnl_talk(&rth, n, n, sizeof(*n));
if ((ret < 0) && (errno == EEXIST))
ret = 0;
diff --git a/ip/iprule.c b/ip/iprule.c
index 167e753bde7b2..475ddc424e46d 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -355,7 +355,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
if (!table_ok && cmd == RTM_NEWRULE)
req.r.rtm_table = RT_TABLE_MAIN;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2;
return 0;
@@ -382,7 +382,7 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *a
if (rtnl_open(&rth2, 0) < 0)
return -1;
- if (rtnl_talk(&rth2, n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth2, n, NULL, 0) < 0)
return -2;
rtnl_close(&rth2);
diff --git a/ip/iptoken.c b/ip/iptoken.c
index 5689c2ece5816..0d265e6da8711 100644
--- a/ip/iptoken.c
+++ b/ip/iptoken.c
@@ -182,7 +182,7 @@ static int iptoken_set(int argc, char **argv)
return -1;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return -2;
return 0;
diff --git a/ip/link_gre.c b/ip/link_gre.c
index fda84d832f542..91ac299da1658 100644
--- a/ip/link_gre.c
+++ b/ip/link_gre.c
@@ -72,7 +72,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
index c7183e2fd4e75..d604f558df6ca 100644
--- a/ip/link_gre6.c
+++ b/ip/link_gre6.c
@@ -86,7 +86,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c
index f5b12454cf5f0..3efe2f4553203 100644
--- a/ip/link_ip6tnl.c
+++ b/ip/link_ip6tnl.c
@@ -84,7 +84,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
index 768c4efd4c26d..439c6e160b9ca 100644
--- a/ip/link_iptnl.c
+++ b/ip/link_iptnl.c
@@ -76,7 +76,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/link_vti.c b/ip/link_vti.c
index 6274c836cb944..0c0f5ba770d75 100644
--- a/ip/link_vti.c
+++ b/ip/link_vti.c
@@ -66,7 +66,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/link_vti6.c b/ip/link_vti6.c
index 282896df917a0..c146f791abaaa 100644
--- a/ip/link_vti6.c
+++ b/ip/link_vti6.c
@@ -67,7 +67,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
req.i.ifi_family = preferred_family;
req.i.ifi_index = ifi->ifi_index;
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
fprintf(stderr,
"Failed to get existing tunnel info.\n");
diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c
index c6be3c94415ff..8fa4b26a4965c 100644
--- a/ip/tcp_metrics.c
+++ b/ip/tcp_metrics.c
@@ -386,10 +386,10 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
}
if (ack) {
- if (rtnl_talk(&grth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&grth, &req.n, NULL, 0) < 0)
return -2;
} else if (atype >= 0) {
- if (rtnl_talk(&grth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0)
return -2;
if (process_msg(NULL, &req.n, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
index a0a9ce14036be..5ff581a2b868b 100644
--- a/ip/xfrm_policy.c
+++ b/ip/xfrm_policy.c
@@ -392,7 +392,7 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.xpinfo.sel.family == AF_UNSPEC)
req.xpinfo.sel.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
rtnl_close(&rth);
@@ -554,7 +554,7 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
}
static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
- void *res_nlbuf)
+ void *res_nlbuf, size_t res_size)
{
struct rtnl_handle rth;
struct {
@@ -669,7 +669,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
(void *)&ctx, ctx.sctx.len);
}
- if (rtnl_talk(&rth, &req.n, 0, 0, res_nlbuf) < 0)
+ if (rtnl_talk(&rth, &req.n, res_nlbuf, res_size) < 0)
exit(2);
rtnl_close(&rth);
@@ -679,7 +679,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete,
static int xfrm_policy_delete(int argc, char **argv)
{
- return xfrm_policy_get_or_delete(argc, argv, 1, NULL);
+ return xfrm_policy_get_or_delete(argc, argv, 1, NULL, 0);
}
static int xfrm_policy_get(int argc, char **argv)
@@ -689,7 +689,7 @@ static int xfrm_policy_get(int argc, char **argv)
memset(buf, 0, sizeof(buf));
- xfrm_policy_get_or_delete(argc, argv, 0, n);
+ xfrm_policy_get_or_delete(argc, argv, 0, n, sizeof(buf));
if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
@@ -974,7 +974,7 @@ static int xfrm_spd_getinfo(int argc, char **argv)
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
print_spdinfo(&req.n, (void*)stdout);
@@ -1026,7 +1026,7 @@ static int xfrm_policy_flush(int argc, char **argv)
if (show_stats > 1)
fprintf(stderr, "Flush policy\n");
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
rtnl_close(&rth);
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index dc6993ef26ca9..68884af14772e 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -647,7 +647,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
if (req.xsinfo.family == AF_UNSPEC)
req.xsinfo.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
rtnl_close(&rth);
@@ -784,7 +784,7 @@ static int xfrm_state_allocspi(int argc, char **argv)
req.xspi.info.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@@ -974,7 +974,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
req.xsid.family = AF_INET;
if (delete) {
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
} else {
char buf[NLMSG_BUF_SIZE];
@@ -982,7 +982,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
memset(buf, 0, sizeof(buf));
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@@ -1223,7 +1223,7 @@ static int xfrm_sad_getinfo(int argc, char **argv)
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
print_sadinfo(&req.n, (void*)stdout);
@@ -1277,7 +1277,7 @@ static int xfrm_state_flush(int argc, char **argv)
fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
strxf_xfrmproto(req.xsf.proto));
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
rtnl_close(&rth);
diff --git a/lib/libgenl.c b/lib/libgenl.c
index ef3e5db60c8cb..acb1478389476 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 0a989f46fa519..c455a41eccfdd 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -29,6 +29,10 @@
#define SOL_NETLINK 270
#endif
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
int rcvbuf = 1024 * 1024;
void rtnl_close(struct rtnl_handle *rth)
@@ -292,8 +296,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 maxlen)
{
int status;
unsigned seq;
@@ -309,12 +313,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;
@@ -322,7 +324,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;
@@ -331,7 +332,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);
@@ -364,7 +364,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. */
@@ -377,20 +377,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(maxlen, 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(maxlen, h->nlmsg_len));
return 0;
}
@@ -399,10 +401,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);
diff --git a/tc/m_action.c b/tc/m_action.c
index 4acabef056db1..7cbf37740c3ba 100644
--- a/tc/m_action.c
+++ b/tc/m_action.c
@@ -451,7 +451,7 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p)
if (cmd == RTM_GETACTION)
ans = &req.n;
- if (rtnl_talk(&rth, &req.n, 0, 0, ans) < 0) {
+ if (rtnl_talk(&rth, &req.n, ans, MAX_MSG) < 0) {
fprintf(stderr, "We have an error talking to the kernel\n");
return 1;
}
@@ -496,7 +496,7 @@ static int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p
}
tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) {
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
fprintf(stderr, "We have an error talking to the kernel\n");
ret = -1;
}
@@ -566,7 +566,7 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
req.n.nlmsg_type = RTM_DELACTION;
req.n.nlmsg_flags |= NLM_F_ROOT;
req.n.nlmsg_flags |= NLM_F_REQUEST;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) {
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
fprintf(stderr, "We have an error flushing\n");
return 1;
}
diff --git a/tc/tc_class.c b/tc/tc_class.c
index 6c0850d09f874..8f6908b85a956 100644
--- a/tc/tc_class.c
+++ b/tc/tc_class.c
@@ -138,7 +138,7 @@ static int tc_class_modify(int cmd, unsigned flags, int argc, char **argv)
}
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2;
return 0;
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index c3f2d5fa863e9..de1a73f470773 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -167,7 +167,7 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv)
}
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) {
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) {
fprintf(stderr, "We have an error talking to the kernel\n");
return 2;
}
diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
index e304858044cbb..984f1359a40e0 100644
--- a/tc/tc_qdisc.c
+++ b/tc/tc_qdisc.c
@@ -187,7 +187,7 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
req.t.tcm_ifindex = idx;
}
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
return 2;
return 0;
--
2.6.4