]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pseries/papr-hvpipe: Fix the usage of copy_to_user()
authorRitesh Harjani (IBM) <ritesh.list@gmail.com>
Fri, 1 May 2026 04:11:44 +0000 (09:41 +0530)
committerMadhavan Srinivasan <maddy@linux.ibm.com>
Wed, 6 May 2026 02:00:24 +0000 (07:30 +0530)
copy_to_user() return bytes_not_copied to the user buffer. If there was
an error writing bytes into the user buffer, i.e. if copy_to_user
returns a non-zero value, then we should simply return -EFAULT from the
->read() call.

Otherwise, in the non-patched version, we may end up mixing
"bytes_not_copied + bytes_copied (HVPIPE_HDR_LEN)" as the return value
to the user in ->read() call

Also let's make sure we clear the hvpipe_status flag, if we have
consumed the hvpipe msg by making the rtas call. ret = -EFAULT means
copy_to_user has failed but that still means that the msg was read from
the hvpipe, hence for both cases, success & -EFAULT, we should clear the
HVPIPE_MSG_AVAILABLE flag in hvpipe_status.

Cc: stable@vger.kernel.org
Fixes: cebdb522fd3edd1 ("powerpc/pseries: Receive payload with ibm,receive-hvpipe-msg RTAS")
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/8fda3212a1ad48879c174e92f67472d9b9f1c3b7.1777606826.git.ritesh.list@gmail.com
arch/powerpc/platforms/pseries/papr-hvpipe.c

index 800649f309a573e8269ea8de76a3689737a07c42..c007560d2d8ce9b4f5212a24ee39a6e904678ab6 100644 (file)
@@ -206,10 +206,11 @@ static int hvpipe_rtas_recv_msg(char __user *buf, int size)
                                        bytes_written, size);
                                bytes_written = size;
                        }
-                       ret = copy_to_user(buf,
+                       if (copy_to_user(buf,
                                        rtas_work_area_raw_buf(work_area),
-                                       bytes_written);
-                       if (!ret)
+                                       bytes_written))
+                               ret = -EFAULT;
+                       else
                                ret = bytes_written;
                }
        } else {
@@ -328,7 +329,7 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
 
        struct hvpipe_source_info *src_info = file->private_data;
        struct papr_hvpipe_hdr hdr = {};
-       long ret;
+       ssize_t ret = 0;
 
        /*
         * Return -ENXIO during migration
@@ -376,7 +377,7 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
 
        ret = copy_to_user(buf, &hdr, HVPIPE_HDR_LEN);
        if (ret)
-               return ret;
+               return -EFAULT;
 
        /*
         * Message event has payload, so get the payload with
@@ -385,19 +386,23 @@ static ssize_t papr_hvpipe_handle_read(struct file *file,
        if (hdr.flags & HVPIPE_MSG_AVAILABLE) {
                ret = hvpipe_rtas_recv_msg(buf + HVPIPE_HDR_LEN,
                                size - HVPIPE_HDR_LEN);
-               if (ret > 0) {
+               /*
+                * Always clear MSG_AVAILABLE once the RTAS call has drained
+                * the message, regardless of whether copy_to_user succeeded.
+                */
+               if (ret >= 0 || ret == -EFAULT)
                        src_info->hvpipe_status &= ~HVPIPE_MSG_AVAILABLE;
-                       ret += HVPIPE_HDR_LEN;
-               }
        } else if (hdr.flags & HVPIPE_LOST_CONNECTION) {
                /*
                 * Hypervisor is closing the pipe for the specific
                 * source. So notify user space.
                 */
                src_info->hvpipe_status &= ~HVPIPE_LOST_CONNECTION;
-               ret = HVPIPE_HDR_LEN;
        }
 
+       if (ret >= 0)
+               ret += HVPIPE_HDR_LEN;
+
        return ret;
 }