From: "YOSHIFUJI Hideaki/吉藤英明" <hideaki.yoshifuji@miraclelinux.com>
To: Tom Herbert <tom@herbertland.com>
Cc: hideaki.yoshifuji@miraclelinux.com,
"David S. Miller" <davem@davemloft.net>,
Linux Kernel Network Developers <netdev@vger.kernel.org>,
Erik Kline <ek@google.com>,
thehajime@gmail.com
Subject: Re: [PATCH] ipv6: Fix finding best source address in ipv6_dev_get_saddr().
Date: Tue, 14 Jul 2015 21:44:04 +0900 [thread overview]
Message-ID: <55A50414.6090407@miraclelinux.com> (raw)
In-Reply-To: <CALx6S34Bj_YtRqqL5U0zJ9RKEu_Uvp9zYyNJLgvjEqX9jNrYqA@mail.gmail.com>
Hi,
Tom Herbert wrote:
> I am testing this patch which may be a little simpler. Also idev needs
> to be checked after __in6_dev_get
We have to select source address on *given* interface for link-local/
multicast destinations.
>
> 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@miraclelinux.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@google.com>.
>> Based on patch proposed by Hajime Tazaki <thehajime@gmail.com>.
>>
>> Fixes: 9131f3de24db4dc12199aede7d931e6703e97f3b ("ipv6: Do not
>> iterate over all interfaces when finding source address
>> on specific interface.")
>> Signed-off-by: YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.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@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
ミラクル・リナックス株式会社 技術本部 サポート部
next prev parent reply other threads:[~2015-07-14 12:44 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-13 14:28 [PATCH] ipv6: Fix finding best source address in ipv6_dev_get_saddr() YOSHIFUJI Hideaki/吉藤英明
2015-07-13 15:23 ` Hajime Tazaki
2015-07-13 15:31 ` Tom Herbert
2015-07-14 12:44 ` YOSHIFUJI Hideaki/吉藤英明 [this message]
2015-07-14 15:22 ` Tom Herbert
2015-07-16 4:07 ` David Miller
2015-07-15 9:15 ` Erik Kline
2015-07-15 10:22 ` Erik Kline
2015-07-16 4:07 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55A50414.6090407@miraclelinux.com \
--to=hideaki.yoshifuji@miraclelinux.com \
--cc=davem@davemloft.net \
--cc=ek@google.com \
--cc=netdev@vger.kernel.org \
--cc=thehajime@gmail.com \
--cc=tom@herbertland.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).