diff options
author | Tom Herbert <tom@herbertland.com> | 2016-11-01 22:55:25 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-02 20:26:02 +0100 |
commit | 1913540a1328d70edf8597f6c2248575d9d2ad62 (patch) | |
tree | 66dee3e9b86d122e3eb0fd40a86e885974b4004e /net/ipv6/ila | |
parent | net: ip, diag -- Adjust raw_abort to use unlocked __udp_disconnect (diff) | |
download | linux-1913540a1328d70edf8597f6c2248575d9d2ad62.tar.xz linux-1913540a1328d70edf8597f6c2248575d9d2ad62.zip |
ila: Fix crash caused by rhashtable changes
commit ca26893f05e86 ("rhashtable: Add rhlist interface")
added a field to rhashtable_iter so that length became 56 bytes
and would exceed the size of args in netlink_callback (which is
48 bytes). The netlink diag dump function already has been
allocating a iter structure and storing the pointed to that
in the args of netlink_callback. ila_xlat also uses
rhahstable_iter but is still putting that directly in
the arg block. Now since rhashtable_iter size is increased
we are overwriting beyond the structure. The next field
happens to be cb_mutex pointer in netlink_sock and hence the crash.
Fix is to alloc the rhashtable_iter and save it as pointer
in arg.
Tested:
modprobe ila
./ip ila add loc 3333:0:0:0 loc_match 2222:0:0:1,
./ip ila list # NO crash now
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ila')
-rw-r--r-- | net/ipv6/ila/ila_xlat.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c index 628ae6d85b59..af8f52ee7180 100644 --- a/net/ipv6/ila/ila_xlat.c +++ b/net/ipv6/ila/ila_xlat.c @@ -474,7 +474,15 @@ static int ila_nl_dump_start(struct netlink_callback *cb) { struct net *net = sock_net(cb->skb->sk); struct ila_net *ilan = net_generic(net, ila_net_id); - struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args; + struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0]; + + if (!iter) { + iter = kmalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + cb->args[0] = (long)iter; + } return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter, GFP_KERNEL); @@ -482,16 +490,18 @@ static int ila_nl_dump_start(struct netlink_callback *cb) static int ila_nl_dump_done(struct netlink_callback *cb) { - struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args; + struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0]; rhashtable_walk_exit(&iter->rhiter); + kfree(iter); + return 0; } static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args; + struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0]; struct rhashtable_iter *rhiter = &iter->rhiter; struct ila_map *ila; int ret; |