[PATCH] 2.5.43 s390 (4/6): 31 bit emulation.

Martin Schwidefsky (schwidefsky@de.ibm.com)
Wed, 16 Oct 2002 18:48:12 +0200


Fix 31 bit emulation of sys_recvmsg, sys_setsockopt and sys_futex.

diff -urN linux-2.5.43/arch/s390x/kernel/linux32.c linux-2.5.43-s390/arch/s390x/kernel/linux32.c
--- linux-2.5.43/arch/s390x/kernel/linux32.c Wed Oct 16 05:27:19 2002
+++ linux-2.5.43-s390/arch/s390x/kernel/linux32.c Wed Oct 16 17:54:11 2002
@@ -2497,8 +2497,23 @@
CMSG32_ALIGN(sizeof(struct cmsghdr32)));
kcmsg32->cmsg_len = clen32;

+ switch (kcmsg32->cmsg_type) {
+ /*
+ * The timestamp type's data needs to be converted
+ * from 64-bit time values to 32-bit time values
+ */
+ case SO_TIMESTAMP: {
+ __kernel_time_t32* ptr_time32 = CMSG32_DATA(kcmsg32);
+ __kernel_time_t* ptr_time = CMSG_DATA(ucmsg);
+ get_user(*ptr_time32, ptr_time);
+ get_user(*(ptr_time32+1), ptr_time+1);
+ kcmsg32->cmsg_len -= 2*(sizeof(__kernel_time_t) -
+ sizeof(__kernel_time_t32));
+ }
+ default:;
+ }
ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
- wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+ wp = (((char *)kcmsg32) + CMSG32_ALIGN(kcmsg32->cmsg_len));
}

/* Copy back fixed up data, and adjust pointers. */
@@ -2613,6 +2628,9 @@

err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len,
user_flags, si->scm);
+ if (err >= 0)
+ scm_recv32(sock, msg, &iocb, flags, cmsg_ptr);
+
if (-EIOCBQUEUED == err)
err = wait_on_sync_kiocb(&iocb);

@@ -2645,7 +2663,7 @@
sockfd_put(sock);
}

- if(uaddr != NULL && err >= 0)
+ if(uaddr != NULL && err >= 0 && kern_msg.msg_namelen)
err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
if(cmsg_ptr != 0 && err >= 0) {
unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
@@ -2747,6 +2765,32 @@
return err;
}

+static __inline__ void
+scm_recv32(struct socket *sock, struct msghdr *msg,
+ struct sock_iocb *si, int flags, unsigned long cmsg_ptr)
+{
+ if(!msg->msg_control) {
+ if(sock->passcred || si->scm->fp)
+ msg->msg_flags |= MSG_CTRUNC;
+ if(si->scm->fp)
+ __scm_destroy(si->scm);
+ } else {
+ /* If recvmsg processing itself placed some
+ * control messages into user space, it's is
+ * using 64-bit CMSG processing, so we need
+ * to fix it up before we tack on more stuff.
+ */
+ if((unsigned long) msg->msg_control != cmsg_ptr)
+ cmsg32_recvmsg_fixup(msg, cmsg_ptr);
+ /* Wheee... */
+ if(sock->passcred)
+ put_cmsg32(msg, SOL_SOCKET, SCM_CREDENTIALS,
+ sizeof(si->scm->creds), &si->scm->creds);
+ if(si->scm->fp != NULL)
+ scm_detach_fds32(msg, si->scm);
+ }
+}
+
/*
* BSD recvmsg interface
*/
@@ -2820,6 +2864,9 @@

err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len,
flags, si->scm);
+ if (err >= 0)
+ scm_recv32(sock, msg, &iocb, flags, cmsg_ptr);
+
if (-EIOCBQUEUED == err)
err = wait_on_sync_kiocb(&iocb);
if (err < 0)
@@ -2833,27 +2880,13 @@
if (err < 0)
goto out_freeiov;
}
- if(!msg_sys.msg_control) {
- if(sock->passcred || si->scm->fp)
- msg_sys.msg_flags |= MSG_CTRUNC;
- if(si->scm->fp)
- __scm_destroy(si->scm);
- } else {
- /* If recvmsg processing itself placed some
- * control messages into user space, it's is
- * using 64-bit CMSG processing, so we need
- * to fix it up before we tack on more stuff.
- */
- if((unsigned long) msg_sys.msg_control != cmsg_ptr)
- cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr);
- /* Wheee... */
- if(sock->passcred)
- put_cmsg32(&msg_sys,
- SOL_SOCKET, SCM_CREDENTIALS,
- sizeof(si->scm->creds), &si->scm->creds);
- if(si->scm->fp != NULL)
- scm_detach_fds32(&msg_sys, si->scm);
- }
+ err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
+ if (err)
+ goto out_freeiov;
+ err = __put_user((__kernel_size_t32) ((unsigned long)msg_sys.msg_control - cmsg_ptr), &msg->msg_controllen);
+ if (err)
+ goto out_freeiov;
+ err = len;

out_freeiov:
if (iov != iovstack)
@@ -2946,6 +2979,20 @@
if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
return do_set_icmpv6_filter(fd, level, optname,
optval, optlen);
+ if (level == SOL_SOCKET &&
+ (optname == SO_SNDTIMEO || optname == SO_RCVTIMEO)) {
+ long ret;
+ struct timeval tmp;
+ mm_segment_t old_fs;
+
+ if (get_tv32(&tmp, (struct timeval32 *)optval ))
+ return -EFAULT;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_setsockopt(fd, level, optname, (char *) &tmp, sizeof(struct timeval));
+ set_fs(old_fs);
+ return ret;
+ }

return sys_setsockopt(fd, level, optname, optval, optlen);
}
@@ -4556,26 +4603,19 @@
sys32_futex(void *uaddr, int op, int val,
struct timespec32 *timeout32)
{
- long ret;
- struct timespec tmp, *timeout;
-
- ret = -ENOMEM;
- timeout = kmalloc(sizeof(*timeout), GFP_USER);
- if (!timeout)
- goto out;
+ struct timespec tmp;
+ mm_segment_t old_fs;
+ int ret;

- ret = -EINVAL;
if (get_user (tmp.tv_sec, &timeout32->tv_sec) ||
- get_user (tmp.tv_nsec, &timeout32->tv_nsec) ||
- put_user (tmp.tv_sec, &timeout->tv_sec) ||
- put_user (tmp.tv_nsec, &timeout->tv_nsec))
- goto out_free;
+ get_user (tmp.tv_nsec, &timeout32->tv_nsec))
+ return -EINVAL;

- ret = sys_futex(uaddr, op, val, timeout);
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_futex(uaddr, op, val, &tmp);
+ set_fs(old_fs);

-out_free:
- kfree(timeout);
-out:
return ret;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/