PROBLEM: null-ptr deref in ip_options_echo may lead to denial of service

Message ID 1489987500.16816.19.camel@edumazet-glaptop3.roam.corp.google.com
State Not Applicable
Delegated to: David Miller
Headers show

Commit Message

Eric Dumazet March 20, 2017, 5:25 a.m.
On Mon, 2017-03-20 at 12:59 +0800, Anarcheuz Fritz wrote:
> Hi David,
> 
> 
> While working on some legacy kernel I stumbled upon a null-ptr deref in
> ip_options_echo. The bug has been verified on the latest version
> 3.2.87 from the supported long-term branch.
> 

Fixed in commit 34b2cef20f19c87999fff3da4071e66937db9644
("ipv4: keep skb->dst around in presence of IP options")

For 3.2, since d826eb14ecef was not backported, following patch should
do it.

(Bug origin was f84af32cbca70 ("net: ip_queue_rcv_skb() helper"))

Comments

Ben Hutchings March 21, 2017, 12:33 a.m. | #1
On Sun, 2017-03-19 at 22:25 -0700, Eric Dumazet wrote:
> On Mon, 2017-03-20 at 12:59 +0800, Anarcheuz Fritz wrote:
> > Hi David,
> > 
> > 
> > While working on some legacy kernel I stumbled upon a null-ptr deref in
> > ip_options_echo. The bug has been verified on the latest version
> > 3.2.87 from the supported long-term branch.
> > 
> 
> Fixed in commit 34b2cef20f19c87999fff3da4071e66937db9644
> ("ipv4: keep skb->dst around in presence of IP options")
> 
> For 3.2, since d826eb14ecef was not backported, following patch should
> do it.
> 
> (Bug origin was f84af32cbca70 ("net: ip_queue_rcv_skb() helper"))

I see, I thought the vulnerability was introduced by d826eb14ecef.

> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index b3648bbef0da..a6e1eeb02267 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -1009,7 +1009,8 @@ e_inval:
>   */
>  int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  {
> -	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
> +	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) &&
> +	    !IPCB(skb)->opt.optlen)
>  		skb_dst_drop(skb);
>  	return sock_queue_rcv_skb(sk, skb);
>  }

Thanks to both of you; I'll queue this up for 3.2.

Ben.
Ben Hutchings March 21, 2017, 12:36 a.m. | #2
On Tue, 2017-03-21 at 00:33 +0000, Ben Hutchings wrote:
> On Sun, 2017-03-19 at 22:25 -0700, Eric Dumazet wrote:
> > On Mon, 2017-03-20 at 12:59 +0800, Anarcheuz Fritz wrote:
> > > Hi David,
> > > 
> > > 
> > > While working on some legacy kernel I stumbled upon a null-ptr deref in
> > > ip_options_echo. The bug has been verified on the latest version
> > > 3.2.87 from the supported long-term branch.
> > > 
> > 
> > Fixed in commit 34b2cef20f19c87999fff3da4071e66937db9644
> > ("ipv4: keep skb->dst around in presence of IP options")
> > 
> > For 3.2, since d826eb14ecef was not backported, following patch should
> > do it.
> > 
> > (Bug origin was f84af32cbca70 ("net: ip_queue_rcv_skb() helper"))
> 
> I see, I thought the vulnerability was introduced by d826eb14ecef.
> 
> > diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> > index b3648bbef0da..a6e1eeb02267 100644
> > --- a/net/ipv4/ip_sockglue.c
> > +++ b/net/ipv4/ip_sockglue.c
> > @@ -1009,7 +1009,8 @@ e_inval:
> >   */
> >  int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
> >  {
> > -	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
> > +	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) &&
> > +	    !IPCB(skb)->opt.optlen)
> >  		skb_dst_drop(skb);
> >  	return sock_queue_rcv_skb(sk, skb);
> >  }
> 
> Thanks to both of you; I'll queue this up for 3.2.

Actually, could I have a Signed-off-by for this, Eric?

Ben.
Eric Dumazet March 21, 2017, 4:24 a.m. | #3
On Tue, 2017-03-21 at 00:36 +0000, Ben Hutchings wrote:

> Actually, could I have a Signed-off-by for this, Eric?

Sure I sent a formal patch.

Thanks.

Patch

diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index b3648bbef0da..a6e1eeb02267 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1009,7 +1009,8 @@  e_inval:
  */
 int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
+	if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) &&
+	    !IPCB(skb)->opt.optlen)
 		skb_dst_drop(skb);
 	return sock_queue_rcv_skb(sk, skb);
 }