The branch main has been updated by dchagin:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b17446281d21311cc4f9d522c5d18337a9f786bc

commit b17446281d21311cc4f9d522c5d18337a9f786bc
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2022-05-09 18:11:37 +0000
Commit:     Dmitry Chagin <[email protected]>
CommitDate: 2022-05-09 18:11:37 +0000

    linux(4): Fixed offset miscalculation in the preadv/pwritev syscalls.
    
    MFC after:              2 weeks
---
 sys/compat/linux/linux_file.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 8926e760fc39..199bed80d92a 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -1268,6 +1268,15 @@ linux_pwrite(struct thread *td, struct linux_pwrite_args 
*uap)
        return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset));
 }
 
+#define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2))
+
+static inline off_t
+pos_from_hilo(unsigned long high, unsigned long low)
+{
+
+       return (((off_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
+}
+
 int
 linux_preadv(struct thread *td, struct linux_preadv_args *uap)
 {
@@ -1280,8 +1289,7 @@ linux_preadv(struct thread *td, struct linux_preadv_args 
*uap)
         * pos_l and pos_h, respectively, contain the
         * low order and high order 32 bits of offset.
         */
-       offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
-           (sizeof(offset) * 4)) | uap->pos_l;
+       offset = pos_from_hilo(uap->pos_h, uap->pos_l);
        if (offset < 0)
                return (EINVAL);
 #ifdef COMPAT_LINUX32
@@ -1308,8 +1316,7 @@ linux_pwritev(struct thread *td, struct 
linux_pwritev_args *uap)
         * pos_l and pos_h, respectively, contain the
         * low order and high order 32 bits of offset.
         */
-       offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
-           (sizeof(offset) * 4)) | uap->pos_l;
+       offset = pos_from_hilo(uap->pos_h, uap->pos_l);
        if (offset < 0)
                return (EINVAL);
 #ifdef COMPAT_LINUX32

Reply via email to