git: b17446281d21 - main - linux(4): Fixed offset miscalculation in the preadv/pwritev syscalls.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Mon, 09 May 2022 18:17:10 UTC
The branch main has been updated by dchagin:

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

commit b17446281d21311cc4f9d522c5d18337a9f786bc
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-09 18:11:37 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
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