* [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
@ 2017-09-06 15:26 Jesper Dangaard Brouer
2017-09-06 15:44 ` Andy Gospodarek
2017-09-06 16:24 ` Daniel Borkmann
0 siblings, 2 replies; 8+ messages in thread
From: Jesper Dangaard Brouer @ 2017-09-06 15:26 UTC (permalink / raw)
To: netdev, David S. Miller
Cc: John Fastabend, Andy Gospodarek, Jesper Dangaard Brouer
Using bpf_redirect_map is allowed for generic XDP programs, but the
appropriate map lookup was never performed in xdp_do_generic_redirect().
Instead the map-index is directly used as the ifindex. For the
xdp_redirect_map sample in SKB-mode '-S', this resulted in trying
sending on ifindex 0 which isn't valid, resulting in getting SKB
packets dropped. Thus, the reported performance numbers are wrong in
commit 24251c264798 ("samples/bpf: add option for native and skb mode
for redirect apps") for the 'xdp_redirect_map -S' case.
It might seem innocent this was lacking, but it can actually crash the
kernel. The potential crash is caused by not consuming redirect_info->map.
The bpf_redirect_map helper will set this_cpu_ptr(&redirect_info)->map
pointer, which will survive even after unloading the xdp bpf_prog and
deallocating the devmap data-structure. This leaves a dead map
pointer around. The kernel will crash when loading the xdp_redirect
sample (in native XDP mode) as it doesn't reset map (via bpf_redirect)
and returns XDP_REDIRECT, which will cause it to dereference the map
pointer.
Fixes: 6103aa96ec07 ("net: implement XDP_REDIRECT for xdp generic")
Fixes: 24251c264798 ("samples/bpf: add option for native and skb mode for redirect apps")
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---
net/core/filter.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/net/core/filter.c b/net/core/filter.c
index 5912c738a7b2..6a4745bf2c9f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
}
EXPORT_SYMBOL_GPL(xdp_do_redirect);
+static int xdp_do_generic_redirect_map(struct net_device *dev,
+ struct sk_buff *skb,
+ struct bpf_prog *xdp_prog)
+{
+ struct redirect_info *ri = this_cpu_ptr(&redirect_info);
+ struct bpf_map *map = ri->map;
+ u32 index = ri->ifindex;
+ struct net_device *fwd;
+ int err;
+
+ ri->ifindex = 0;
+ ri->map = NULL;
+
+ fwd = __dev_map_lookup_elem(map, index);
+ if (!fwd) {
+ err = -EINVAL;
+ goto err;
+ }
+ skb->dev = fwd;
+ _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
+ return 0;
+err:
+ _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
+ return err;
+}
+
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
struct bpf_prog *xdp_prog)
{
@@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
unsigned int len;
int err = 0;
+ if (ri->map)
+ return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
+
fwd = dev_get_by_index_rcu(dev_net(dev), index);
ri->ifindex = 0;
if (unlikely(!fwd)) {
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 15:26 [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP Jesper Dangaard Brouer
@ 2017-09-06 15:44 ` Andy Gospodarek
2017-09-06 16:01 ` Jesper Dangaard Brouer
2017-09-06 16:24 ` Daniel Borkmann
1 sibling, 1 reply; 8+ messages in thread
From: Andy Gospodarek @ 2017-09-06 15:44 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev@vger.kernel.org, David S. Miller, John Fastabend
On Wed, Sep 6, 2017 at 11:26 AM, Jesper Dangaard Brouer
<brouer@redhat.com> wrote:
> Using bpf_redirect_map is allowed for generic XDP programs, but the
> appropriate map lookup was never performed in xdp_do_generic_redirect().
>
> Instead the map-index is directly used as the ifindex. For the
> xdp_redirect_map sample in SKB-mode '-S', this resulted in trying
> sending on ifindex 0 which isn't valid, resulting in getting SKB
> packets dropped. Thus, the reported performance numbers are wrong in
> commit 24251c264798 ("samples/bpf: add option for native and skb mode
> for redirect apps") for the 'xdp_redirect_map -S' case.
>
> It might seem innocent this was lacking, but it can actually crash the
> kernel. The potential crash is caused by not consuming redirect_info->map.
> The bpf_redirect_map helper will set this_cpu_ptr(&redirect_info)->map
> pointer, which will survive even after unloading the xdp bpf_prog and
> deallocating the devmap data-structure. This leaves a dead map
> pointer around. The kernel will crash when loading the xdp_redirect
> sample (in native XDP mode) as it doesn't reset map (via bpf_redirect)
> and returns XDP_REDIRECT, which will cause it to dereference the map
> pointer.
Nice catch!
Since 'net-next' is closed and this is a bugfix it seems like this is
a good candidate for 'net' right?
>
> Fixes: 6103aa96ec07 ("net: implement XDP_REDIRECT for xdp generic")
> Fixes: 24251c264798 ("samples/bpf: add option for native and skb mode for redirect apps")
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: Andy Gospodarek <andy@greyhouse.net>
> ---
> net/core/filter.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 5912c738a7b2..6a4745bf2c9f 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
> }
> EXPORT_SYMBOL_GPL(xdp_do_redirect);
>
> +static int xdp_do_generic_redirect_map(struct net_device *dev,
> + struct sk_buff *skb,
> + struct bpf_prog *xdp_prog)
> +{
> + struct redirect_info *ri = this_cpu_ptr(&redirect_info);
> + struct bpf_map *map = ri->map;
> + u32 index = ri->ifindex;
> + struct net_device *fwd;
> + int err;
> +
> + ri->ifindex = 0;
> + ri->map = NULL;
> +
> + fwd = __dev_map_lookup_elem(map, index);
> + if (!fwd) {
> + err = -EINVAL;
> + goto err;
> + }
> + skb->dev = fwd;
> + _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
> + return 0;
> +err:
> + _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
> + return err;
> +}
> +
> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> struct bpf_prog *xdp_prog)
> {
> @@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> unsigned int len;
> int err = 0;
>
> + if (ri->map)
> + return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
> +
> fwd = dev_get_by_index_rcu(dev_net(dev), index);
> ri->ifindex = 0;
> if (unlikely(!fwd)) {
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 15:44 ` Andy Gospodarek
@ 2017-09-06 16:01 ` Jesper Dangaard Brouer
0 siblings, 0 replies; 8+ messages in thread
From: Jesper Dangaard Brouer @ 2017-09-06 16:01 UTC (permalink / raw)
To: Andy Gospodarek
Cc: netdev@vger.kernel.org, David S. Miller, John Fastabend, brouer
On Wed, 6 Sep 2017 11:44:18 -0400
Andy Gospodarek <andy@greyhouse.net> wrote:
> On Wed, Sep 6, 2017 at 11:26 AM, Jesper Dangaard Brouer
> <brouer@redhat.com> wrote:
> > Using bpf_redirect_map is allowed for generic XDP programs, but the
> > appropriate map lookup was never performed in xdp_do_generic_redirect().
> >
> > Instead the map-index is directly used as the ifindex. For the
> > xdp_redirect_map sample in SKB-mode '-S', this resulted in trying
> > sending on ifindex 0 which isn't valid, resulting in getting SKB
> > packets dropped. Thus, the reported performance numbers are wrong in
> > commit 24251c264798 ("samples/bpf: add option for native and skb mode
> > for redirect apps") for the 'xdp_redirect_map -S' case.
> >
> > It might seem innocent this was lacking, but it can actually crash the
> > kernel. The potential crash is caused by not consuming redirect_info->map.
> > The bpf_redirect_map helper will set this_cpu_ptr(&redirect_info)->map
> > pointer, which will survive even after unloading the xdp bpf_prog and
> > deallocating the devmap data-structure. This leaves a dead map
> > pointer around. The kernel will crash when loading the xdp_redirect
> > sample (in native XDP mode) as it doesn't reset map (via bpf_redirect)
> > and returns XDP_REDIRECT, which will cause it to dereference the map
> > pointer.
>
> Nice catch!
>
> Since 'net-next' is closed and this is a bugfix it seems like this is
> a good candidate for 'net' right?
Yes, I know 'net-next' is closed, but 'net' doesn't contain the
XDP_REDIRECT code yet... thus I had to base it on net-next ;-)
> >
> > Fixes: 6103aa96ec07 ("net: implement XDP_REDIRECT for xdp generic")
> > Fixes: 24251c264798 ("samples/bpf: add option for native and skb mode for redirect apps")
> > Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
>
> Acked-by: Andy Gospodarek <andy@greyhouse.net>
Thanks
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 15:26 [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP Jesper Dangaard Brouer
2017-09-06 15:44 ` Andy Gospodarek
@ 2017-09-06 16:24 ` Daniel Borkmann
2017-09-06 17:02 ` Daniel Borkmann
2017-09-06 18:18 ` Jesper Dangaard Brouer
1 sibling, 2 replies; 8+ messages in thread
From: Daniel Borkmann @ 2017-09-06 16:24 UTC (permalink / raw)
To: Jesper Dangaard Brouer, netdev, David S. Miller
Cc: John Fastabend, Andy Gospodarek
On 09/06/2017 05:26 PM, Jesper Dangaard Brouer wrote:
> Using bpf_redirect_map is allowed for generic XDP programs, but the
> appropriate map lookup was never performed in xdp_do_generic_redirect().
>
> Instead the map-index is directly used as the ifindex. For the
Good point, but ...
[...]
> net/core/filter.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 5912c738a7b2..6a4745bf2c9f 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
> }
> EXPORT_SYMBOL_GPL(xdp_do_redirect);
>
> +static int xdp_do_generic_redirect_map(struct net_device *dev,
> + struct sk_buff *skb,
> + struct bpf_prog *xdp_prog)
> +{
> + struct redirect_info *ri = this_cpu_ptr(&redirect_info);
> + struct bpf_map *map = ri->map;
> + u32 index = ri->ifindex;
> + struct net_device *fwd;
> + int err;
> +
> + ri->ifindex = 0;
> + ri->map = NULL;
> +
> + fwd = __dev_map_lookup_elem(map, index);
> + if (!fwd) {
> + err = -EINVAL;
> + goto err;
> + }
> + skb->dev = fwd;
> + _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
> + return 0;
> +err:
> + _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
> + return err;
> +}
> +
> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> struct bpf_prog *xdp_prog)
> {
> @@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> unsigned int len;
> int err = 0;
>
> + if (ri->map)
> + return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
This is not quite correct. Really, the only thing you want
to do here is more or less ...
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
struct bpf_prog *xdp_prog)
{
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
struct bpf_map *map = ri->map;
u32 index = ri->ifindex;
struct net_device *fwd;
unsigned int len;
int err = 0;
ri->ifindex = 0;
ri->map = NULL;
if (map)
fwd = __dev_map_lookup_elem(map, index);
else
fwd = dev_get_by_index_rcu(dev_net(dev), index);
if (unlikely(!fwd)) {
err = -EINVAL;
goto err;
}
[...]
... such that you have a common path to also do the IFF_UP
and MTU checks that are done here, but otherwise omitted in
your patch.
Otherwise it looks good, but note that it also doesn't really
resolve the issue you mention wrt stale map pointers by the
way. This would need a different way to clear out the pointers
from redirect_info, I'm thinking when we have devmap dismantle
time after RCU grace period we should check whether there are
still stale pointers from this map around and clear them under
disabled preemption, but need to brainstorm a bit more on that
first.
> fwd = dev_get_by_index_rcu(dev_net(dev), index);
> ri->ifindex = 0;
> if (unlikely(!fwd)) {
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 16:24 ` Daniel Borkmann
@ 2017-09-06 17:02 ` Daniel Borkmann
2017-09-06 18:18 ` Jesper Dangaard Brouer
1 sibling, 0 replies; 8+ messages in thread
From: Daniel Borkmann @ 2017-09-06 17:02 UTC (permalink / raw)
To: Jesper Dangaard Brouer, netdev, David S. Miller
Cc: John Fastabend, Andy Gospodarek
On 09/06/2017 06:24 PM, Daniel Borkmann wrote:
[...]
> Otherwise it looks good, but note that it also doesn't really
> resolve the issue you mention wrt stale map pointers by the
> way. This would need a different way to clear out the pointers
> from redirect_info, I'm thinking when we have devmap dismantle
> time after RCU grace period we should check whether there are
> still stale pointers from this map around and clear them under
> disabled preemption, but need to brainstorm a bit more on that
> first.
Scratch that approach, doesn't work. So thinking bit more on
this, what we could do here is the following: verifier knows
we called bpf_xdp_redirect_map() helper, so it could do a small
insn rewrite in the sense that it fills R4 with a pointer to
the bpf_prog. We have that at verification time anyway and R4
is allowed to be populated since we scratch it per convention.
Then, the helper would store the prog pointer in struct redirect_info.
Later in xdp_do_*_redirect() we check whether the redirect_info's
prog pointer is the same as passed xdp_prog pointer, and if
that's the case then all good, since the prog holds a ref on
the map anyway, if they are not equal in the unlikely case, it
means stale pointer, so we bail out right there. That would
work imo, will see to code it up and check it out.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 16:24 ` Daniel Borkmann
2017-09-06 17:02 ` Daniel Borkmann
@ 2017-09-06 18:18 ` Jesper Dangaard Brouer
2017-09-06 18:42 ` John Fastabend
1 sibling, 1 reply; 8+ messages in thread
From: Jesper Dangaard Brouer @ 2017-09-06 18:18 UTC (permalink / raw)
To: Daniel Borkmann
Cc: netdev, David S. Miller, John Fastabend, Andy Gospodarek, brouer
On Wed, 06 Sep 2017 18:24:07 +0200
Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 09/06/2017 05:26 PM, Jesper Dangaard Brouer wrote:
> > Using bpf_redirect_map is allowed for generic XDP programs, but the
> > appropriate map lookup was never performed in xdp_do_generic_redirect().
> >
> > Instead the map-index is directly used as the ifindex. For the
>
> Good point, but ...
>
> [...]
> > net/core/filter.c | 29 +++++++++++++++++++++++++++++
> > 1 file changed, 29 insertions(+)
> >
> > diff --git a/net/core/filter.c b/net/core/filter.c
> > index 5912c738a7b2..6a4745bf2c9f 100644
> > --- a/net/core/filter.c
> > +++ b/net/core/filter.c
> > @@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
> > }
> > EXPORT_SYMBOL_GPL(xdp_do_redirect);
> >
> > +static int xdp_do_generic_redirect_map(struct net_device *dev,
> > + struct sk_buff *skb,
> > + struct bpf_prog *xdp_prog)
> > +{
> > + struct redirect_info *ri = this_cpu_ptr(&redirect_info);
> > + struct bpf_map *map = ri->map;
> > + u32 index = ri->ifindex;
> > + struct net_device *fwd;
> > + int err;
> > +
> > + ri->ifindex = 0;
> > + ri->map = NULL;
> > +
> > + fwd = __dev_map_lookup_elem(map, index);
> > + if (!fwd) {
> > + err = -EINVAL;
> > + goto err;
> > + }
> > + skb->dev = fwd;
> > + _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
> > + return 0;
> > +err:
> > + _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
> > + return err;
> > +}
> > +
> > int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> > struct bpf_prog *xdp_prog)
> > {
> > @@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> > unsigned int len;
> > int err = 0;
> >
> > + if (ri->map)
> > + return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
>
> This is not quite correct. Really, the only thing you want
> to do here is more or less ...
>
> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
> struct bpf_prog *xdp_prog)
> {
> struct redirect_info *ri = this_cpu_ptr(&redirect_info);
> struct bpf_map *map = ri->map;
> u32 index = ri->ifindex;
> struct net_device *fwd;
> unsigned int len;
> int err = 0;
>
> ri->ifindex = 0;
> ri->map = NULL;
>
> if (map)
> fwd = __dev_map_lookup_elem(map, index);
> else
> fwd = dev_get_by_index_rcu(dev_net(dev), index);
> if (unlikely(!fwd)) {
> err = -EINVAL;
> goto err;
> }
> [...]
>
> ... such that you have a common path to also do the IFF_UP
> and MTU checks that are done here, but otherwise omitted in
> your patch.
Ah, yes. My patch miss the IFF_UP and MTU check. (I was too inspired by
xdp_do_redirect_map).
> Otherwise it looks good, but note that it also doesn't really
> resolve the issue you mention wrt stale map pointers by the
> way. [...]
I actually discovered more cases where we can crash the kernel :-(
E.g. driver not supporting XDP_REDIRECT, are still allowed to load an
XDP bpf_prog that call bpf_redirect_map() and set the ->map pointer,
but it will never call xdp_do_redirect() (which is responsible for
clearing/consuming ->map pointer).
Another case: You can also call bpf_redirect_map() and then NOT return
XDP_REDIRECT (it is obviously strange, but the bpf-helper API allows it).
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 18:18 ` Jesper Dangaard Brouer
@ 2017-09-06 18:42 ` John Fastabend
2017-09-06 18:51 ` Daniel Borkmann
0 siblings, 1 reply; 8+ messages in thread
From: John Fastabend @ 2017-09-06 18:42 UTC (permalink / raw)
To: Jesper Dangaard Brouer, Daniel Borkmann
Cc: netdev, David S. Miller, Andy Gospodarek
On 09/06/2017 11:18 AM, Jesper Dangaard Brouer wrote:
> On Wed, 06 Sep 2017 18:24:07 +0200
> Daniel Borkmann <daniel@iogearbox.net> wrote:
>
>> On 09/06/2017 05:26 PM, Jesper Dangaard Brouer wrote:
>>> Using bpf_redirect_map is allowed for generic XDP programs, but the
>>> appropriate map lookup was never performed in xdp_do_generic_redirect().
>>>
>>> Instead the map-index is directly used as the ifindex. For the
>>
>> Good point, but ...
>>
>> [...]
>>> net/core/filter.c | 29 +++++++++++++++++++++++++++++
>>> 1 file changed, 29 insertions(+)
>>>
>>> diff --git a/net/core/filter.c b/net/core/filter.c
>>> index 5912c738a7b2..6a4745bf2c9f 100644
>>> --- a/net/core/filter.c
>>> +++ b/net/core/filter.c
>>> @@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
>>> }
>>> EXPORT_SYMBOL_GPL(xdp_do_redirect);
>>>
>>> +static int xdp_do_generic_redirect_map(struct net_device *dev,
>>> + struct sk_buff *skb,
>>> + struct bpf_prog *xdp_prog)
>>> +{
>>> + struct redirect_info *ri = this_cpu_ptr(&redirect_info);
>>> + struct bpf_map *map = ri->map;
>>> + u32 index = ri->ifindex;
>>> + struct net_device *fwd;
>>> + int err;
>>> +
>>> + ri->ifindex = 0;
>>> + ri->map = NULL;
>>> +
>>> + fwd = __dev_map_lookup_elem(map, index);
>>> + if (!fwd) {
>>> + err = -EINVAL;
>>> + goto err;
>>> + }
>>> + skb->dev = fwd;
>>> + _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
>>> + return 0;
>>> +err:
>>> + _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
>>> + return err;
>>> +}
>>> +
>>> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>>> struct bpf_prog *xdp_prog)
>>> {
>>> @@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>>> unsigned int len;
>>> int err = 0;
>>>
>>> + if (ri->map)
>>> + return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
>>
>> This is not quite correct. Really, the only thing you want
>> to do here is more or less ...
>>
>> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>> struct bpf_prog *xdp_prog)
>> {
>> struct redirect_info *ri = this_cpu_ptr(&redirect_info);
>> struct bpf_map *map = ri->map;
>> u32 index = ri->ifindex;
>> struct net_device *fwd;
>> unsigned int len;
>> int err = 0;
>>
>> ri->ifindex = 0;
>> ri->map = NULL;
>>
>> if (map)
>> fwd = __dev_map_lookup_elem(map, index);
>> else
>> fwd = dev_get_by_index_rcu(dev_net(dev), index);
>> if (unlikely(!fwd)) {
>> err = -EINVAL;
>> goto err;
>> }
>> [...]
>>
>> ... such that you have a common path to also do the IFF_UP
>> and MTU checks that are done here, but otherwise omitted in
>> your patch.
>
> Ah, yes. My patch miss the IFF_UP and MTU check. (I was too inspired by
> xdp_do_redirect_map).
>
>
>> Otherwise it looks good, but note that it also doesn't really
>> resolve the issue you mention wrt stale map pointers by the
>> way. [...]
>
> I actually discovered more cases where we can crash the kernel :-(
>
> E.g. driver not supporting XDP_REDIRECT, are still allowed to load an
> XDP bpf_prog that call bpf_redirect_map() and set the ->map pointer,
> but it will never call xdp_do_redirect() (which is responsible for
> clearing/consuming ->map pointer).
>
> Another case: You can also call bpf_redirect_map() and then NOT return
> XDP_REDIRECT (it is obviously strange, but the bpf-helper API allows it).
>
I think we can cover both these cases with previous suggestion to check
prog pointers. Working up a patch now.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP
2017-09-06 18:42 ` John Fastabend
@ 2017-09-06 18:51 ` Daniel Borkmann
0 siblings, 0 replies; 8+ messages in thread
From: Daniel Borkmann @ 2017-09-06 18:51 UTC (permalink / raw)
To: John Fastabend, Jesper Dangaard Brouer
Cc: netdev, David S. Miller, Andy Gospodarek
On 09/06/2017 08:42 PM, John Fastabend wrote:
> On 09/06/2017 11:18 AM, Jesper Dangaard Brouer wrote:
>> On Wed, 06 Sep 2017 18:24:07 +0200
>> Daniel Borkmann <daniel@iogearbox.net> wrote:
>>> On 09/06/2017 05:26 PM, Jesper Dangaard Brouer wrote:
>>>> Using bpf_redirect_map is allowed for generic XDP programs, but the
>>>> appropriate map lookup was never performed in xdp_do_generic_redirect().
>>>>
>>>> Instead the map-index is directly used as the ifindex. For the
>>>
>>> Good point, but ...
>>>
>>> [...]
>>>> net/core/filter.c | 29 +++++++++++++++++++++++++++++
>>>> 1 file changed, 29 insertions(+)
>>>>
>>>> diff --git a/net/core/filter.c b/net/core/filter.c
>>>> index 5912c738a7b2..6a4745bf2c9f 100644
>>>> --- a/net/core/filter.c
>>>> +++ b/net/core/filter.c
>>>> @@ -2562,6 +2562,32 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
>>>> }
>>>> EXPORT_SYMBOL_GPL(xdp_do_redirect);
>>>>
>>>> +static int xdp_do_generic_redirect_map(struct net_device *dev,
>>>> + struct sk_buff *skb,
>>>> + struct bpf_prog *xdp_prog)
>>>> +{
>>>> + struct redirect_info *ri = this_cpu_ptr(&redirect_info);
>>>> + struct bpf_map *map = ri->map;
>>>> + u32 index = ri->ifindex;
>>>> + struct net_device *fwd;
>>>> + int err;
>>>> +
>>>> + ri->ifindex = 0;
>>>> + ri->map = NULL;
>>>> +
>>>> + fwd = __dev_map_lookup_elem(map, index);
>>>> + if (!fwd) {
>>>> + err = -EINVAL;
>>>> + goto err;
>>>> + }
>>>> + skb->dev = fwd;
>>>> + _trace_xdp_redirect_map(dev, xdp_prog, fwd, map, index);
>>>> + return 0;
>>>> +err:
>>>> + _trace_xdp_redirect_map_err(dev, xdp_prog, fwd, map, index, err);
>>>> + return err;
>>>> +}
>>>> +
>>>> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>>>> struct bpf_prog *xdp_prog)
>>>> {
>>>> @@ -2571,6 +2597,9 @@ int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>>>> unsigned int len;
>>>> int err = 0;
>>>>
>>>> + if (ri->map)
>>>> + return xdp_do_generic_redirect_map(dev, skb, xdp_prog);
>>>
>>> This is not quite correct. Really, the only thing you want
>>> to do here is more or less ...
>>>
>>> int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb,
>>> struct bpf_prog *xdp_prog)
>>> {
>>> struct redirect_info *ri = this_cpu_ptr(&redirect_info);
>>> struct bpf_map *map = ri->map;
>>> u32 index = ri->ifindex;
>>> struct net_device *fwd;
>>> unsigned int len;
>>> int err = 0;
>>>
>>> ri->ifindex = 0;
>>> ri->map = NULL;
>>>
>>> if (map)
>>> fwd = __dev_map_lookup_elem(map, index);
>>> else
>>> fwd = dev_get_by_index_rcu(dev_net(dev), index);
>>> if (unlikely(!fwd)) {
>>> err = -EINVAL;
>>> goto err;
>>> }
>>> [...]
>>>
>>> ... such that you have a common path to also do the IFF_UP
>>> and MTU checks that are done here, but otherwise omitted in
>>> your patch.
>>
>> Ah, yes. My patch miss the IFF_UP and MTU check. (I was too inspired by
>> xdp_do_redirect_map).
>>
>>> Otherwise it looks good, but note that it also doesn't really
>>> resolve the issue you mention wrt stale map pointers by the
>>> way. [...]
>>
>> I actually discovered more cases where we can crash the kernel :-(
>>
>> E.g. driver not supporting XDP_REDIRECT, are still allowed to load an
>> XDP bpf_prog that call bpf_redirect_map() and set the ->map pointer,
>> but it will never call xdp_do_redirect() (which is responsible for
>> clearing/consuming ->map pointer).
>>
>> Another case: You can also call bpf_redirect_map() and then NOT return
>> XDP_REDIRECT (it is obviously strange, but the bpf-helper API allows it).
>
> I think we can cover both these cases with previous suggestion to check
> prog pointers. Working up a patch now.
Yep, they would both be covered.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-09-06 18:51 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-06 15:26 [PATCH net-next] xdp: implement xdp_redirect_map for generic XDP Jesper Dangaard Brouer
2017-09-06 15:44 ` Andy Gospodarek
2017-09-06 16:01 ` Jesper Dangaard Brouer
2017-09-06 16:24 ` Daniel Borkmann
2017-09-06 17:02 ` Daniel Borkmann
2017-09-06 18:18 ` Jesper Dangaard Brouer
2017-09-06 18:42 ` John Fastabend
2017-09-06 18:51 ` Daniel Borkmann
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).