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
This commit is contained in:
parent
05386e4d1f
commit
293becab6b
@ -592,13 +592,6 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
|
||||
return (error);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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, \
|
||||
|
@ -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 (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 *uap)
|
||||
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 *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
|
||||
|
@ -552,13 +552,6 @@ linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
|
||||
return (error);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user