Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe0c72f3 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by David S. Miller
Browse files

socket: move compat timeout handling into sock.c



This is a cleanup to prepare for the addition of 64-bit time_t
in O_SNDTIMEO/O_RCVTIMEO. The existing compat handler seems
unnecessarily complex and error-prone, moving it all into the
main setsockopt()/getsockopt() implementation requires half
as much code and is easier to extend.

32-bit user space can now use old_timeval32 on both 32-bit
and 64-bit machines, while 64-bit code can use
__old_kernel_timeval.

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarDeepa Dinamani <deepa.kernel@gmail.com>
Acked-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a9bcfd1d
Loading
Loading
Loading
Loading
+1 −65
Original line number Diff line number Diff line
@@ -348,28 +348,6 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname,
			      sizeof(struct sock_fprog));
}

static int do_set_sock_timeout(struct socket *sock, int level,
		int optname, char __user *optval, unsigned int optlen)
{
	struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
	struct timeval ktime;
	mm_segment_t old_fs;
	int err;

	if (optlen < sizeof(*up))
		return -EINVAL;
	if (!access_ok(up, sizeof(*up)) ||
	    __get_user(ktime.tv_sec, &up->tv_sec) ||
	    __get_user(ktime.tv_usec, &up->tv_usec))
		return -EFAULT;
	old_fs = get_fs();
	set_fs(KERNEL_DS);
	err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
	set_fs(old_fs);

	return err;
}

static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
				char __user *optval, unsigned int optlen)
{
@@ -377,10 +355,6 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
	    optname == SO_ATTACH_REUSEPORT_CBPF)
		return do_set_attach_filter(sock, level, optname,
					    optval, optlen);
	if (!COMPAT_USE_64BIT_TIME &&
	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
		return do_set_sock_timeout(sock, level, optname, optval, optlen);

	return sock_setsockopt(sock, level, optname, optval, optlen);
}

@@ -417,44 +391,6 @@ COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
	return __compat_sys_setsockopt(fd, level, optname, optval, optlen);
}

static int do_get_sock_timeout(struct socket *sock, int level, int optname,
		char __user *optval, int __user *optlen)
{
	struct compat_timeval __user *up;
	struct timeval ktime;
	mm_segment_t old_fs;
	int len, err;

	up = (struct compat_timeval __user *) optval;
	if (get_user(len, optlen))
		return -EFAULT;
	if (len < sizeof(*up))
		return -EINVAL;
	len = sizeof(ktime);
	old_fs = get_fs();
	set_fs(KERNEL_DS);
	err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
	set_fs(old_fs);

	if (!err) {
		if (put_user(sizeof(*up), optlen) ||
		    !access_ok(up, sizeof(*up)) ||
		    __put_user(ktime.tv_sec, &up->tv_sec) ||
		    __put_user(ktime.tv_usec, &up->tv_usec))
			err = -EFAULT;
	}
	return err;
}

static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
				char __user *optval, int __user *optlen)
{
	if (!COMPAT_USE_64BIT_TIME &&
	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
		return do_get_sock_timeout(sock, level, optname, optval, optlen);
	return sock_getsockopt(sock, level, optname, optval, optlen);
}

int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
{
	struct compat_timeval __user *ctv;
@@ -527,7 +463,7 @@ static int __compat_sys_getsockopt(int fd, int level, int optname,
		}

		if (level == SOL_SOCKET)
			err = compat_sock_getsockopt(sock, level,
			err = sock_getsockopt(sock, level,
					optname, optval, optlen);
		else if (sock->ops->compat_getsockopt)
			err = sock->ops->compat_getsockopt(sock, level,
+43 −22
Original line number Diff line number Diff line
@@ -335,14 +335,48 @@ int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(__sk_backlog_rcv);

static int sock_get_timeout(long timeo, void *optval)
{
	struct __kernel_old_timeval tv;

	if (timeo == MAX_SCHEDULE_TIMEOUT) {
		tv.tv_sec = 0;
		tv.tv_usec = 0;
	} else {
		tv.tv_sec = timeo / HZ;
		tv.tv_usec = ((timeo % HZ) * USEC_PER_SEC) / HZ;
	}

	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
		struct old_timeval32 tv32 = { tv.tv_sec, tv.tv_usec };
		*(struct old_timeval32 *)optval = tv32;
		return sizeof(tv32);
	}

	*(struct __kernel_old_timeval *)optval = tv;
	return sizeof(tv);
}

static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
{
	struct timeval tv;
	struct __kernel_old_timeval tv;

	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
		struct old_timeval32 tv32;

		if (optlen < sizeof(tv32))
			return -EINVAL;

		if (copy_from_user(&tv32, optval, sizeof(tv32)))
			return -EFAULT;
		tv.tv_sec = tv32.tv_sec;
		tv.tv_usec = tv32.tv_usec;
	} else {
		if (optlen < sizeof(tv))
			return -EINVAL;
		if (copy_from_user(&tv, optval, sizeof(tv)))
			return -EFAULT;
	}
	if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC)
		return -EDOM;

@@ -1121,7 +1155,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
		int val;
		u64 val64;
		struct linger ling;
		struct timeval tm;
		struct old_timeval32 tm32;
		struct __kernel_old_timeval tm;
		struct sock_txtime txtime;
	} v;

@@ -1222,25 +1257,11 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
		break;

	case SO_RCVTIMEO:
		lv = sizeof(struct timeval);
		if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
			v.tm.tv_sec = 0;
			v.tm.tv_usec = 0;
		} else {
			v.tm.tv_sec = sk->sk_rcvtimeo / HZ;
			v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * USEC_PER_SEC) / HZ;
		}
		lv = sock_get_timeout(sk->sk_rcvtimeo, &v);
		break;

	case SO_SNDTIMEO:
		lv = sizeof(struct timeval);
		if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {
			v.tm.tv_sec = 0;
			v.tm.tv_usec = 0;
		} else {
			v.tm.tv_sec = sk->sk_sndtimeo / HZ;
			v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * USEC_PER_SEC) / HZ;
		}
		lv = sock_get_timeout(sk->sk_sndtimeo, &v);
		break;

	case SO_RCVLOWAT:
+2 −2
Original line number Diff line number Diff line
@@ -1439,7 +1439,7 @@ static int vsock_stream_setsockopt(struct socket *sock,
		break;

	case SO_VM_SOCKETS_CONNECT_TIMEOUT: {
		struct timeval tv;
		struct __kernel_old_timeval tv;
		COPY_IN(tv);
		if (tv.tv_sec >= 0 && tv.tv_usec < USEC_PER_SEC &&
		    tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) {
@@ -1517,7 +1517,7 @@ static int vsock_stream_getsockopt(struct socket *sock,
		break;

	case SO_VM_SOCKETS_CONNECT_TIMEOUT: {
		struct timeval tv;
		struct __kernel_old_timeval tv;
		tv.tv_sec = vsk->connect_timeout / HZ;
		tv.tv_usec =
		    (vsk->connect_timeout -