diff mbox

[net] netpoll: linearize skb before accessing its data

Message ID 1382391080-1607-1-git-send-email-antonio@meshcoding.com
State Rejected, archived
Delegated to: David Miller
Headers show

Commit Message

Antonio Quartulli Oct. 21, 2013, 9:31 p.m. UTC
__netpoll_rx() assumes that the data buffer of the received
skb is linear and then passes it to rx_hook().
However this is not true because the skb has not been
linearized yet.

This can cause rx_hook() to access non allocated memory
while parsing the received data.

Fix __netpoll_rx() by explicitly linearising the skb.

Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
---

I checked linux-3.0 and this bug seems to be already there. Please consider
queueing it for stable.


Regards,



 net/core/netpoll.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

David Miller Oct. 21, 2013, 10:23 p.m. UTC | #1
From: Antonio Quartulli <antonio@meshcoding.com>
Date: Mon, 21 Oct 2013 23:31:20 +0200

> __netpoll_rx() assumes that the data buffer of the received
> skb is linear and then passes it to rx_hook().
> However this is not true because the skb has not been
> linearized yet.
> 
> This can cause rx_hook() to access non allocated memory
> while parsing the received data.
> 
> Fix __netpoll_rx() by explicitly linearising the skb.
> 
> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>

It is rx_hook's obligation to access the SKB properly and not
assume that the SKB is linear.  It is very expensive to
linearize every SKB just for the sake of improperly implemented
receive hooks.

In particular the rx hooks must make use of interface such
as pskb_may_pull(), just like every other protocol does
on packet input processing, to make sure the area they want
to access is in the linear area.
--
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
Eric Dumazet Oct. 21, 2013, 10:25 p.m. UTC | #2
On Mon, 2013-10-21 at 23:31 +0200, Antonio Quartulli wrote:
> __netpoll_rx() assumes that the data buffer of the received
> skb is linear and then passes it to rx_hook().
> However this is not true because the skb has not been
> linearized yet.
> 
> This can cause rx_hook() to access non allocated memory
> while parsing the received data.
> 
> Fix __netpoll_rx() by explicitly linearising the skb.
> 
> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
> ---
> 
> I checked linux-3.0 and this bug seems to be already there. Please consider
> queueing it for stable.
> 
> 
> Regards,
> 
> 
> 
>  net/core/netpoll.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> index fc75c9e..97cff18 100644
> --- a/net/core/netpoll.c
> +++ b/net/core/netpoll.c
> @@ -814,6 +814,9 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
>  		if (pskb_trim_rcsum(skb, len))
>  			goto out;
>  
> +		if (skb_linearize(skb))
> +			goto out;
> +
>  		iph = (struct iphdr *)skb->data;
>  		if (iph->protocol != IPPROTO_UDP)
>  			goto out;
> @@ -855,6 +858,8 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
>  			goto out;
>  		if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
>  			goto out;
> +		if (skb_linearize(skb))
> +			goto out;
>  		ip6h = ipv6_hdr(skb);
>  		if (!pskb_may_pull(skb, sizeof(struct udphdr)))
>  			goto out;

Well, if you linearize the skb, no need for pskb_may_pull(),
and it would be better to do it once at the beginning...


Anyway, how I see nothing sets rx_hook, what am I missing ?

