diff options
author | Shan Wei <davidshan@tencent.com> | 2012-12-04 18:49:15 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-05 16:01:28 -0500 |
commit | ce46cc64d47a8afaf13c300b09a7f9c29f4979b6 (patch) | |
tree | 2fcaf39d15b41ee1f92f14eb8035f82eb80a5364 /net | |
parent | 1642182ea0eedecc5d6f330c43cef8639327f0e5 (diff) | |
download | linux-3.10-ce46cc64d47a8afaf13c300b09a7f9c29f4979b6.tar.gz linux-3.10-ce46cc64d47a8afaf13c300b09a7f9c29f4979b6.tar.bz2 linux-3.10-ce46cc64d47a8afaf13c300b09a7f9c29f4979b6.zip |
net: neighbour: prohibit negative value for unres_qlen_bytes parameter
unres_qlen_bytes and unres_qlen are int type.
But multiple relation(unres_qlen_bytes = unres_qlen * SKB_TRUESIZE(ETH_FRAME_LEN))
will cause type overflow when seting unres_qlen. e.g.
$ echo 1027506 > /proc/sys/net/ipv4/neigh/eth1/unres_qlen
$ cat /proc/sys/net/ipv4/neigh/eth1/unres_qlen
1182657265
$ cat /proc/sys/net/ipv4/neigh/eth1/unres_qlen_bytes
-2147479756
The gutted value is not that we setting。
But user/administrator don't know this is caused by int type overflow.
what's more, it is meaningless and even dangerous that unres_qlen_bytes is set
with negative number. Because, for unresolved neighbour address, kernel will cache packets
without limit in __neigh_event_send()(e.g. (u32)-1 = 2GB).
Signed-off-by: Shan Wei <davidshan@tencent.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/neighbour.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f1c0c2e9cad..36fc692e2bd 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -62,6 +62,9 @@ static void __neigh_notify(struct neighbour *n, int type, int flags); static void neigh_update_notify(struct neighbour *neigh); static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +static int zero; +static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN); + static struct neigh_table *neigh_tables; #ifdef CONFIG_PROC_FS static const struct file_operations neigh_stat_seq_fops; @@ -1787,8 +1790,7 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) || /* approximative value for deprecated QUEUE_LEN (in packets) */ nla_put_u32(skb, NDTPA_QUEUE_LEN, - DIV_ROUND_UP(parms->queue_len_bytes, - SKB_TRUESIZE(ETH_FRAME_LEN))) || + parms->queue_len_bytes / SKB_TRUESIZE(ETH_FRAME_LEN)) || nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) || nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) || nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) || @@ -2777,9 +2779,13 @@ static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer, int size, ret; ctl_table tmp = *ctl; + tmp.extra1 = &zero; + tmp.extra2 = &unres_qlen_max; tmp.data = &size; - size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN)); - ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); + + size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + if (write && !ret) *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN); return ret; @@ -2865,7 +2871,8 @@ static struct neigh_sysctl_table { .procname = "unres_qlen_bytes", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_PROXY_QLEN] = { .procname = "proxy_qlen", |