Commit 7b6575c6 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-start-to-replace-copy_from_sockptr'

Eric Dumazet says:

====================
net: start to replace copy_from_sockptr()

We got several syzbot reports about unsafe copy_from_sockptr()
calls. After fixing some of them, it appears that we could
use a new helper to factorize all the checks in one place.

This series targets net tree, we can later start converting
many call sites in net-next.
====================

Link: https://lore.kernel.org/r/20240408082845.3957374-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents cf1b7201 7a87441c
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -401,23 +401,23 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}

static int data_sock_setsockopt(struct socket *sock, int level, int optname,
				sockptr_t optval, unsigned int len)
				sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	int err = 0, opt = 0;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p, %d, %x, optval, %d)\n", __func__, sock,
		       level, optname, len);
		       level, optname, optlen);

	lock_sock(sk);

	switch (optname) {
	case MISDN_TIME_STAMP:
		if (copy_from_sockptr(&opt, optval, sizeof(int))) {
			err = -EFAULT;
		err = copy_safe_from_sockptr(&opt, sizeof(opt),
					     optval, optlen);
		if (err)
			break;
		}

		if (opt)
			_pms(sk)->cmask |= MISDN_TIME_STAMP;
+25 −0
Original line number Diff line number Diff line
@@ -50,11 +50,36 @@ static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
	return 0;
}

/* Deprecated.
 * This is unsafe, unless caller checked user provided optlen.
 * Prefer copy_safe_from_sockptr() instead.
 */
static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
{
	return copy_from_sockptr_offset(dst, src, 0, size);
}

/**
 * copy_safe_from_sockptr: copy a struct from sockptr
 * @dst:   Destination address, in kernel space. This buffer must be @ksize
 *         bytes long.
 * @ksize: Size of @dst struct.
 * @optval: Source address. (in user or kernel space)
 * @optlen: Size of @optval data.
 *
 * Returns:
 *  * -EINVAL: @optlen < @ksize
 *  * -EFAULT: access to userspace failed.
 *  * 0 : @ksize bytes were copied
 */
static inline int copy_safe_from_sockptr(void *dst, size_t ksize,
					 sockptr_t optval, unsigned int optlen)
{
	if (optlen < ksize)
		return -EINVAL;
	return copy_from_sockptr(dst, optval, ksize);
}

static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
		sockptr_t src, size_t usize)
{
+6 −6
Original line number Diff line number Diff line
@@ -252,10 +252,10 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
			break;
		}

		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
			err = -EFAULT;
		err = copy_safe_from_sockptr(&opt, sizeof(opt),
					     optval, optlen);
		if (err)
			break;
		}

		if (opt > LLCP_MAX_RW) {
			err = -EINVAL;
@@ -274,10 +274,10 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
			break;
		}

		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
			err = -EFAULT;
		err = copy_safe_from_sockptr(&opt, sizeof(opt),
					     optval, optlen);
		if (err)
			break;
		}

		if (opt > LLCP_MAX_MIUX) {
			err = -EINVAL;