diff options
author | Mark Johnston <markj@FreeBSD.org> | 2020-01-21 17:28:22 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2020-01-21 17:28:22 +0000 |
commit | 149afbf3ba2960dd800edc0212aec4f245535a10 (patch) | |
tree | 7923c45cdfd703e331062aeb9de9247d94864748 /sys/compat/linux/linux_file.c | |
parent | 4c6076088aa19703494353d3c6e234ad089986c4 (diff) | |
download | src-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.c | 98 |
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 |