Commit af4be126 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[PKT_SCHED]: Add rtattr_strlcpy, use it where appropriate

Add rtattr_strlcpy to handle unterminated strings. The destination
is nulled out entirely to avoid possible leaks when dumping. The
return value can be checked for >= size to detect truncated strings.
Currently strings equal to the size of the destination are accepted
everywhere even if not null-terminated. Sometimes they are silently
truncated, sometimes the unterminated string is used.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 06fe37b4
......@@ -748,6 +748,7 @@ struct tcamsg
#include <linux/config.h>
extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
{
int len = strlen(str) + 1;
......
......@@ -152,14 +152,8 @@ extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
static inline int
tcf_change_indev(struct tcf_proto *tp, char *indev, struct rtattr *indev_tlv)
{
if (RTA_PAYLOAD(indev_tlv) >= IFNAMSIZ) {
printk("cls: bad indev name %s\n", (char *) RTA_DATA(indev_tlv));
if (rtattr_strlcpy(indev, indev_tlv, IFNAMSIZ) >= IFNAMSIZ)
return -EINVAL;
}
memset(indev, 0, IFNAMSIZ);
sprintf(indev, "%s", (char *) RTA_DATA(indev_tlv));
return 0;
}
......
......@@ -124,6 +124,21 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
memcpy(RTA_DATA(rta), data, attrlen);
}
size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
{
size_t ret = RTA_PAYLOAD(rta);
char *src = RTA_DATA(rta);
if (ret > 0 && src[ret - 1] == '\0')
ret--;
if (size > 0) {
size_t len = (ret >= size) ? size - 1 : ret;
memset(dest, 0, size);
memcpy(dest, src, len);
}
return ret;
}
int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
{
int err = 0;
......@@ -277,13 +292,9 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
else if (ida[IFLA_IFNAME - 1]) {
char ifname[IFNAMSIZ];
if (RTA_PAYLOAD(ida[IFLA_IFNAME - 1]) > RTA_ALIGN(sizeof(ifname)))
if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
IFNAMSIZ) >= IFNAMSIZ)
return -EINVAL;
memset(ifname, 0, sizeof(ifname));
memcpy(ifname, RTA_DATA(ida[IFLA_IFNAME - 1]),
RTA_PAYLOAD(ida[IFLA_IFNAME - 1]));
ifname[IFNAMSIZ - 1] = '\0';
dev = dev_get_by_name(ifname);
} else
return -EINVAL;
......@@ -381,16 +392,10 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
char ifname[IFNAMSIZ];
if (RTA_PAYLOAD(ida[IFLA_IFNAME - 1]) > RTA_ALIGN(sizeof(ifname)))
if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
IFNAMSIZ) >= IFNAMSIZ)
goto out;
memset(ifname, 0, sizeof(ifname));
memcpy(ifname, RTA_DATA(ida[IFLA_IFNAME - 1]),
RTA_PAYLOAD(ida[IFLA_IFNAME - 1]));
ifname[IFNAMSIZ - 1] = '\0';
err = dev_change_name(dev, ifname);
if (err)
goto out;
}
......@@ -695,6 +700,7 @@ void __init rtnetlink_init(void)
}
EXPORT_SYMBOL(__rta_fill);
EXPORT_SYMBOL(rtattr_strlcpy);
EXPORT_SYMBOL(rtattr_parse);
EXPORT_SYMBOL(rtnetlink_links);
EXPORT_SYMBOL(rtnetlink_put_metrics);
......
......@@ -705,7 +705,7 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_dev = dn_db;
if (rta[IFA_LABEL-1])
memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL-1], IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
......
......@@ -170,8 +170,7 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
new_r->r_table = table_id;
if (rta[RTA_IIF-1]) {
struct net_device *dev;
memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
new_r->r_ifname[IFNAMSIZ-1] = 0;
rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
new_r->r_ifindex = -1;
dev = dev_get_by_name(new_r->r_ifname);
if (dev) {
......
......@@ -456,7 +456,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
if (rta[IFA_LABEL - 1])
memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL - 1]), IFNAMSIZ);
rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
......
......@@ -209,8 +209,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
new_r->r_table = table_id;
if (rta[RTA_IIF-1]) {
struct net_device *dev;
memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
new_r->r_ifname[IFNAMSIZ-1] = 0;
rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
new_r->r_ifindex = -1;
dev = __dev_get_by_name(new_r->r_ifname);
if (dev)
......
......@@ -272,7 +272,7 @@ struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est,
{
struct tc_action *a;
struct tc_action_ops *a_o;
char act_name[4 + IFNAMSIZ + 1];
char act_name[IFNAMSIZ];
struct rtattr *tb[TCA_ACT_MAX+1];
struct rtattr *kind;
......@@ -284,12 +284,9 @@ struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est,
goto err_out;
kind = tb[TCA_ACT_KIND-1];
if (kind != NULL) {
sprintf(act_name, "%s", (char*)RTA_DATA(kind));
if (RTA_PAYLOAD(kind) >= IFNAMSIZ) {
printk("Action %s bad\n",
(char*)RTA_DATA(kind));
if (rtattr_strlcpy(act_name, kind,
IFNAMSIZ) >= IFNAMSIZ)
goto err_out;
}
} else {
printk("Action bad kind\n");
goto err_out;
......@@ -492,7 +489,7 @@ static int tcf_action_get_1(struct rtattr *rta, struct tc_action *a,
struct nlmsghdr *n, u32 pid)
{
struct tc_action_ops *a_o;
char act_name[4 + IFNAMSIZ + 1];
char act_name[IFNAMSIZ];
struct rtattr *tb[TCA_ACT_MAX+1];
struct rtattr *kind;
int index;
......@@ -502,12 +499,8 @@ static int tcf_action_get_1(struct rtattr *rta, struct tc_action *a,
goto err_out;
kind = tb[TCA_ACT_KIND-1];
if (kind != NULL) {
sprintf(act_name, "%s", (char*)RTA_DATA(kind));
if (RTA_PAYLOAD(kind) >= IFNAMSIZ) {
printk("tcf_action_get_1: action %s bad\n",
(char*)RTA_DATA(kind));
if (rtattr_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
goto err_out;
}
} else {
printk("tcf_action_get_1: action bad kind\n");
goto err_out;
......@@ -562,16 +555,12 @@ static void cleanup_a(struct tc_action *act)
static struct tc_action_ops *get_ao(struct rtattr *kind, struct tc_action *a)
{
char act_name[4 + IFNAMSIZ + 1];
char act_name[IFNAMSIZ];
struct tc_action_ops *a_o;
if (kind != NULL) {
sprintf(act_name, "%s", (char*)RTA_DATA(kind));
if (RTA_PAYLOAD(kind) >= IFNAMSIZ) {
printk("get_ao: action %s bad\n",
(char*)RTA_DATA(kind));
if (rtattr_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
return NULL;
}
} else {
printk("get_ao: action bad kind\n");
return NULL;
......
......@@ -215,9 +215,10 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
#ifdef CONFIG_KMOD
if (tp_ops==NULL && tca[TCA_KIND-1] != NULL) {
struct rtattr *kind = tca[TCA_KIND-1];
char name[IFNAMSIZ];
if (RTA_PAYLOAD(kind) <= IFNAMSIZ) {
request_module("cls_%s", (char*)RTA_DATA(kind));
if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
request_module("cls_%s", name);
tp_ops = tcf_proto_lookup_ops(kind);
}
}
......
......@@ -407,8 +407,9 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
ops = qdisc_lookup_ops(kind);
#ifdef CONFIG_KMOD
if (ops==NULL && tca[TCA_KIND-1] != NULL) {
if (RTA_PAYLOAD(kind) <= IFNAMSIZ) {
request_module("sch_%s", (char*)RTA_DATA(kind));
char name[IFNAMSIZ];
if (rtattr_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
request_module("sch_%s", name);
ops = qdisc_lookup_ops(kind);
}
}
......
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