Getting the following kernel panic in papr_hvpipe_dev_create_handle()
when trying to add src_info to the list.
 Kernel attempted to write user page (0) - exploit attempt? (uid: 0)
 BUG: Kernel NULL pointer dereference on write at 0x00000000
 Faulting instruction address: 0xc0000000001b44a0
 Oops: Kernel access of bad area, sig: 11 [#1]
 ...
 Call Trace:
 papr_hvpipe_dev_ioctl+0x1f4/0x48c (unreliable)
 sys_ioctl+0x528/0x1064
 system_call_exception+0x128/0x360
 system_call_vectored_common+0x15c/0x2ec

The error handling with FD_PREPARE's file cleanup and __free(kfree) auto
cleanup is getting too convoluted. This is mainly because we need to
ensure only 1 user get the srcID handle. To simplify this, we allocate
prepare the src_info in the beginning and add it to the global list
under a spinlock after checking that no duplicates exist.

This simplify the error handling where if the FD_ADD fails, we can
simply remove the src_info from the list.

Cc: Christian Brauner <[email protected]>
Fixes: 6d3789d347a7 ("papr-hvpipe: convert papr_hvpipe_dev_create_handle() to 
FD_PREPARE()")
Reported-by: Haren Myneni <[email protected]>
Signed-off-by: Ritesh Harjani (IBM) <[email protected]>
---
 arch/powerpc/platforms/pseries/papr-hvpipe.c | 50 +++++++++-----------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/papr-hvpipe.c 
b/arch/powerpc/platforms/pseries/papr-hvpipe.c
index 14ae480d060a..ef10f5a5a4fa 100644
--- a/arch/powerpc/platforms/pseries/papr-hvpipe.c
+++ b/arch/powerpc/platforms/pseries/papr-hvpipe.c
@@ -479,21 +479,8 @@ static const struct file_operations papr_hvpipe_handle_ops 
= {

 static int papr_hvpipe_dev_create_handle(u32 srcID)
 {
-       struct hvpipe_source_info *src_info __free(kfree) = NULL;
-
-       spin_lock(&hvpipe_src_list_lock);
-       /*
-        * Do not allow more than one process communicates with
-        * each source.
-        */
-       src_info = hvpipe_find_source(srcID);
-       if (src_info) {
-               spin_unlock(&hvpipe_src_list_lock);
-               pr_err("pid(%d) is already using the source(%d)\n",
-                               src_info->tsk->pid, srcID);
-               return -EALREADY;
-       }
-       spin_unlock(&hvpipe_src_list_lock);
+       struct hvpipe_source_info *src_info;
+       int fd;

        src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT);
        if (!src_info)
@@ -503,26 +490,33 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
        src_info->tsk = current;
        init_waitqueue_head(&src_info->recv_wqh);

-       FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
-                  anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
-                                     (void *)src_info, O_RDWR));
-       if (fdf.err)
-               return fdf.err;
-
-       retain_and_null_ptr(src_info);
-       spin_lock(&hvpipe_src_list_lock);
        /*
-        * If two processes are executing ioctl() for the same
-        * source ID concurrently, prevent the second process to
-        * acquire FD.
+        * Do not allow more than one process communicates with
+        * each source.
         */
-       if (hvpipe_find_source(srcID)) {
+       spin_lock(&hvpipe_src_list_lock);
+       if(hvpipe_find_source(srcID)) {
                spin_unlock(&hvpipe_src_list_lock);
+               pr_err("pid(%d) could not get the source(%d)\n",
+                               src_info->tsk->pid, srcID);
+               kfree(src_info);
                return -EALREADY;
        }
        list_add(&src_info->list, &hvpipe_src_list);
        spin_unlock(&hvpipe_src_list_lock);
-       return fd_publish(fdf);
+
+       fd = FD_ADD(O_RDONLY | O_CLOEXEC,
+                  anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
+                                     (void *)src_info, O_RDWR));
+       if (fd < 0) {
+               spin_lock(&hvpipe_src_list_lock);
+               list_del(&src_info->list);
+               spin_unlock(&hvpipe_src_list_lock);
+               kfree(src_info);
+               return fd;
+       }
+
+       return fd;
 }

 /*
--
2.39.5


Reply via email to