Re: RFD: x32 ABI system call numbers

From: H.J. Lu
Date: Mon Sep 05 2011 - 11:11:37 EST


On Mon, Sep 5, 2011 at 12:48 AM, Arnd Bergmann <arnd@xxxxxxxx> wrote:
> On Sunday 04 September 2011 15:13:18 H.J. Lu wrote:
>> On Sun, Sep 4, 2011 at 2:41 PM, Arnd Bergmann <arnd@xxxxxxxx> wrote:
>> > On Sunday 04 September 2011 14:25:53 H.J. Lu wrote:
>> >> >> >> #define __NR_x32_recvfrom
>> >> >> >> #define __NR_x32_sendmsg
>> >> >> >> #define __NR_x32_recvmsg
>> >> >> >> #define __NR_x32_recvmmsg
>> >> >> >> #define __NR_x32_sendmmsg
>> >> >> >
>> >> >> > These today use the MSG_CMSG_COMPAT flag to distinguish native and compat
>> >> >> > calls. Do you plan to have another flag here to handle cmsg time values?
>> >> >>
>> >> >> I am using x86-32 calls for them.
>> >> >
>> >> > But isn't that broken? These all pass u64 or time_t values at some point.
>> >> >
>> >>
>> >> time_t isn't a problem since time_t/timeval/timespec are identical for
>> >> x32 and x86-64.  As for u64, I added NATIVE_LONG_TYPE, which is
>> >> defined as long long for x32,  and use it instead of long in types for
>> >> 64bit system calls.
>> >
>> > Sorry, I misread you as saying you use the compat syscalls for these.
>> > If you use the native 64 bit syscalls, you have the opposite problem:
>> > Some network protocols (e.g. netlink or rxrpc) use other data structures
>> > that require conversion, e.g. 'long' members that x32 will get wrong.
>>
>> For those, I use x86-32 calls.
>
> So to ask again, what do you plan to do about SCM_TIMESTAMP*?
>

I added MSG_CMSG_COMPAT64 and new compat system calls with
64bit timespec/val to support it. See the enclosed patch.

BTW, I also added

compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec,
unsigned long vlen, loff_t pos)
compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec,
unsigned long vlen, loff_t pos)

to support 32bit compat_iovec * and 64bit offset.


--
H.J.
diff --git a/include/linux/socket.h b/include/linux/socket.h
index d0e77f6..86ecf27 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -272,8 +272,10 @@ struct ucred {
descriptor received through
SCM_RIGHTS */
#if defined(CONFIG_COMPAT)
+#define MSG_CMSG_COMPAT64 0x20000000 /* This message needs 64 bit timestamp */
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
#else
+#define MSG_CMSG_COMPAT64 0 /* We never have 64 bit timestamp */
#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
#endif

diff --git a/net/compat.c b/net/compat.c
index c578d93..555b951 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -229,24 +229,26 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
return 0; /* XXX: return error? check spec. */
}

- if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
- struct timeval *tv = (struct timeval *)data;
- ctv.tv_sec = tv->tv_sec;
- ctv.tv_usec = tv->tv_usec;
- data = &ctv;
- len = sizeof(ctv);
- }
- if (level == SOL_SOCKET &&
- (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
- int count = type == SCM_TIMESTAMPNS ? 1 : 3;
- int i;
- struct timespec *ts = (struct timespec *)data;
- for (i = 0; i < count; i++) {
- cts[i].tv_sec = ts[i].tv_sec;
- cts[i].tv_nsec = ts[i].tv_nsec;
+ if ((MSG_CMSG_COMPAT64 & kmsg->msg_flags) == 0) {
+ if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
+ struct timeval *tv = (struct timeval *)data;
+ ctv.tv_sec = tv->tv_sec;
+ ctv.tv_usec = tv->tv_usec;
+ data = &ctv;
+ len = sizeof(ctv);
+ }
+ if (level == SOL_SOCKET &&
+ (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
+ int count = type == SCM_TIMESTAMPNS ? 1 : 3;
+ int i;
+ struct timespec *ts = (struct timespec *)data;
+ for (i = 0; i < count; i++) {
+ cts[i].tv_sec = ts[i].tv_sec;
+ cts[i].tv_nsec = ts[i].tv_nsec;
+ }
+ data = &cts;
+ len = sizeof(cts[0]) * count;
}
- data = &cts;
- len = sizeof(cts[0]) * count;
}

cmlen = CMSG_COMPAT_LEN(len);
@@ -781,6 +783,52 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
return datagrams;
}

+asmlinkage long compat_sys_sendmsg64(int fd, struct compat_msghdr __user *msg,
+ unsigned flags)
+{
+ return sys_sendmsg(fd, (struct msghdr __user *)msg,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64);
+}
+
+asmlinkage long compat_sys_sendmmsg64(int fd, struct compat_mmsghdr __user *mmsg,
+ unsigned vlen, unsigned int flags)
+{
+ return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64);
+}
+
+asmlinkage long compat_sys_recvmsg64(int fd, struct compat_msghdr __user *msg,
+ unsigned int flags)
+{
+ return sys_recvmsg(fd, (struct msghdr __user *)msg,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64);
+}
+
+asmlinkage long compat_sys_recv64(int fd, void __user *buf, size_t len,
+ unsigned flags)
+{
+ return sys_recv(fd, buf, len,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64);
+}
+
+asmlinkage long compat_sys_recvfrom64(int fd, void __user *buf, size_t len,
+ unsigned flags, struct sockaddr __user *addr,
+ int __user *addrlen)
+{
+ return sys_recvfrom(fd, buf, len,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64,
+ addr, addrlen);
+}
+
+asmlinkage long compat_sys_recvmmsg64(int fd, struct compat_mmsghdr __user *mmsg,
+ unsigned vlen, unsigned int flags,
+ struct timespec __user *timeout)
+{
+ return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+ flags | MSG_CMSG_COMPAT | MSG_CMSG_COMPAT64,
+ timeout);
+}
+
asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
diff --git a/net/socket.c b/net/socket.c
index 24a7740..fae5472 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2133,7 +2133,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
total_len = err;

cmsg_ptr = (unsigned long)msg_sys->msg_control;
- msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+ msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT|MSG_CMSG_COMPAT64);

if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;