aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-05 02:03:53 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:45 -0400
commit5c7539781d392629fb40b04aad9a1f197b66cd01 (patch)
tree4c625e6191c7dd9fdb7d2479993c4b94ea322290
parentbf8b79e444a748963c71d2a58709e1ce5597e1b5 (diff)
[IPV4]: Convert address addition to new netlink api
Adds rtm_to_ifaddr() transforming a netlink message to a struct in_ifaddr. Fixes various unvalidated netlink attributes causing memory corruptions when left empty by userspace applications. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/devinet.c108
1 files changed, 75 insertions, 33 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 9f3ffbec3296..6b297c8697e6 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -62,6 +62,7 @@
62#include <net/ip.h> 62#include <net/ip.h>
63#include <net/route.h> 63#include <net/route.h>
64#include <net/ip_fib.h> 64#include <net/ip_fib.h>
65#include <net/netlink.h>
65 66
66struct ipv4_devconf ipv4_devconf = { 67struct ipv4_devconf ipv4_devconf = {
67 .accept_redirects = 1, 68 .accept_redirects = 1,
@@ -78,6 +79,14 @@ static struct ipv4_devconf ipv4_devconf_dflt = {
78 .accept_source_route = 1, 79 .accept_source_route = 1,
79}; 80};
80 81
82static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = {
83 [IFA_LOCAL] = { .type = NLA_U32 },
84 [IFA_ADDRESS] = { .type = NLA_U32 },
85 [IFA_BROADCAST] = { .type = NLA_U32 },
86 [IFA_ANYCAST] = { .type = NLA_U32 },
87 [IFA_LABEL] = { .type = NLA_STRING },
88};
89
81static void rtmsg_ifa(int event, struct in_ifaddr *); 90static void rtmsg_ifa(int event, struct in_ifaddr *);
82 91
83static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); 92static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
@@ -451,57 +460,90 @@ out:
451 return -EADDRNOTAVAIL; 460 return -EADDRNOTAVAIL;
452} 461}
453 462
454static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 463static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
455{ 464{
456 struct rtattr **rta = arg; 465 struct nlattr *tb[IFA_MAX+1];
466 struct in_ifaddr *ifa;
467 struct ifaddrmsg *ifm;
457 struct net_device *dev; 468 struct net_device *dev;
458 struct in_device *in_dev; 469 struct in_device *in_dev;
459 struct ifaddrmsg *ifm = NLMSG_DATA(nlh); 470 int err = -EINVAL;
460 struct in_ifaddr *ifa;
461 int rc = -EINVAL;
462 471
463 ASSERT_RTNL(); 472 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
473 if (err < 0)
474 goto errout;
464 475
465 if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1]) 476 ifm = nlmsg_data(nlh);
466 goto out; 477 if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
478 goto errout;
467 479
468 rc = -ENODEV; 480 dev = __dev_get_by_index(ifm->ifa_index);
469 if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) 481 if (dev == NULL) {
470 goto out; 482 err = -ENODEV;
483 goto errout;
484 }
471 485
472 rc = -ENOBUFS; 486 in_dev = __in_dev_get_rtnl(dev);
473 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) { 487 if (in_dev == NULL) {
474 in_dev = inetdev_init(dev); 488 in_dev = inetdev_init(dev);
475 if (!in_dev) 489 if (in_dev == NULL) {
476 goto out; 490 err = -ENOBUFS;
491 goto errout;
492 }
477 } 493 }
478 494
479 if ((ifa = inet_alloc_ifa()) == NULL) 495 ifa = inet_alloc_ifa();
480 goto out; 496 if (ifa == NULL) {
497 /*
498 * A potential indev allocation can be left alive, it stays
499 * assigned to its device and is destroy with it.
500 */
501 err = -ENOBUFS;
502 goto errout;
503 }
504
505 in_dev_hold(in_dev);
506
507 if (tb[IFA_ADDRESS] == NULL)
508 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
481 509
482 if (!rta[IFA_ADDRESS - 1])
483 rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
484 memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
485 memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
486 ifa->ifa_prefixlen = ifm->ifa_prefixlen; 510 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
487 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); 511 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
488 if (rta[IFA_BROADCAST - 1])
489 memcpy(&ifa->ifa_broadcast,
490 RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
491 if (rta[IFA_ANYCAST - 1])
492 memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
493 ifa->ifa_flags = ifm->ifa_flags; 512 ifa->ifa_flags = ifm->ifa_flags;
494 ifa->ifa_scope = ifm->ifa_scope; 513 ifa->ifa_scope = ifm->ifa_scope;
495 in_dev_hold(in_dev); 514 ifa->ifa_dev = in_dev;
496 ifa->ifa_dev = in_dev; 515
497 if (rta[IFA_LABEL - 1]) 516 ifa->ifa_local = nla_get_u32(tb[IFA_LOCAL]);
498 rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ); 517 ifa->ifa_address = nla_get_u32(tb[IFA_ADDRESS]);
518
519 if (tb[IFA_BROADCAST])
520 ifa->ifa_broadcast = nla_get_u32(tb[IFA_BROADCAST]);
521
522 if (tb[IFA_ANYCAST])
523 ifa->ifa_anycast = nla_get_u32(tb[IFA_ANYCAST]);
524
525 if (tb[IFA_LABEL])
526 nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
499 else 527 else
500 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 528 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
501 529
502 rc = inet_insert_ifa(ifa); 530 return ifa;
503out: 531
504 return rc; 532errout:
533 return ERR_PTR(err);
534}
535
536static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
537{
538 struct in_ifaddr *ifa;
539
540 ASSERT_RTNL();
541
542 ifa = rtm_to_ifaddr(nlh);
543 if (IS_ERR(ifa))
544 return PTR_ERR(ifa);
545
546 return inet_insert_ifa(ifa);
505} 547}
506 548
507/* 549/*