# git grep -n rx_hook
include/linux/netpoll.h:27:     void (*rx_hook)(struct netpoll *, int, char *, int);
include/linux/netpoll.h:44:     struct list_head rx_np; /* netpolls that registered an rx_hook */
net/core/netpoll.c:639:                 /* If there are several rx_hooks for the same address,
net/core/netpoll.c:722:                 /* If there are several rx_hooks for the same address,
net/core/netpoll.c:837:                 np->rx_hook(np, ntohs(uh->source),
net/core/netpoll.c:875:                 np->rx_hook(np, ntohs(uh->source),
net/core/netpoll.c:1065:        if (np->rx_hook) {



--
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
David Miller Oct. 21, 2013, 10:33 p.m. UTC | #3
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 21 Oct 2013 15:25:36 -0700

> Anyway, how I see nothing sets rx_hook, what am I missing ?

Only out of tree code makes use of this facility, and it's been
this way since the facility was introduced.

Yes, I'm disappointed and unhappy about this too.
--
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
Antonio Quartulli Oct. 22, 2013, 6:06 a.m. UTC | #4
On Mon, Oct 21, 2013 at 06:23:19PM -0400, David Miller wrote:
> From: Antonio Quartulli <antonio@meshcoding.com>
> Date: Mon, 21 Oct 2013 23:31:20 +0200
> 
> > __netpoll_rx() assumes that the data buffer of the received
> > skb is linear and then passes it to rx_hook().
> > However this is not true because the skb has not been
> > linearized yet.
> > 
> > This can cause rx_hook() to access non allocated memory
> > while parsing the received data.
> > 
> > Fix __netpoll_rx() by explicitly linearising the skb.
> > 
> > Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
> 
> It is rx_hook's obligation to access the SKB properly and not
> assume that the SKB is linear.  It is very expensive to
> linearize every SKB just for the sake of improperly implemented
> receive hooks.
> 
> In particular the rx hooks must make use of interface such
> as pskb_may_pull(), just like every other protocol does
> on packet input processing, to make sure the area they want
> to access is in the linear area.
> 

But rx_hook() does not receive any skb:

609                 np->rx_hook(np, ntohs(uh->source),
610                                (char *)(uh+1),
611                                ulen - sizeof(struct udphdr));

it just receives a pointer to the data and can't do anything to make it linear.
(uh is a pointer to the udp header). Am I missing something?


Regards,
David Miller Oct. 22, 2013, 6:25 a.m. UTC | #5
From: Antonio Quartulli <antonio@meshcoding.com>
Date: Tue, 22 Oct 2013 08:06:35 +0200

> But rx_hook() does not receive any skb:
> 
> 609                 np->rx_hook(np, ntohs(uh->source),
> 610                                (char *)(uh+1),
> 611                                ulen - sizeof(struct udphdr));
> 
> it just receives a pointer to the data and can't do anything to make it linear.
> (uh is a pointer to the udp header). Am I missing something?

Then this hook's API needs to be fixed, it's completely broken.

Make it pass the SKB and the appropriate offset (from skb->data) in
bytes.
--
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
Antonio Quartulli Oct. 22, 2013, 6:37 a.m. UTC | #6
On Tue, Oct 22, 2013 at 02:25:25AM -0400, David Miller wrote:
> From: Antonio Quartulli <antonio@meshcoding.com>
> Date: Tue, 22 Oct 2013 08:06:35 +0200
> 
> > But rx_hook() does not receive any skb:
> > 
> > 609                 np->rx_hook(np, ntohs(uh->source),
> > 610                                (char *)(uh+1),
> > 611                                ulen - sizeof(struct udphdr));
> > 
> > it just receives a pointer to the data and can't do anything to make it linear.
> > (uh is a pointer to the udp header). Am I missing something?
> 
> Then this hook's API needs to be fixed, it's completely broken.
> 
> Make it pass the SKB and the appropriate offset (from skb->data) in
> bytes.
> 

Ok I will do that. But I think this API change must go into net-next, right?
Otherwise we would break every existing user.

What about resending this patch to net (after having removed the pskb_may_pull()
as pointed out by Eric) and then fixing the API in net-next?
David Miller Oct. 22, 2013, 6:50 a.m. UTC | #7
From: Antonio Quartulli <antonio@meshcoding.com>
Date: Tue, 22 Oct 2013 08:37:14 +0200

> Ok I will do that. But I think this API change must go into
> net-next, right?  Otherwise we would break every existing user.

Too bad, it's a necessary API change to fix the bug, the users
will need to change too.

It's not our problem if they are out-of-tree and can't be fixed
in-situ.
--
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
diff mbox

Patch

diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index fc75c9e..97cff18 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -814,6 +814,9 @@  int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 		if (pskb_trim_rcsum(skb, len))
 			goto out;
 
+		if (skb_linearize(skb))
+			goto out;
+
 		iph = (struct iphdr *)skb->data;
 		if (iph->protocol != IPPROTO_UDP)
 			goto out;
@@ -855,6 +858,8 @@  int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 			goto out;
 		if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
 			goto out;
+		if (skb_linearize(skb))
+			goto out;
 		ip6h = ipv6_hdr(skb);
 		if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 			goto out;