From 5a114b98661e3aaa0ac085eb931584dce3b0ef9b Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 4 Mar 2013 11:19:09 -0500 Subject: tile: work around bug in the generic sys_llseek sys_llseek should specify the high and low 32-bit seek values as "unsigned int" but instead it specifies "unsigned long". Since compat syscall arguments are always sign-extended on tile, this means that a seek value of 0xffffffff will be incorrectly interpreted as a value of -1ULL. To avoid the risk of breaking binary compatibility on architectures that already use sys_llseek this way, we follow the same path as MIPS and provide a wrapper override. Signed-off-by: Chris Metcalf Cc: stable@kernel.org [v3.6 onwards] --- arch/tile/include/asm/compat.h | 3 +++ arch/tile/kernel/compat.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 001d418..78f1f2d 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -288,6 +288,9 @@ long compat_sys_sync_file_range2(int fd, unsigned int flags, long compat_sys_fallocate(int fd, int mode, u32 offset_lo, u32 offset_hi, u32 len_lo, u32 len_hi); +long compat_sys_llseek(unsigned int fd, unsigned int offset_high, + unsigned int offset_low, loff_t __user * result, + unsigned int origin); /* Assembly trampoline to avoid clobbering r0. */ long _compat_sys_rt_sigreturn(void); diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c index 7f72401..69034e2 100644 --- a/arch/tile/kernel/compat.c +++ b/arch/tile/kernel/compat.c @@ -76,6 +76,18 @@ long compat_sys_fallocate(int fd, int mode, ((loff_t)len_hi << 32) | len_lo); } +/* + * Avoid bug in generic sys_llseek() that specifies offset_high and + * offset_low as "unsigned long", thus making it possible to pass + * a sign-extended high 32 bits in offset_low. + */ +long compat_sys_llseek(unsigned int fd, unsigned int offset_high, + unsigned int offset_low, loff_t __user * result, + unsigned int origin) +{ + return sys_llseek(fd, offset_high, offset_low, result, origin); +} + /* Provide the compat syscall number to call mapping. */ #undef __SYSCALL #define __SYSCALL(nr, call) [nr] = (call), @@ -83,6 +95,7 @@ long compat_sys_fallocate(int fd, int mode, /* See comments in sys.c */ #define compat_sys_fadvise64_64 sys32_fadvise64_64 #define compat_sys_readahead sys32_readahead +#define sys_llseek compat_sys_llseek /* Call the assembly trampolines where necessary. */ #define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn -- cgit v1.1 From 87c319a2c3c2efd397281089b9cdce3050febeff Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 4 Mar 2013 13:37:32 -0500 Subject: tile: properly use COMPAT_SYSCALL_DEFINEx This was pointed out by Al Viro. Using the correct wrappers properly does sign extension as necessary on syscall arguments. Signed-off-by: Chris Metcalf --- arch/tile/kernel/compat.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c index 69034e2..6ea4cdb 100644 --- a/arch/tile/kernel/compat.c +++ b/arch/tile/kernel/compat.c @@ -32,45 +32,48 @@ * adapt the usual convention. */ -long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high) +COMPAT_SYSCALL_DEFINE4(truncate64, char __user *, filename, u32, dummy, + u32, low, u32, high) { return sys_truncate(filename, ((loff_t)high << 32) | low); } -long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high) +COMPAT_SYSCALL_DEFINE4(ftruncate64, unsigned int, fd, u32, dummy, + u32, low, u32, high) { return sys_ftruncate(fd, ((loff_t)high << 32) | low); } -long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count, - u32 dummy, u32 low, u32 high) +COMPAT_SYSCALL_DEFINE6(pread64, unsigned int, fd, char __user *, ubuf, + size_t, count, u32, dummy, u32, low, u32, high) { return sys_pread64(fd, ubuf, count, ((loff_t)high << 32) | low); } -long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count, - u32 dummy, u32 low, u32 high) +COMPAT_SYSCALL_DEFINE6(pwrite64, unsigned int, fd, char __user *, ubuf, + size_t, count, u32, dummy, u32, low, u32, high) { return sys_pwrite64(fd, ubuf, count, ((loff_t)high << 32) | low); } -long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len) +COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, low, u32, high, + char __user *, buf, size_t, len) { return sys_lookup_dcookie(((loff_t)high << 32) | low, buf, len); } -long compat_sys_sync_file_range2(int fd, unsigned int flags, - u32 offset_lo, u32 offset_hi, - u32 nbytes_lo, u32 nbytes_hi) +COMPAT_SYSCALL_DEFINE6(sync_file_range2, int, fd, unsigned int, flags, + u32, offset_lo, u32, offset_hi, + u32, nbytes_lo, u32, nbytes_hi) { return sys_sync_file_range(fd, ((loff_t)offset_hi << 32) | offset_lo, ((loff_t)nbytes_hi << 32) | nbytes_lo, flags); } -long compat_sys_fallocate(int fd, int mode, - u32 offset_lo, u32 offset_hi, - u32 len_lo, u32 len_hi) +COMPAT_SYSCALL_DEFINE6(fallocate, int, fd, int, mode, + u32, offset_lo, u32, offset_hi, + u32, len_lo, u32, len_hi) { return sys_fallocate(fd, mode, ((loff_t)offset_hi << 32) | offset_lo, ((loff_t)len_hi << 32) | len_lo); @@ -81,9 +84,9 @@ long compat_sys_fallocate(int fd, int mode, * offset_low as "unsigned long", thus making it possible to pass * a sign-extended high 32 bits in offset_low. */ -long compat_sys_llseek(unsigned int fd, unsigned int offset_high, - unsigned int offset_low, loff_t __user * result, - unsigned int origin) +COMPAT_SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned int, offset_high, + unsigned int, offset_low, loff_t __user *, result, + unsigned int, origin) { return sys_llseek(fd, offset_high, offset_low, result, origin); } -- cgit v1.1