// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/kernel/sys_oabi-compat.c * * Compatibility wrappers for syscalls that are used from * old ABI user space binaries with an EABI kernel. * * Author: Nicolas Pitre * Created: Oct 7, 2005 * Copyright: MontaVista Software, Inc.
*/
#include <asm/syscalls.h>
/* * The legacy ABI and the new ARM EABI have different rules making some * syscalls incompatible especially with structure arguments. * Most notably, Eabi says 64-bit members should be 64-bit aligned instead of * simply word aligned. EABI also pads structures to the size of the largest * member it contains instead of the invariant 32-bit. * * The following syscalls are affected: * * sys_stat64: * sys_lstat64: * sys_fstat64: * sys_fstatat64: * * struct stat64 has different sizes and some members are shifted * Compatibility wrappers are needed for them and provided below. * * sys_fcntl64: * * struct flock64 has different sizes and some members are shifted * A compatibility wrapper is needed and provided below. * * sys_statfs64: * sys_fstatfs64: * * struct statfs64 has extra padding with EABI growing its size from * 84 to 88. This struct is now __attribute__((packed,aligned(4))) * with a small assembly wrapper to force the sz argument to 84 if it is 88 * to avoid copying the extra padding over user space unexpecting it. * * sys_newuname: * * struct new_utsname has no padding with EABI. No problem there. * * sys_epoll_ctl: * sys_epoll_wait: * * struct epoll_event has its second member shifted also affecting the * structure size. Compatibility wrappers are needed and provided below. * * sys_ipc: * sys_semop: * sys_semtimedop: * * struct sembuf loses its padding with EABI. Since arrays of them are * used they have to be copyed to remove the padding. Compatibility wrappers * provided below. * * sys_bind: * sys_connect: * sys_sendmsg: * sys_sendto: * sys_socketcall: * * struct sockaddr_un loses its padding with EABI. Since the size of the * structure is used as a validation test in unix_mkname(), we need to * change the length argument to 110 whenever it is 112. Compatibility * wrappers provided below.
*/
asmlinkage long sys_oabi_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
{ struct sockaddr __user *addr; int msg_namelen;
sa_family_t sa_family; if (msg &&
get_user(msg_namelen, &msg->msg_namelen) == 0 &&
msg_namelen == 112 &&
get_user(addr, &msg->msg_name) == 0 &&
get_user(sa_family, &addr->sa_family) == 0 &&
sa_family == AF_UNIX)
{ /* * HACK ALERT: there is a limit to how much backward bending * we should do for what is actually a transitional * compatibility layer. This already has known flaws with * a few ioctls that we don't intend to fix. Therefore * consider this blatent hack as another one... and take care * to run for cover. In most cases it will "just work fine". * If it doesn't, well, tough.
*/
put_user(110, &msg->msg_namelen);
} return sys_sendmsg(fd, msg, flags);
}
asmlinkage long sys_oabi_socketcall(int call, unsignedlong __user *args)
{ unsignedlong r = -EFAULT, a[6];
switch (call) { case SYS_BIND: if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
r = sys_oabi_bind(a[0], (struct sockaddr __user *)a[1], a[2]); break; case SYS_CONNECT: if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
r = sys_oabi_connect(a[0], (struct sockaddr __user *)a[1], a[2]); break; case SYS_SENDTO: if (copy_from_user(a, args, 6 * sizeof(long)) == 0)
r = sys_oabi_sendto(a[0], (void __user *)a[1], a[2], a[3],
(struct sockaddr __user *)a[4], a[5]); break; case SYS_SENDMSG: if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
r = sys_oabi_sendmsg(a[0], (struct user_msghdr __user *)a[1], a[2]); break; default:
r = sys_socketcall(call, args);
}