From: Hui Zhu <[email protected]>

When bpf_trampoline_update() fails before modify_fentry_multi()/
unregister_fentry_multi() is called, cur_image is unchanged
(cur_image == old_image) and ftrace still calls into it.  Freeing
old_image in that case causes a UAF.

Only free old_image when it differs from cur_image.

Fixes: aef4dfa790b2 ("bpf: Add bpf_trampoline_multi_attach/detach functions")
Signed-off-by: Hui Zhu <[email protected]>
---
 kernel/bpf/trampoline.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index ed7999ad6c66..ea4d3c62f289 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -1595,7 +1595,17 @@ static void bpf_trampoline_multi_attach_init(struct 
bpf_trampoline *tr)
 
 static void bpf_trampoline_multi_attach_free(struct bpf_trampoline *tr)
 {
-       if (tr->multi_attach.old_image)
+       /*
+        * Only free old_image if it is no longer the active image.
+        * When bpf_trampoline_update() fails before modify_fentry_multi()/
+        * unregister_fentry_multi() is called, cur_image is unchanged
+        * (cur_image == old_image) and ftrace still points to it. Freeing
+        * it would cause a UAF when ftrace calls into the freed memory.
+        * On success, cur_image is either a new image or NULL, so
+        * old_image != cur_image means the image is stale.
+        */
+       if (tr->multi_attach.old_image &&
+           tr->multi_attach.old_image != tr->cur_image)
                bpf_tramp_image_put(tr->multi_attach.old_image);
 
        tr->multi_attach.old_image = NULL;
-- 
2.53.0


Reply via email to