[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CALx6S34Bj_YtRqqL5U0zJ9RKEu_Uvp9zYyNJLgvjEqX9jNrYqA@mail.gmail.com>
Date: Mon, 13 Jul 2015 08:31:05 -0700
From: Tom Herbert <tom@...bertland.com>
To: YOSHIFUJI Hideaki/吉藤英明
<hideaki.yoshifuji@...aclelinux.com>
Cc: "David S. Miller" <davem@...emloft.net>,
Linux Kernel Network Developers <netdev@...r.kernel.org>,
Erik Kline <ek@...gle.com>, thehajime@...il.com
Subject: Re: [PATCH] ipv6: Fix finding best source address in ipv6_dev_get_saddr().
I am testing this patch which may be a little simpler. Also idev needs
to be checked after __in6_dev_get
Tom
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4ab74d5..d631ac3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1363,9 +1363,10 @@ static void __ipv6_dev_get_saddr(struct net *net,
unsigned int prefs,
const struct in6_addr *saddr,
struct inet6_dev *idev,
- struct ipv6_saddr_score *scores)
+ struct ipv6_saddr_score **in_score,
+ struct ipv6_saddr_score **in_hiscore)
{
- struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
+ struct ipv6_saddr_score *score = *in_score, *hiscore = *in_hiscore;
read_lock_bh(&idev->lock);
list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
@@ -1434,13 +1435,16 @@ static void __ipv6_dev_get_saddr(struct net *net,
}
out:
read_unlock_bh(&idev->lock);
+ *in_hiscore = hiscore;
+ *in_score = score;
}
int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
const struct in6_addr *daddr, unsigned int prefs,
struct in6_addr *saddr)
{
- struct ipv6_saddr_score scores[2], *hiscore = &scores[1];
+ struct ipv6_saddr_score scores[2];
+ struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
struct ipv6_saddr_dst dst;
struct inet6_dev *idev;
struct net_device *dev;
@@ -1475,18 +1479,19 @@ int ipv6_dev_get_saddr(struct net *net, const
struct net_device *dst_dev,
if ((dst_type & IPV6_ADDR_MULTICAST) ||
dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) {
idev = __in6_dev_get(dst_dev);
- use_oif_addr = true;
+ if (idev)
+ use_oif_addr = true;
}
}
if (use_oif_addr) {
- __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
+ __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev,
&score, &hiscore);
} else {
for_each_netdev_rcu(net, dev) {
idev = __in6_dev_get(dev);
if (!idev)
continue;
- __ipv6_dev_get_saddr(net, &dst, prefs, saddr,
idev, scores);
+ __ipv6_dev_get_saddr(net, &dst, prefs, saddr,
idev, &score, &hiscore);
}
}
rcu_read_unlock();
On Mon, Jul 13, 2015 at 7:28 AM, YOSHIFUJI Hideaki/吉藤英明
<hideaki.yoshifuji@...aclelinux.com> wrote:
> Commit 9131f3de2 ("ipv6: Do not iterate over all interfaces when
> finding source address on specific interface.") did not properly
> update best source address available. Plus, it introduced
> possible NULL pointer dereference.
>
> Bug was reported by Erik Kline <ek@...gle.com>.
> Based on patch proposed by Hajime Tazaki <thehajime@...il.com>.
>
> Fixes: 9131f3de24db4dc12199aede7d931e6703e97f3b ("ipv6: Do not
> iterate over all interfaces when finding source address
> on specific interface.")
> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@...aclelinux.com>
> ---
> net/ipv6/addrconf.c | 30 ++++++++++++++++++------------
> 1 file changed, 18 insertions(+), 12 deletions(-)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 4ab74d5..4c9a024 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -1358,14 +1358,15 @@ out:
> return ret;
> }
>
> -static void __ipv6_dev_get_saddr(struct net *net,
> - struct ipv6_saddr_dst *dst,
> - unsigned int prefs,
> - const struct in6_addr *saddr,
> - struct inet6_dev *idev,
> - struct ipv6_saddr_score *scores)
> +static int __ipv6_dev_get_saddr(struct net *net,
> + struct ipv6_saddr_dst *dst,
> + unsigned int prefs,
> + const struct in6_addr *saddr,
> + struct inet6_dev *idev,
> + struct ipv6_saddr_score *scores,
> + int hiscore_idx)
> {
> - struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1];
> + struct ipv6_saddr_score *score = &scores[1 - hiscore_idx], *hiscore = &scores[hiscore_idx];
>
> read_lock_bh(&idev->lock);
> list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
> @@ -1424,6 +1425,7 @@ static void __ipv6_dev_get_saddr(struct net *net,
> in6_ifa_hold(score->ifa);
>
> swap(hiscore, score);
> + hiscore_idx = 1 - hiscore_idx;
>
> /* restore our iterator */
> score->ifa = hiscore->ifa;
> @@ -1434,18 +1436,20 @@ static void __ipv6_dev_get_saddr(struct net *net,
> }
> out:
> read_unlock_bh(&idev->lock);
> + return hiscore_idx;
> }
>
> int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
> const struct in6_addr *daddr, unsigned int prefs,
> struct in6_addr *saddr)
> {
> - struct ipv6_saddr_score scores[2], *hiscore = &scores[1];
> + struct ipv6_saddr_score scores[2], *hiscore;
> struct ipv6_saddr_dst dst;
> struct inet6_dev *idev;
> struct net_device *dev;
> int dst_type;
> bool use_oif_addr = false;
> + int hiscore_idx = 0;
>
> dst_type = __ipv6_addr_type(daddr);
> dst.addr = daddr;
> @@ -1454,8 +1458,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
> dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
> dst.prefs = prefs;
>
> - hiscore->rule = -1;
> - hiscore->ifa = NULL;
> + scores[hiscore_idx].rule = -1;
> + scores[hiscore_idx].ifa = NULL;
>
> rcu_read_lock();
>
> @@ -1480,17 +1484,19 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
> }
>
> if (use_oif_addr) {
> - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> + if (idev)
> + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx);
> } else {
> for_each_netdev_rcu(net, dev) {
> idev = __in6_dev_get(dev);
> if (!idev)
> continue;
> - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores);
> + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx);
> }
> }
> rcu_read_unlock();
>
> + hiscore = &scores[hiscore_idx];
> if (!hiscore->ifa)
> return -EADDRNOTAVAIL;
>
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists