bpf: offload: free program id when device disappears
authorJakub Kicinski <jakub.kicinski@netronome.com>
Thu, 28 Dec 2017 02:39:07 +0000 (18:39 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Sun, 31 Dec 2017 15:12:23 +0000 (16:12 +0100)
Bound programs are quite useless after their device disappears.
They are simply waiting for reference count to go to zero,
don't list them in BPF_PROG_GET_NEXT_ID by freeing their ID
early.

Note that orphaned offload programs will return -ENODEV on
BPF_OBJ_GET_INFO_BY_FD so user will never see ID 0.

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>
include/linux/bpf.h
kernel/bpf/offload.c
kernel/bpf/syscall.c

index 669549f..9a916ab 100644 (file)
@@ -357,6 +357,8 @@ void bpf_prog_put(struct bpf_prog *prog);
 int __bpf_prog_charge(struct user_struct *user, u32 pages);
 void __bpf_prog_uncharge(struct user_struct *user, u32 pages);
 
+void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock);
+
 struct bpf_map *bpf_map_get_with_uref(u32 ufd);
 struct bpf_map *__bpf_map_get(struct fd f);
 struct bpf_map * __must_check bpf_map_inc(struct bpf_map *map, bool uref);
index 3126e1a..e4f1668 100644 (file)
@@ -130,6 +130,9 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
        if (offload->dev_state)
                WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));
 
+       /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
+       bpf_prog_free_id(prog, true);
+
        list_del_init(&offload->offloads);
        kfree(offload);
        prog->aux->offload = NULL;
index e0afc2e..e02dafa 100644 (file)
@@ -905,9 +905,13 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
        return id > 0 ? 0 : id;
 }
 
-static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
+void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
 {
-       /* cBPF to eBPF migrations are currently not in the idr store. */
+       /* cBPF to eBPF migrations are currently not in the idr store.
+        * Offloaded programs are removed from the store when their device
+        * disappears - even if someone grabs an fd to them they are unusable,
+        * simply waiting for refcnt to drop to be freed.
+        */
        if (!prog->aux->id)
                return;
 
@@ -917,6 +921,7 @@ static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
                __acquire(&prog_idr_lock);
 
        idr_remove(&prog_idr, prog->aux->id);
+       prog->aux->id = 0;
 
        if (do_idr_lock)
                spin_unlock_bh(&prog_idr_lock);