| From fd3344e474d0cae0d9d05ade4f800f800bc5f623 Mon Sep 17 00:00:00 2001 |
| From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Date: Thu, 20 Feb 2020 16:42:13 +0200 |
| Subject: [PATCH] net: netlink: cap max groups which will be considered in |
| netlink_bind() |
| |
| commit 3a20773beeeeadec41477a5ba872175b778ff752 upstream. |
| |
| Since nl_groups is a u32 we can't bind more groups via ->bind |
| (netlink_bind) call, but netlink has supported more groups via |
| setsockopt() for a long time and thus nlk->ngroups could be over 32. |
| Recently I added support for per-vlan notifications and increased the |
| groups to 33 for NETLINK_ROUTE which exposed an old bug in the |
| netlink_bind() code causing out-of-bounds access on archs where unsigned |
| long is 32 bits via test_bit() on a local variable. Fix this by capping the |
| maximum groups in netlink_bind() to BITS_PER_TYPE(u32), effectively |
| capping them at 32 which is the minimum of allocated groups and the |
| maximum groups which can be bound via netlink_bind(). |
| |
| CC: Christophe Leroy <christophe.leroy@c-s.fr> |
| CC: Richard Guy Briggs <rgb@redhat.com> |
| Fixes: 4f520900522f ("netlink: have netlink per-protocol bind function return an error code.") |
| Reported-by: Erhard F. <erhard_f@mailbox.org> |
| Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c |
| index e9ddfd782d16..bd056ec269f1 100644 |
| --- a/net/netlink/af_netlink.c |
| +++ b/net/netlink/af_netlink.c |
| @@ -1019,7 +1019,8 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
| if (nlk->netlink_bind && groups) { |
| int group; |
| |
| - for (group = 0; group < nlk->ngroups; group++) { |
| + /* nl_groups is a u32, so cap the maximum groups we can bind */ |
| + for (group = 0; group < BITS_PER_TYPE(u32); group++) { |
| if (!test_bit(group, &groups)) |
| continue; |
| err = nlk->netlink_bind(net, group + 1); |
| @@ -1038,7 +1039,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
| netlink_insert(sk, nladdr->nl_pid) : |
| netlink_autobind(sock); |
| if (err) { |
| - netlink_undo_bind(nlk->ngroups, groups, sk); |
| + netlink_undo_bind(BITS_PER_TYPE(u32), groups, sk); |
| goto unlock; |
| } |
| } |
| -- |
| 2.7.4 |
| |