svn commit: r356945 - in head/sys: amd64/linux32 compat/linux i386/linux

Mark Johnston markj at FreeBSD.org
Tue Jan 21 17:28:24 UTC 2020


Author: markj
Date: Tue Jan 21 17:28:22 2020
New Revision: 356945
URL: https://svnweb.freebsd.org/changeset/base/356945

Log:
  Fix 64-bit syscall argument fetching in 32-bit Linux syscall handlers.
  
  The Linux32 system call argument fetcher places each argument (passed in
  registers in the Linux x86 system call convention) into an entry in the
  generic system call args array.  Each member of this array is 8 bytes
  wide, so this approach is broken for system calls that take off_t
  arguments.
  
  Fix the problem by splitting l_loff_t arguments in the 32-bit system
  call descriptions, the same as we do for FreeBSD32.  Change entry points
  to handle this using the PAIR32TO64 macro.
  
  Move linux_ftruncate64() into compat/linux.
  
  PR:		243155
  Reported by:	Alex S <iwtcex at gmail.com>
  Reviewed by:	kib (previous version)
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D23210

Modified:
  head/sys/amd64/linux32/linux32_machdep.c
  head/sys/amd64/linux32/syscalls.master
  head/sys/compat/linux/linux_file.c
  head/sys/i386/linux/linux_machdep.c

Modified: head/sys/amd64/linux32/linux32_machdep.c
==============================================================================
--- head/sys/amd64/linux32/linux32_machdep.c	Tue Jan 21 17:16:02 2020	(r356944)
+++ head/sys/amd64/linux32/linux32_machdep.c	Tue Jan 21 17:28:22 2020	(r356945)
@@ -593,13 +593,6 @@ linux_sigaltstack(struct thread *td, struct linux_siga
 }
 
 int
-linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
-{
-
-	return (kern_ftruncate(td, args->fd, args->length));
-}
-
-int
 linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap)
 {
 	struct timeval atv;

Modified: head/sys/amd64/linux32/syscalls.master
==============================================================================
--- head/sys/amd64/linux32/syscalls.master	Tue Jan 21 17:16:02 2020	(r356944)
+++ head/sys/amd64/linux32/syscalls.master	Tue Jan 21 17:28:22 2020	(r356945)
@@ -325,9 +325,9 @@
 				    l_sigset_t *newset, \
 				    l_size_t sigsetsize); }
 180	AUE_PREAD	STD	{ int linux_pread(l_uint fd, char *buf, \
-				    l_size_t nbyte, l_loff_t offset); }
+				    l_size_t nbyte, uint32_t offset1, uint32_t offset2); }
 181	AUE_PWRITE	STD	{ int linux_pwrite(l_uint fd, char *buf, \
-				    l_size_t nbyte, l_loff_t offset); }
+				    l_size_t nbyte, uint32_t offset1, uint32_t offset2); }
 182	AUE_CHOWN	STD	{ int linux_chown16(char *path, \
 				    l_uid16_t uid, l_gid16_t gid); }
 183	AUE_GETCWD	STD	{ int linux_getcwd(char *buf, \
@@ -349,9 +349,9 @@
 				    l_ulong prot, l_ulong flags, l_ulong fd, \
 				    l_ulong pgoff); }
 193	AUE_TRUNCATE	STD	{ int linux_truncate64(char *path, \
-				    l_loff_t length); }
+				    uint32_t length1, uint32_t length2); }
 194	AUE_FTRUNCATE	STD	{ int linux_ftruncate64(l_uint fd, \
-				    l_loff_t length); }
+				    uint32_t length1, uint32_t length2); }
 195	AUE_STAT	STD	{ int linux_stat64(const char *filename, \
 				    struct l_stat64 *statbuf); }
 196	AUE_LSTAT	STD	{ int linux_lstat64(const char *filename, \
@@ -426,7 +426,7 @@
 247	AUE_NULL	UNIMPL	linux_io_getevents
 248	AUE_NULL	UNIMPL	linux_io_submit
 249	AUE_NULL	UNIMPL	linux_io_cancel
-250	AUE_NULL	STD	{ int linux_fadvise64(int fd, l_loff_t offset, \
+250	AUE_NULL	STD	{ int linux_fadvise64(int fd, uint32_t offset1, uint32_t offset2, \
 					l_size_t len, int advice); }
 251	AUE_NULL	UNIMPL
 252	AUE_EXIT	STD	{ int linux_exit_group(int error_code); }
@@ -456,7 +456,8 @@
 271	AUE_UTIMES	STD	{ int linux_utimes(char *fname, \
 					struct l_timeval *tptr); }
 272	AUE_NULL	STD	{ int linux_fadvise64_64(int fd, \
-					l_loff_t offset, l_loff_t len, \
+					uint32_t offset1, uint32_t offset2, \
+					uint32_t len1, uint32_t len2, \
 					int advice); }
 273	AUE_NULL	UNIMPL	vserver
 274	AUE_NULL	STD	{ int linux_mbind(void); }
@@ -524,8 +525,9 @@
 312	AUE_NULL	STD	{ int linux_get_robust_list(l_int pid, \
 				    struct linux_robust_list_head **head, l_size_t *len); }
 313	AUE_NULL	STD	{ int linux_splice(void); }
-314	AUE_NULL	STD	{ int linux_sync_file_range(l_int fd, l_loff_t offset,
-				    l_loff_t nbytes, unsigned int flags); }
+314	AUE_NULL	STD	{ int linux_sync_file_range(l_int fd, uint32_t offset1,
+				    uint32_t offset2, uint32_t nbytes1, uint32_t nbytes2,
+				    unsigned int flags); }
 315	AUE_NULL	STD	{ int linux_tee(void); }
 316	AUE_NULL	STD	{ int linux_vmsplice(void); }
 ; Linux 2.6.18:
@@ -544,7 +546,8 @@
 323	AUE_NULL	STD	{ int linux_eventfd(l_uint initval); }
 ; Linux 2.6.23:
 324	AUE_NULL	STD	{ int linux_fallocate(l_int fd, l_int mode, \
-				    l_loff_t offset, l_loff_t len); }
+				    uint32_t offset1, uint32_t offset2, uint32_t len1,
+				    uint32_t len2); }
 ; Linux 2.6.25:
 325	AUE_NULL	STD	{ int linux_timerfd_settime(l_int fd, l_int flags,	\
 				    const struct l_itimerspec *new_value,		\

Modified: head/sys/compat/linux/linux_file.c
==============================================================================
--- head/sys/compat/linux/linux_file.c	Tue Jan 21 17:16:02 2020	(r356944)
+++ head/sys/compat/linux/linux_file.c	Tue Jan 21 17:28:22 2020	(r356945)
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vnode.h>
 
 #ifdef COMPAT_LINUX32
+#include <compat/freebsd32/freebsd32_misc.h>
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
 #else
@@ -67,7 +68,6 @@ __FBSDID("$FreeBSD$");
 static int	linux_common_open(struct thread *, int, char *, int, int);
 static int	linux_getdents_error(struct thread *, int, int);
 
-
 #ifdef LINUX_LEGACY_SYSCALLS
 int
 linux_creat(struct thread *td, struct linux_creat_args *args)
@@ -820,7 +820,6 @@ linux_truncate(struct thread *td, struct linux_truncat
 	int error;
 
 	LCONVPATHEXIST(td, args->path, &path);
-
 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
 	LFREEPATH(path);
 	return (error);
@@ -831,11 +830,17 @@ int
 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
 {
 	char *path;
+	off_t length;
 	int error;
 
-	LCONVPATHEXIST(td, args->path, &path);
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	length = PAIR32TO64(off_t, args->length);
+#else
+	length = args->length;
+#endif
 
-	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
+	LCONVPATHEXIST(td, args->path, &path);
+	error = kern_truncate(td, path, UIO_SYSSPACE, length);
 	LFREEPATH(path);
 	return (error);
 }
@@ -848,6 +853,22 @@ linux_ftruncate(struct thread *td, struct linux_ftrunc
 	return (kern_ftruncate(td, args->fd, args->length));
 }
 
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
+{
+	off_t length;
+
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	length = PAIR32TO64(off_t, args->length);
+#else
+	length = args->length;
+#endif
+
+	return (kern_ftruncate(td, args->fd, length));
+}
+#endif
+
 #ifdef LINUX_LEGACY_SYSCALLS
 int
 linux_link(struct thread *td, struct linux_link_args *args)
@@ -908,8 +929,17 @@ linux_fdatasync(struct thread *td, struct linux_fdatas
 int
 linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap)
 {
+	off_t nbytes, offset;
 
-	if (uap->offset < 0 || uap->nbytes < 0 ||
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	nbytes = PAIR32TO64(off_t, uap->nbytes);
+	offset = PAIR32TO64(off_t, uap->offset);
+#else
+	nbytes = uap->nbytes;
+	offset = uap->offset;
+#endif
+
+	if (offset < 0 || nbytes < 0 ||
 	    (uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE |
 	    LINUX_SYNC_FILE_RANGE_WRITE |
 	    LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) {
@@ -923,18 +953,23 @@ int
 linux_pread(struct thread *td, struct linux_pread_args *uap)
 {
 	struct vnode *vp;
+	off_t offset;
 	int error;
 
-	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	offset = PAIR32TO64(off_t, uap->offset);
+#else
+	offset = uap->offset;
+#endif
+
+	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset);
 	if (error == 0) {
 		/* This seems to violate POSIX but Linux does it. */
 		error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
 		if (error != 0)
 			return (error);
-		if (vp->v_type == VDIR) {
-			vrele(vp);
-			return (EISDIR);
-		}
+		if (vp->v_type == VDIR)
+			error = EISDIR;
 		vrele(vp);
 	}
 	return (error);
@@ -943,8 +978,15 @@ linux_pread(struct thread *td, struct linux_pread_args
 int
 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
 {
+	off_t offset;
 
-	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	offset = PAIR32TO64(off_t, uap->offset);
+#else
+	offset = uap->offset;
+#endif
+
+	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset));
 }
 
 int
@@ -1466,26 +1508,40 @@ convert_fadvice(int advice)
 int
 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
 {
+	off_t offset;
 	int advice;
 
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	offset = PAIR32TO64(off_t, args->offset);
+#else
+	offset = args->offset;
+#endif
+
 	advice = convert_fadvice(args->advice);
 	if (advice == -1)
 		return (EINVAL);
-	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
-	    advice));
+	return (kern_posix_fadvise(td, args->fd, offset, args->len, advice));
 }
 
 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 int
 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
 {
+	off_t len, offset;
 	int advice;
 
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	len = PAIR32TO64(off_t, args->len);
+	offset = PAIR32TO64(off_t, args->offset);
+#else
+	len = args->len;
+	offset = args->offset;
+#endif
+
 	advice = convert_fadvice(args->advice);
 	if (advice == -1)
 		return (EINVAL);
-	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
-	    advice));
+	return (kern_posix_fadvise(td, args->fd, offset, len, advice));
 }
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
@@ -1559,6 +1615,7 @@ linux_dup3(struct thread *td, struct linux_dup3_args *
 int
 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
 {
+	off_t len, offset;
 
 	/*
 	 * We emulate only posix_fallocate system call for which
@@ -1567,8 +1624,15 @@ linux_fallocate(struct thread *td, struct linux_falloc
 	if (args->mode != 0)
 		return (ENOSYS);
 
-	return (kern_posix_fallocate(td, args->fd, args->offset,
-	    args->len));
+#if defined(__amd64__) && defined(COMPAT_LINUX32)
+	len = PAIR32TO64(off_t, args->len);
+	offset = PAIR32TO64(off_t, args->offset);
+#else
+	len = args->len;
+	offset = args->offset;
+#endif
+
+	return (kern_posix_fallocate(td, args->fd, offset, len));
 }
 
 int

Modified: head/sys/i386/linux/linux_machdep.c
==============================================================================
--- head/sys/i386/linux/linux_machdep.c	Tue Jan 21 17:16:02 2020	(r356944)
+++ head/sys/i386/linux/linux_machdep.c	Tue Jan 21 17:28:22 2020	(r356945)
@@ -553,13 +553,6 @@ linux_sigaltstack(struct thread *td, struct linux_siga
 }
 
 int
-linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
-{
-
-	return (kern_ftruncate(td, args->fd, args->length));
-}
-
-int
 linux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args)
 {
 	struct l_user_desc info;


More information about the svn-src-head mailing list