Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: offload: free prog->aux->offload when device disappears

All bpf offload operations should now be under bpf_devs_lock,
it's safe to free and clear the entire offload structure,
not only the netdev pointer.

__bpf_prog_offload_destroy() will no longer be called multiple
times.

Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

Jakub Kicinski and committed by
Daniel Borkmann
ce3b9db4 cae1927c

+9 -14
+9 -14
kernel/bpf/offload.c
··· 70 70 static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd, 71 71 struct netdev_bpf *data) 72 72 { 73 - struct net_device *netdev = prog->aux->offload->netdev; 73 + struct bpf_dev_offload *offload = prog->aux->offload; 74 + struct net_device *netdev; 74 75 75 76 ASSERT_RTNL(); 76 77 77 - if (!netdev) 78 + if (!offload) 78 79 return -ENODEV; 80 + netdev = offload->netdev; 79 81 if (!netdev->netdev_ops->ndo_bpf) 80 82 return -EOPNOTSUPP; 81 83 ··· 113 111 114 112 down_read(&bpf_devs_lock); 115 113 offload = env->prog->aux->offload; 116 - if (offload->netdev) 114 + if (offload) 117 115 ret = offload->dev_ops->insn_hook(env, insn_idx, prev_insn_idx); 118 116 up_read(&bpf_devs_lock); 119 117 ··· 125 123 struct bpf_dev_offload *offload = prog->aux->offload; 126 124 struct netdev_bpf data = {}; 127 125 128 - /* Caution - if netdev is destroyed before the program, this function 129 - * will be called twice. 130 - */ 131 - 132 126 data.offload.prog = prog; 133 127 134 128 if (offload->dev_state) 135 129 WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); 136 130 137 - offload->dev_state = false; 138 131 list_del_init(&offload->offloads); 139 - offload->netdev = NULL; 132 + kfree(offload); 133 + prog->aux->offload = NULL; 140 134 } 141 135 142 136 void bpf_prog_offload_destroy(struct bpf_prog *prog) 143 137 { 144 - struct bpf_dev_offload *offload = prog->aux->offload; 145 - 146 138 rtnl_lock(); 147 139 down_write(&bpf_devs_lock); 148 - __bpf_prog_offload_destroy(prog); 140 + if (prog->aux->offload) 141 + __bpf_prog_offload_destroy(prog); 149 142 up_write(&bpf_devs_lock); 150 143 rtnl_unlock(); 151 - 152 - kfree(offload); 153 144 } 154 145 155 146 static int bpf_prog_offload_translate(struct bpf_prog *prog)