aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_file.c
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2020-01-21 17:28:22 +0000
committerMark Johnston <markj@FreeBSD.org>2020-01-21 17:28:22 +0000
commit149afbf3ba2960dd800edc0212aec4f245535a10 (patch)
tree7923c45cdfd703e331062aeb9de9247d94864748 /sys/compat/linux/linux_file.c
parent4c6076088aa19703494353d3c6e234ad089986c4 (diff)
downloadsrc-149afbf3ba2960dd800edc0212aec4f245535a10.tar.gz
src-149afbf3ba2960dd800edc0212aec4f245535a10.zip
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@gmail.com> Reviewed by: kib (previous version) MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D23210
Notes
Notes: svn path=/head/; revision=356945
Diffstat (limited to 'sys/compat/linux/linux_file.c')
-rw-r--r--sys/compat/linux/linux_file.c98
1 files changed, 81 insertions, 17 deletions
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index f341e67b11e7..c335d6fd1ffd 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -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_truncate_args *args)
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_ftruncate_args *args)
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_fdatasync_args *uap)
int
linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap)
{
+ off_t nbytes, offset;
+
+#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 (uap->offset < 0 || uap->nbytes < 0 ||
+ 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 *uap)
int
linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
{
+ off_t 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, uap->offset));
+ 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 *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_fallocate_args *args)
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