]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - kernel/bpf/syscall.c
bpf: fix use after free in prog symbol exposure
[mirror_ubuntu-bionic-kernel.git] / kernel / bpf / syscall.c
index 2753f8866415883fda1c56e175c099aaa3452c46..cdc81ca6c6f0cb98c4f98bbbef483f32ef758921 100644 (file)
@@ -1236,20 +1236,26 @@ static int bpf_prog_load(union bpf_attr *attr)
        if (err)
                goto free_used_maps;
 
-       err = bpf_prog_new_fd(prog);
-       if (err < 0) {
-               /* failed to allocate fd.
-                * bpf_prog_put() is needed because the above
-                * bpf_prog_alloc_id() has published the prog
-                * to the userspace and the userspace may
-                * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
-                */
-               bpf_prog_put(prog);
-               return err;
-       }
-
+       /* Upon success of bpf_prog_alloc_id(), the BPF prog is
+        * effectively publicly exposed. However, retrieving via
+        * bpf_prog_get_fd_by_id() will take another reference,
+        * therefore it cannot be gone underneath us.
+        *
+        * Only for the time /after/ successful bpf_prog_new_fd()
+        * and before returning to userspace, we might just hold
+        * one reference and any parallel close on that fd could
+        * rip everything out. Hence, below notifications must
+        * happen before bpf_prog_new_fd().
+        *
+        * Also, any failure handling from this point onwards must
+        * be using bpf_prog_put() given the program is exposed.
+        */
        bpf_prog_kallsyms_add(prog);
        trace_bpf_prog_load(prog, err);
+
+       err = bpf_prog_new_fd(prog);
+       if (err < 0)
+               bpf_prog_put(prog);
        return err;
 
 free_used_maps: