Commit 998f1729 authored by Toke Høiland-Jørgensen's avatar Toke Høiland-Jørgensen Committed by Daniel Borkmann

xdp: Remove the xdp_attachment_flags_ok() callback

Since commit 7f0a8382 ("bpf, xdp: Maintain info on attached XDP BPF
programs in net_device"), the XDP program attachment info is now maintained
in the core code. This interacts badly with the xdp_attachment_flags_ok()
check that prevents unloading an XDP program with different load flags than
it was loaded with. In practice, two kinds of failures are seen:

- An XDP program loaded without specifying a mode (and which then ends up
  in driver mode) cannot be unloaded if the program mode is specified on
  unload.

- The dev_xdp_uninstall() hook always calls the driver callback with the
  mode set to the type of the program but an empty flags argument, which
  means the flags_ok() check prevents the program from being removed,
  leading to bpf prog reference leaks.

The original reason this check was added was to avoid ambiguity when
multiple programs were loaded. With the way the checks are done in the core
now, this is quite simple to enforce in the core code, so let's add a check
there and get rid of the xdp_attachment_flags_ok() callback entirely.

Fixes: 7f0a8382 ("bpf, xdp: Maintain info on attached XDP BPF programs in net_device")
Signed-off-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/bpf/160752225751.110217.10267659521308669050.stgit@toke.dk
parent b6252700
...@@ -3562,9 +3562,6 @@ static int nfp_net_xdp_setup_drv(struct nfp_net *nn, struct netdev_bpf *bpf) ...@@ -3562,9 +3562,6 @@ static int nfp_net_xdp_setup_drv(struct nfp_net *nn, struct netdev_bpf *bpf)
struct nfp_net_dp *dp; struct nfp_net_dp *dp;
int err; int err;
if (!xdp_attachment_flags_ok(&nn->xdp, bpf))
return -EBUSY;
if (!prog == !nn->dp.xdp_prog) { if (!prog == !nn->dp.xdp_prog) {
WRITE_ONCE(nn->dp.xdp_prog, prog); WRITE_ONCE(nn->dp.xdp_prog, prog);
xdp_attachment_setup(&nn->xdp, bpf); xdp_attachment_setup(&nn->xdp, bpf);
...@@ -3593,9 +3590,6 @@ static int nfp_net_xdp_setup_hw(struct nfp_net *nn, struct netdev_bpf *bpf) ...@@ -3593,9 +3590,6 @@ static int nfp_net_xdp_setup_hw(struct nfp_net *nn, struct netdev_bpf *bpf)
{ {
int err; int err;
if (!xdp_attachment_flags_ok(&nn->xdp_hw, bpf))
return -EBUSY;
err = nfp_app_xdp_offload(nn->app, nn, bpf->prog, bpf->extack); err = nfp_app_xdp_offload(nn->app, nn, bpf->prog, bpf->extack);
if (err) if (err)
return err; return err;
......
...@@ -1265,9 +1265,6 @@ static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf) ...@@ -1265,9 +1265,6 @@ static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf)
if (!priv->xdpi.prog && !prog) if (!priv->xdpi.prog && !prog)
return 0; return 0;
if (!xdp_attachment_flags_ok(&priv->xdpi, bpf))
return -EBUSY;
WRITE_ONCE(priv->xdp_prog, prog); WRITE_ONCE(priv->xdp_prog, prog);
xdp_attachment_setup(&priv->xdpi, bpf); xdp_attachment_setup(&priv->xdpi, bpf);
......
...@@ -190,9 +190,6 @@ nsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf, ...@@ -190,9 +190,6 @@ nsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf,
{ {
int err; int err;
if (!xdp_attachment_flags_ok(xdp, bpf))
return -EBUSY;
if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) { if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS"); NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS");
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -240,8 +240,6 @@ struct xdp_attachment_info { ...@@ -240,8 +240,6 @@ struct xdp_attachment_info {
}; };
struct netdev_bpf; struct netdev_bpf;
bool xdp_attachment_flags_ok(struct xdp_attachment_info *info,
struct netdev_bpf *bpf);
void xdp_attachment_setup(struct xdp_attachment_info *info, void xdp_attachment_setup(struct xdp_attachment_info *info,
struct netdev_bpf *bpf); struct netdev_bpf *bpf);
......
...@@ -8917,6 +8917,17 @@ static struct bpf_prog *dev_xdp_prog(struct net_device *dev, ...@@ -8917,6 +8917,17 @@ static struct bpf_prog *dev_xdp_prog(struct net_device *dev,
return dev->xdp_state[mode].prog; return dev->xdp_state[mode].prog;
} }
static u8 dev_xdp_prog_count(struct net_device *dev)
{
u8 count = 0;
int i;
for (i = 0; i < __MAX_XDP_MODE; i++)
if (dev->xdp_state[i].prog || dev->xdp_state[i].link)
count++;
return count;
}
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode) u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
{ {
struct bpf_prog *prog = dev_xdp_prog(dev, mode); struct bpf_prog *prog = dev_xdp_prog(dev, mode);
...@@ -9007,6 +9018,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack ...@@ -9007,6 +9018,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
struct bpf_xdp_link *link, struct bpf_prog *new_prog, struct bpf_xdp_link *link, struct bpf_prog *new_prog,
struct bpf_prog *old_prog, u32 flags) struct bpf_prog *old_prog, u32 flags)
{ {
unsigned int num_modes = hweight32(flags & XDP_FLAGS_MODES);
struct bpf_prog *cur_prog; struct bpf_prog *cur_prog;
enum bpf_xdp_mode mode; enum bpf_xdp_mode mode;
bpf_op_t bpf_op; bpf_op_t bpf_op;
...@@ -9022,11 +9034,17 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack ...@@ -9022,11 +9034,17 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
NL_SET_ERR_MSG(extack, "Invalid XDP flags for BPF link attachment"); NL_SET_ERR_MSG(extack, "Invalid XDP flags for BPF link attachment");
return -EINVAL; return -EINVAL;
} }
/* just one XDP mode bit should be set, zero defaults to SKB mode */ /* just one XDP mode bit should be set, zero defaults to drv/skb mode */
if (hweight32(flags & XDP_FLAGS_MODES) > 1) { if (num_modes > 1) {
NL_SET_ERR_MSG(extack, "Only one XDP mode flag can be set"); NL_SET_ERR_MSG(extack, "Only one XDP mode flag can be set");
return -EINVAL; return -EINVAL;
} }
/* avoid ambiguity if offload + drv/skb mode progs are both loaded */
if (!num_modes && dev_xdp_prog_count(dev) > 1) {
NL_SET_ERR_MSG(extack,
"More than one program loaded, unset mode is ambiguous");
return -EINVAL;
}
/* old_prog != NULL implies XDP_FLAGS_REPLACE is set */ /* old_prog != NULL implies XDP_FLAGS_REPLACE is set */
if (old_prog && !(flags & XDP_FLAGS_REPLACE)) { if (old_prog && !(flags & XDP_FLAGS_REPLACE)) {
NL_SET_ERR_MSG(extack, "XDP_FLAGS_REPLACE is not specified"); NL_SET_ERR_MSG(extack, "XDP_FLAGS_REPLACE is not specified");
......
...@@ -403,18 +403,6 @@ void __xdp_release_frame(void *data, struct xdp_mem_info *mem) ...@@ -403,18 +403,6 @@ void __xdp_release_frame(void *data, struct xdp_mem_info *mem)
} }
EXPORT_SYMBOL_GPL(__xdp_release_frame); EXPORT_SYMBOL_GPL(__xdp_release_frame);
bool xdp_attachment_flags_ok(struct xdp_attachment_info *info,
struct netdev_bpf *bpf)
{
if (info->prog && (bpf->flags ^ info->flags) & XDP_FLAGS_MODES) {
NL_SET_ERR_MSG(bpf->extack,
"program loaded with different flags");
return false;
}
return true;
}
EXPORT_SYMBOL_GPL(xdp_attachment_flags_ok);
void xdp_attachment_setup(struct xdp_attachment_info *info, void xdp_attachment_setup(struct xdp_attachment_info *info,
struct netdev_bpf *bpf) struct netdev_bpf *bpf)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment