2019-06-04 10:10:46 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2015-01-06 16:42:32 +00:00
/*
* arch / arm64 / kernel / sys32 . c
*
* Copyright ( C ) 2015 ARM Ltd .
*/
/*
* Needed to avoid conflicting __NR_ * macros between uapi / asm / unistd . h and
* asm / unistd32 . h .
*/
# define __COMPAT_SYSCALL_NR
2018-07-11 14:56:55 +01:00
# include <linux/compat.h>
2015-01-06 16:42:32 +00:00
# include <linux/compiler.h>
# include <linux/syscalls.h>
2018-07-11 14:56:42 +01:00
# include <asm/syscall.h>
2018-07-11 14:56:41 +01:00
asmlinkage long compat_sys_sigreturn ( void ) ;
asmlinkage long compat_sys_rt_sigreturn ( void ) ;
2018-07-11 14:56:55 +01:00
COMPAT_SYSCALL_DEFINE3 ( aarch32_statfs64 , const char __user * , pathname ,
compat_size_t , sz , struct compat_statfs64 __user * , buf )
{
/*
* 32 - bit ARM applies an OABI compatibility fixup to statfs64 and
* fstatfs64 regardless of whether OABI is in use , and therefore
* arbitrary binaries may rely upon it , so we must do the same .
* For more details , see commit :
*
* 713 c481519f19df9 ( " [ARM] 3108/2: old ABI compat: statfs64 and
* fstatfs64 " )
*/
if ( sz = = 88 )
sz = 84 ;
return kcompat_sys_statfs64 ( pathname , sz , buf ) ;
}
COMPAT_SYSCALL_DEFINE3 ( aarch32_fstatfs64 , unsigned int , fd , compat_size_t , sz ,
struct compat_statfs64 __user * , buf )
{
/* see aarch32_statfs64 */
if ( sz = = 88 )
sz = 84 ;
return kcompat_sys_fstatfs64 ( fd , sz , buf ) ;
}
/*
* Note : off_4k is always in units of 4 K . If we can ' t do the
* requested offset because it is not page - aligned , we return - EINVAL .
*/
COMPAT_SYSCALL_DEFINE6 ( aarch32_mmap2 , unsigned long , addr , unsigned long , len ,
unsigned long , prot , unsigned long , flags ,
unsigned long , fd , unsigned long , off_4k )
{
if ( off_4k & ( ~ PAGE_MASK > > 12 ) )
return - EINVAL ;
off_4k > > = ( PAGE_SHIFT - 12 ) ;
return ksys_mmap_pgoff ( addr , len , prot , flags , fd , off_4k ) ;
}
# ifdef CONFIG_CPU_BIG_ENDIAN
# define arg_u32p(name) u32, name##_hi, u32, name##_lo
# else
# define arg_u32p(name) u32, name##_lo, u32, name##_hi
# endif
# define arg_u64(name) (((u64)name##_hi << 32) | name##_lo)
COMPAT_SYSCALL_DEFINE6 ( aarch32_pread64 , unsigned int , fd , char __user * , buf ,
size_t , count , u32 , __pad , arg_u32p ( pos ) )
{
return ksys_pread64 ( fd , buf , count , arg_u64 ( pos ) ) ;
}
COMPAT_SYSCALL_DEFINE6 ( aarch32_pwrite64 , unsigned int , fd ,
const char __user * , buf , size_t , count , u32 , __pad ,
arg_u32p ( pos ) )
{
return ksys_pwrite64 ( fd , buf , count , arg_u64 ( pos ) ) ;
}
COMPAT_SYSCALL_DEFINE4 ( aarch32_truncate64 , const char __user * , pathname ,
u32 , __pad , arg_u32p ( length ) )
{
return ksys_truncate ( pathname , arg_u64 ( length ) ) ;
}
COMPAT_SYSCALL_DEFINE4 ( aarch32_ftruncate64 , unsigned int , fd , u32 , __pad ,
arg_u32p ( length ) )
{
return ksys_ftruncate ( fd , arg_u64 ( length ) ) ;
}
COMPAT_SYSCALL_DEFINE5 ( aarch32_readahead , int , fd , u32 , __pad ,
arg_u32p ( offset ) , size_t , count )
{
return ksys_readahead ( fd , arg_u64 ( offset ) , count ) ;
}
COMPAT_SYSCALL_DEFINE6 ( aarch32_fadvise64_64 , int , fd , int , advice ,
arg_u32p ( offset ) , arg_u32p ( len ) )
{
return ksys_fadvise64_64 ( fd , arg_u64 ( offset ) , arg_u64 ( len ) , advice ) ;
}
COMPAT_SYSCALL_DEFINE6 ( aarch32_sync_file_range2 , int , fd , unsigned int , flags ,
arg_u32p ( offset ) , arg_u32p ( nbytes ) )
{
return ksys_sync_file_range ( fd , arg_u64 ( offset ) , arg_u64 ( nbytes ) ,
flags ) ;
}
COMPAT_SYSCALL_DEFINE6 ( aarch32_fallocate , int , fd , int , mode ,
arg_u32p ( offset ) , arg_u32p ( len ) )
{
return ksys_fallocate ( fd , mode , arg_u64 ( offset ) , arg_u64 ( len ) ) ;
}
2015-01-06 16:42:32 +00:00
arm64: implement syscall wrappers
To minimize the risk of userspace-controlled values being used under
speculation, this patch adds pt_regs based syscall wrappers for arm64,
which pass the minimum set of required userspace values to syscall
implementations. For each syscall, a wrapper which takes a pt_regs
argument is automatically generated, and this extracts the arguments
before calling the "real" syscall implementation.
Each syscall has three functions generated:
* __do_<compat_>sys_<name> is the "real" syscall implementation, with
the expected prototype.
* __se_<compat_>sys_<name> is the sign-extension/narrowing wrapper,
inherited from common code. This takes a series of long parameters,
casting each to the requisite types required by the "real" syscall
implementation in __do_<compat_>sys_<name>.
This wrapper *may* not be necessary on arm64 given the AAPCS rules on
unused register bits, but it seemed safer to keep the wrapper for now.
* __arm64_<compat_>_sys_<name> takes a struct pt_regs pointer, and
extracts *only* the relevant register values, passing these on to the
__se_<compat_>sys_<name> wrapper.
The syscall invocation code is updated to handle the calling convention
required by __arm64_<compat_>_sys_<name>, and passes a single struct
pt_regs pointer.
The compiler can fold the syscall implementation and its wrappers, such
that the overhead of this approach is minimized.
Note that we play games with sys_ni_syscall(). It can't be defined with
SYSCALL_DEFINE0() because we must avoid the possibility of error
injection. Additionally, there are a couple of locations where we need
to call it from C code, and we don't (currently) have a
ksys_ni_syscall(). While it has no wrapper, passing in a redundant
pt_regs pointer is benign per the AAPCS.
When ARCH_HAS_SYSCALL_WRAPPER is selected, no prototype is defines for
sys_ni_syscall(). Since we need to treat it differently for in-kernel
calls and the syscall tables, the prototype is defined as-required.
The wrappers are largely the same as their x86 counterparts, but
simplified as we don't have a variety of compat calling conventions that
require separate stubs. Unlike x86, we have some zero-argument compat
syscalls, and must define COMPAT_SYSCALL_DEFINE0() to ensure that these
are also given an __arm64_compat_sys_ prefix.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2018-07-11 14:56:56 +01:00
# undef __SYSCALL
# define __SYSCALL(nr, sym) asmlinkage long __arm64_##sym(const struct pt_regs *);
# include <asm/unistd32.h>
2015-01-06 16:42:32 +00:00
# undef __SYSCALL
2019-05-24 15:11:18 -07:00
# define __SYSCALL(nr, sym) [nr] = __arm64_##sym,
2015-01-06 16:42:32 +00:00
2018-07-11 14:56:49 +01:00
const syscall_fn_t compat_sys_call_table [ __NR_compat_syscalls ] = {
2019-05-24 15:11:18 -07:00
[ 0 . . . __NR_compat_syscalls - 1 ] = __arm64_sys_ni_syscall ,
2015-01-06 16:42:32 +00:00
# include <asm/unistd32.h>
} ;