Commit 7c4c2416 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'get-rid-of-the-address_space-override-in-setsockopt-v2'



Christoph Hellwig says:

====================
get rid of the address_space override in setsockopt v2

setsockopt is the last place in architecture-independ code that still
uses set_fs to force the uaccess routines to operate on kernel pointers.

This series adds a new sockptr_t type that can contained either a kernel
or user pointer, and which has accessors that do the right thing, and
then uses it for setsockopt, starting by refactoring some low-level
helpers and moving them over to it before finally doing the main
setsockopt method.

Note that apparently the eBPF selftests do not even cover this path, so
the series has been tested with a testing patch that always copies the
data first and passes a kernel pointer.  This is something that works for
most common sockopts (and is something that the ePBF support relies on),
but unfortunately in various corner cases we either don't use the passed
in length, or in one case actually copy data back from setsockopt, or in
case of bpfilter straight out do not work with kernel pointers at all.

Against net-next/master.

Changes since v1:
 - check that users don't pass in kernel addresses
 - more bpfilter cleanups
 - cosmetic mptcp tweak
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 197569f7 6d04fe15
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -197,8 +197,7 @@ unlock:
	return err;
}

static int alg_setkey(struct sock *sk, char __user *ukey,
		      unsigned int keylen)
static int alg_setkey(struct sock *sk, sockptr_t ukey, unsigned int keylen)
{
	struct alg_sock *ask = alg_sk(sk);
	const struct af_alg_type *type = ask->type;
@@ -210,7 +209,7 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
		return -ENOMEM;

	err = -EFAULT;
	if (copy_from_user(key, ukey, keylen))
	if (copy_from_sockptr(key, ukey, keylen))
		goto out;

	err = type->setkey(ask->private, key, keylen);
@@ -222,7 +221,7 @@ out:
}

static int alg_setsockopt(struct socket *sock, int level, int optname,
			  char __user *optval, unsigned int optlen)
			  sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	struct alg_sock *ask = alg_sk(sk);
+10 −8
Original line number Diff line number Diff line
@@ -488,7 +488,7 @@ static int chtls_getsockopt(struct sock *sk, int level, int optname,
}

static int do_chtls_setsockopt(struct sock *sk, int optname,
			       char __user *optval, unsigned int optlen)
			       sockptr_t optval, unsigned int optlen)
{
	struct tls_crypto_info *crypto_info, tmp_crypto_info;
	struct chtls_sock *csk;
@@ -498,12 +498,12 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,

	csk = rcu_dereference_sk_user_data(sk);

	if (!optval || optlen < sizeof(*crypto_info)) {
	if (sockptr_is_null(optval) || optlen < sizeof(*crypto_info)) {
		rc = -EINVAL;
		goto out;
	}

	rc = copy_from_user(&tmp_crypto_info, optval, sizeof(*crypto_info));
	rc = copy_from_sockptr(&tmp_crypto_info, optval, sizeof(*crypto_info));
	if (rc) {
		rc = -EFAULT;
		goto out;
@@ -525,8 +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 */
		rc = copy_from_user((char *)crypto_info + sizeof(*crypto_info),
				optval + sizeof(*crypto_info),
		sockptr_advance(optval, sizeof(*crypto_info));
		rc = copy_from_sockptr((char *)crypto_info + sizeof(*crypto_info),
				optval,
				sizeof(struct tls12_crypto_info_aes_gcm_128)
				- sizeof(*crypto_info));

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

@@ -565,7 +567,7 @@ out:
}

static int chtls_setsockopt(struct sock *sk, int level, int optname,
			    char __user *optval, unsigned int optlen)
			    sockptr_t optval, unsigned int optlen)
{
	struct tls_context *ctx = tls_get_ctx(sk);

+2 −2
Original line number Diff line number Diff line
@@ -401,7 +401,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}

static int data_sock_setsockopt(struct socket *sock, int level, int optname,
				char __user *optval, unsigned int len)
				sockptr_t optval, unsigned int len)
{
	struct sock *sk = sock->sk;
	int err = 0, opt = 0;
@@ -414,7 +414,7 @@ static int data_sock_setsockopt(struct socket *sock, int level, int optname,

	switch (optname) {
	case MISDN_TIME_STAMP:
		if (get_user(opt, (int __user *)optval)) {
		if (copy_from_sockptr(&opt, optval, sizeof(int))) {
			err = -EFAULT;
			break;
		}
+3 −3
Original line number Diff line number Diff line
@@ -4,9 +4,10 @@

#include <uapi/linux/bpfilter.h>
#include <linux/usermode_driver.h>
#include <linux/sockptr.h>

struct sock;
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, sockptr_t optval,
			    unsigned int optlen);
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
			    int __user *optlen);
@@ -16,8 +17,7 @@ struct bpfilter_umh_ops {
	struct umd_info info;
	/* since ip_getsockopt() can run in parallel, serialize access to umh */
	struct mutex lock;
	int (*sockopt)(struct sock *sk, int optname,
		       char __user *optval,
	int (*sockopt)(struct sock *sk, int optname, sockptr_t optval,
		       unsigned int optlen, bool is_set);
	int (*start)(void);
};
+2 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/kallsyms.h>
#include <linux/if_vlan.h>
#include <linux/vmalloc.h>
#include <linux/sockptr.h>
#include <crypto/sha.h>

#include <net/sch_generic.h>
@@ -1276,7 +1277,7 @@ struct bpf_sockopt_kern {
	s32		retval;
};

int copy_bpf_fprog_from_user(struct sock_fprog *dst, void __user *src, int len);
int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len);

struct bpf_sk_lookup_kern {
	u16		family;
Loading