Skip to content

Commit

Permalink
[NETLINK]: Don't BUG on undersized allocations
Browse files Browse the repository at this point in the history
Currently netlink users BUG when the allocated skb for an event
notification is undersized. While this is certainly a kernel bug,
its not critical and crashing the kernel is too drastic, especially
when considering that these errors have appeared multiple times in
the past and it BUGs even if no listeners are present.

This patch replaces BUG by WARN_ON and changes the notification
functions to inform potential listeners of undersized allocations
using a unique error code (EMSGSIZE).

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Feb 8, 2007
1 parent 2cf6c36 commit 2693256
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 85 deletions.
14 changes: 9 additions & 5 deletions net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por

nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

hdr = nlmsg_data(nlh);
hdr->ifi_family = AF_BRIDGE;
Expand All @@ -72,7 +72,8 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

/*
Expand All @@ -89,9 +90,12 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
goto errout;

err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
/* failure implies BUG in br_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in br_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
errout:
if (err < 0)
Expand Down
14 changes: 9 additions & 5 deletions net/core/fib_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,

nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags);
if (nlh == NULL)
return -1;
return -EMSGSIZE;

frh = nlmsg_data(nlh);
frh->table = rule->table;
Expand Down Expand Up @@ -359,7 +359,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
Expand Down Expand Up @@ -405,9 +406,12 @@ static void notify_rule_change(int event, struct fib_rule *rule,
goto errout;

err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops);
/* failure implies BUG in fib_rule_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in fib_rule_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
errout:
if (err < 0)
Expand Down
24 changes: 15 additions & 9 deletions net/core/neighbour.c
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,

nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ndtmsg = nlmsg_data(nlh);

Expand Down Expand Up @@ -1706,7 +1706,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,

nla_put_failure:
read_unlock_bh(&tbl->lock);
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static int neightbl_fill_param_info(struct sk_buff *skb,
Expand All @@ -1720,7 +1721,7 @@ static int neightbl_fill_param_info(struct sk_buff *skb,

nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ndtmsg = nlmsg_data(nlh);

Expand All @@ -1737,7 +1738,8 @@ static int neightbl_fill_param_info(struct sk_buff *skb,
return nlmsg_end(skb, nlh);
errout:
read_unlock_bh(&tbl->lock);
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
Expand Down Expand Up @@ -1955,7 +1957,7 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,

nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ndm = nlmsg_data(nlh);
ndm->ndm_family = neigh->ops->family;
Expand Down Expand Up @@ -1987,7 +1989,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}


Expand Down Expand Up @@ -2429,9 +2432,12 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
goto errout;

err = neigh_fill_info(skb, n, 0, 0, type, flags);
/* failure implies BUG in neigh_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
errout:
if (err < 0)
Expand Down
23 changes: 15 additions & 8 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,

nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ifm = nlmsg_data(nlh);
ifm->ifi_family = AF_UNSPEC;
Expand Down Expand Up @@ -384,7 +384,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
Expand Down Expand Up @@ -633,9 +634,12 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)

err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
/* failure impilies BUG in if_nlmsg_size or wireless_rtnetlink_get */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size */
WARN_ON(err == -EMSGSIZE);
kfree_skb(nskb);
goto errout;
}
err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
kfree(iw_buf);
Expand Down Expand Up @@ -678,9 +682,12 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
goto errout;

err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0);
/* failure implies BUG in if_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
errout:
if (err < 0)
Expand Down
14 changes: 9 additions & 5 deletions net/decnet/dn_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,

nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_DECnet;
Expand All @@ -768,7 +768,8 @@ static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
Expand All @@ -781,9 +782,12 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
goto errout;

err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
/* failure implies BUG in dn_ifaddr_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
errout:
if (err < 0)
Expand Down
11 changes: 7 additions & 4 deletions net/decnet/dn_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
nlmsg_failure:
rtattr_failure:
skb_trim(skb, b - skb->data);
return -1;
return -EMSGSIZE;
}


Expand All @@ -368,9 +368,12 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
f->fn_type, f->fn_scope, &f->fn_key, z,
DN_FIB_INFO(f), 0);
/* failure implies BUG in dn_fib_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
errout:
if (err < 0)
Expand Down
14 changes: 9 additions & 5 deletions net/ipv4/devinet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,

nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_INET;
Expand All @@ -1167,7 +1167,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
Expand Down Expand Up @@ -1225,9 +1226,12 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
goto errout;

err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
/* failure implies BUG in inet_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in inet_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
errout:
if (err < 0)
Expand Down
14 changes: 9 additions & 5 deletions net/ipv4/fib_semantics.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,12 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
err = fib_dump_info(skb, info->pid, seq, event, tb_id,
fa->fa_type, fa->fa_scope, key, dst_len,
fa->fa_tos, fa->fa_info, 0);
/* failure implies BUG in fib_nlmsg_size() */
BUG_ON(err < 0);

if (err < 0) {
/* -EMSGSIZE implies BUG in fib_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);
errout:
Expand Down Expand Up @@ -960,7 +963,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,

nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

rtm = nlmsg_data(nlh);
rtm->rtm_family = AF_INET;
Expand Down Expand Up @@ -1031,7 +1034,8 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

/*
Expand Down
17 changes: 10 additions & 7 deletions net/ipv4/inet_diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ static int inet_csk_diag_fill(struct sock *sk,
rtattr_failure:
nlmsg_failure:
skb_trim(skb, b - skb->data);
return -1;
return -EMSGSIZE;
}

static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
Expand Down Expand Up @@ -209,7 +209,7 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
return skb->len;
nlmsg_failure:
skb_trim(skb, previous_tail - skb->data);
return -1;
return -EMSGSIZE;
}

static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
Expand Down Expand Up @@ -274,11 +274,14 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
if (!rep)
goto out;

if (sk_diag_fill(sk, rep, req->idiag_ext,
NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, nlh) <= 0)
BUG();

err = sk_diag_fill(sk, rep, req->idiag_ext,
NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, nlh);
if (err < 0) {
WARN_ON(err == -EMSGSIZE);
kfree_skb(rep);
goto out;
}
err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
MSG_DONTWAIT);
if (err > 0)
Expand Down
5 changes: 3 additions & 2 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -2635,7 +2635,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,

nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
if (nlh == NULL)
return -ENOBUFS;
return -EMSGSIZE;

r = nlmsg_data(nlh);
r->rtm_family = AF_INET;
Expand Down Expand Up @@ -2718,7 +2718,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
return nlmsg_end(skb, nlh);

nla_put_failure:
return nlmsg_cancel(skb, nlh);
nlmsg_cancel(skb, nlh);
return -EMSGSIZE;
}

int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
Expand Down
Loading

0 comments on commit 2693256

Please sign in to comment.