Commit 0003041e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sockptr_t-fixes-v2'



Christoph Hellwig says:

====================
sockptr_t fixes v2

a bunch of fixes for the sockptr_t conversion

Changes since v1:
 - fix a user pointer dereference braino in bpfilter
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 21db923e a31edb20
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -525,9 +525,9 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,
		/* Obtain version and type from previous copy */
		crypto_info[0] = tmp_crypto_info;
		/* Now copy the following data */
		sockptr_advance(optval, sizeof(*crypto_info));
		rc = copy_from_sockptr((char *)crypto_info + sizeof(*crypto_info),
				optval,
		rc = copy_from_sockptr_offset((char *)crypto_info +
				sizeof(*crypto_info),
				optval, sizeof(*crypto_info),
				sizeof(struct tls12_crypto_info_aes_gcm_128)
				- sizeof(*crypto_info));

@@ -542,9 +542,9 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,
	}
	case TLS_CIPHER_AES_GCM_256: {
		crypto_info[0] = tmp_crypto_info;
		sockptr_advance(optval, sizeof(*crypto_info));
		rc = copy_from_sockptr((char *)crypto_info + sizeof(*crypto_info),
				    optval,
		rc = copy_from_sockptr_offset((char *)crypto_info +
				sizeof(*crypto_info),
				optval, sizeof(*crypto_info),
				sizeof(struct tls12_crypto_info_aes_gcm_256)
				- sizeof(*crypto_info));

+22 −27
Original line number Diff line number Diff line
@@ -27,14 +27,6 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
{
	return (sockptr_t) { .kernel = p };
}

static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
{
	if ((unsigned long)p >= TASK_SIZE)
		return -EFAULT;
	sp->user = p;
	return 0;
}
#else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
typedef struct {
	union {
@@ -53,33 +45,44 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
{
	return (sockptr_t) { .kernel = p, .is_kernel = true };
}
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */

static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p,
		size_t size)
{
	sp->user = p;
	sp->is_kernel = false;
	if (!access_ok(p, size))
		return -EFAULT;
	*sp = (sockptr_t) { .user = p };
	return 0;
}
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */

static inline bool sockptr_is_null(sockptr_t sockptr)
{
	return !sockptr.user && !sockptr.kernel;
	if (sockptr_is_kernel(sockptr))
		return !sockptr.kernel;
	return !sockptr.user;
}

static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
		size_t offset, size_t size)
{
	if (!sockptr_is_kernel(src))
		return copy_from_user(dst, src.user, size);
	memcpy(dst, src.kernel, size);
		return copy_from_user(dst, src.user + offset, size);
	memcpy(dst, src.kernel + offset, size);
	return 0;
}

static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size)
static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
{
	return copy_from_sockptr_offset(dst, src, 0, size);
}

static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
		const void *src, size_t size)
{
	if (!sockptr_is_kernel(dst))
		return copy_to_user(dst.user, src, size);
	memcpy(dst.kernel, src, size);
		return copy_to_user(dst.user + offset, src, size);
	memcpy(dst.kernel + offset, src, size);
	return 0;
}

@@ -110,14 +113,6 @@ static inline void *memdup_sockptr_nul(sockptr_t src, size_t len)
	return p;
}

static inline void sockptr_advance(sockptr_t sockptr, size_t len)
{
	if (sockptr_is_kernel(sockptr))
		sockptr.kernel += len;
	else
		sockptr.user += len;
}

static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
{
	if (sockptr_is_kernel(src)) {
+2 −3
Original line number Diff line number Diff line
@@ -426,9 +426,8 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
			return -ENOMEM;

		sl->dccpsl_nr = optlen / sizeof(u32) - 1;
		sockptr_advance(optval, sizeof(service));
		if (copy_from_sockptr(sl->dccpsl_list, optval,
				      optlen - sizeof(service)) ||
		if (copy_from_sockptr_offset(sl->dccpsl_list, optval,
				sizeof(service), optlen - sizeof(service)) ||
		    dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
			kfree(sl);
			return -EFAULT;
+1 −1
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname,

	if (get_user(len, optlen))
		return -EFAULT;
	err = init_user_sockptr(&optval, user_optval);
	err = init_user_sockptr(&optval, user_optval, len);
	if (err)
		return err;
	return bpfilter_mbox_request(sk, optname, optval, len, false);
+5 −5
Original line number Diff line number Diff line

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Packet matching code for ARP packets.
 *
@@ -971,8 +971,8 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
		return -ENOMEM;

	loc_cpu_entry = newinfo->entries;
	sockptr_advance(arg, sizeof(tmp));
	if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
	if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
			tmp.size) != 0) {
		ret = -EFAULT;
		goto free_newinfo;
	}
@@ -1267,8 +1267,8 @@ static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
		return -ENOMEM;

	loc_cpu_entry = newinfo->entries;
	sockptr_advance(arg, sizeof(tmp));
	if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
	if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
			tmp.size) != 0) {
		ret = -EFAULT;
		goto free_newinfo;
	}
Loading