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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-07-24 15:41:54 -07:00
commit 7c4c241680
87 changed files with 898 additions and 747 deletions

View File

@ -197,8 +197,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
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 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
}
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);

View File

@ -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 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,
}
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);

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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;

View File

@ -8,6 +8,7 @@
#include <net/fib_notifier.h>
#include <uapi/linux/mroute.h>
#include <linux/mroute_base.h>
#include <linux/sockptr.h>
#ifdef CONFIG_IP_MROUTE
static inline int ip_mroute_opt(int opt)
@ -15,7 +16,7 @@ static inline int ip_mroute_opt(int opt)
return opt >= MRT_BASE && opt <= MRT_MAX;
}
int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int);
int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);
int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
@ -23,7 +24,7 @@ int ip_mr_init(void);
bool ipmr_rule_default(const struct fib_rule *rule);
#else
static inline int ip_mroute_setsockopt(struct sock *sock, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
return -ENOPROTOOPT;
}

View File

@ -8,6 +8,7 @@
#include <net/net_namespace.h>
#include <uapi/linux/mroute6.h>
#include <linux/mroute_base.h>
#include <linux/sockptr.h>
#include <net/fib_rules.h>
#ifdef CONFIG_IPV6_MROUTE
@ -25,7 +26,7 @@ static inline int ip6_mroute_opt(int opt)
struct sock;
#ifdef CONFIG_IPV6_MROUTE
extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, unsigned int);
extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);
extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
extern int ip6_mr_input(struct sk_buff *skb);
extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
@ -33,9 +34,8 @@ extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *ar
extern int ip6_mr_init(void);
extern void ip6_mr_cleanup(void);
#else
static inline
int ip6_mroute_setsockopt(struct sock *sock,
int optname, char __user *optval, unsigned int optlen)
static inline int ip6_mroute_setsockopt(struct sock *sock, int optname,
sockptr_t optval, unsigned int optlen)
{
return -ENOPROTOOPT;
}

View File

@ -21,6 +21,7 @@
#include <linux/rcupdate.h>
#include <linux/once.h>
#include <linux/fs.h>
#include <linux/sockptr.h>
#include <uapi/linux/net.h>
@ -162,7 +163,8 @@ struct proto_ops {
int (*listen) (struct socket *sock, int len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt)(struct socket *sock, int level,
int optname, char __user *optval, unsigned int optlen);
int optname, sockptr_t optval,
unsigned int optlen);
int (*getsockopt)(struct socket *sock, int level,
int optname, char __user *optval, int __user *optlen);
void (*show_fdinfo)(struct seq_file *m, struct socket *sock);

View File

@ -13,6 +13,7 @@
#include <linux/static_key.h>
#include <linux/netfilter_defs.h>
#include <linux/netdevice.h>
#include <linux/sockptr.h>
#include <net/net_namespace.h>
static inline int NF_DROP_GETERR(int verdict)
@ -163,7 +164,8 @@ struct nf_sockopt_ops {
/* Non-inclusive ranges: use 0/0/NULL to never get called. */
int set_optmin;
int set_optmax;
int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);
int (*set)(struct sock *sk, int optval, sockptr_t arg,
unsigned int len);
int get_optmin;
int get_optmax;
int (*get)(struct sock *sk, int optval, void __user *user, int *len);
@ -338,7 +340,7 @@ NF_HOOK_LIST(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
}
/* Call setsockopt() */
int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, sockptr_t opt,
unsigned int len);
int nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
int *len);

View File

@ -301,8 +301,8 @@ int xt_target_to_user(const struct xt_entry_target *t,
int xt_data_to_user(void __user *dst, const void *src,
int usersize, int size, int aligned_size);
void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
struct xt_counters_info *info);
void *xt_copy_counters(sockptr_t arg, unsigned int len,
struct xt_counters_info *info);
struct xt_counters *xt_counters_alloc(unsigned int counters);
struct xt_table *xt_register_table(struct net *net,

132
include/linux/sockptr.h Normal file
View File

@ -0,0 +1,132 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020 Christoph Hellwig.
*
* Support for "universal" pointers that can point to either kernel or userspace
* memory.
*/
#ifndef _LINUX_SOCKPTR_H
#define _LINUX_SOCKPTR_H
#include <linux/compiler.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
typedef union {
void *kernel;
void __user *user;
} sockptr_t;
static inline bool sockptr_is_kernel(sockptr_t sockptr)
{
return (unsigned long)sockptr.kernel >= TASK_SIZE;
}
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 {
void *kernel;
void __user *user;
};
bool is_kernel : 1;
} sockptr_t;
static inline bool sockptr_is_kernel(sockptr_t sockptr)
{
return sockptr.is_kernel;
}
static inline sockptr_t KERNEL_SOCKPTR(void *p)
{
return (sockptr_t) { .kernel = p, .is_kernel = true };
}
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
{
sp->user = p;
sp->is_kernel = false;
return 0;
}
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
static inline bool sockptr_is_null(sockptr_t sockptr)
{
return !sockptr.user && !sockptr.kernel;
}
static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
{
if (!sockptr_is_kernel(src))
return copy_from_user(dst, src.user, size);
memcpy(dst, src.kernel, size);
return 0;
}
static inline int copy_to_sockptr(sockptr_t dst, 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 0;
}
static inline void *memdup_sockptr(sockptr_t src, size_t len)
{
void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
if (!p)
return ERR_PTR(-ENOMEM);
if (copy_from_sockptr(p, src, len)) {
kfree(p);
return ERR_PTR(-EFAULT);
}
return p;
}
static inline void *memdup_sockptr_nul(sockptr_t src, size_t len)
{
char *p = kmalloc_track_caller(len + 1, GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
if (copy_from_sockptr(p, src, len)) {
kfree(p);
return ERR_PTR(-EFAULT);
}
p[len] = '\0';
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)) {
size_t len = min(strnlen(src.kernel, count - 1) + 1, count);
memcpy(dst, src.kernel, len);
return len;
}
return strncpy_from_user(dst, src.user, count);
}
#endif /* _LINUX_SOCKPTR_H */

View File

@ -16,6 +16,7 @@
#include <linux/timer.h>
#include <linux/poll.h>
#include <linux/kernel.h>
#include <linux/sockptr.h>
#include <net/inet_sock.h>
#include <net/request_sock.h>
@ -45,7 +46,7 @@ struct inet_connection_sock_af_ops {
u16 net_frag_header_len;
u16 sockaddr_len;
int (*setsockopt)(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
sockptr_t optval, unsigned int optlen);
int (*getsockopt)(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
void (*addr2sockaddr)(struct sock *sk, struct sockaddr *);

View File

@ -23,6 +23,7 @@
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/jhash.h>
#include <linux/sockptr.h>
#include <net/inet_sock.h>
#include <net/route.h>
@ -707,9 +708,7 @@ int __ip_options_compile(struct net *net, struct ip_options *opt,
int ip_options_compile(struct net *net, struct ip_options *opt,
struct sk_buff *skb);
int ip_options_get(struct net *net, struct ip_options_rcu **optp,
unsigned char *data, int optlen);
int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp,
unsigned char __user *data, int optlen);
sockptr_t data, int optlen);
void ip_options_undo(struct ip_options *opt);
void ip_forward_options(struct sk_buff *skb);
int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev);
@ -723,7 +722,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
struct sk_buff *skb, int tlen, int offset);
int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
struct ipcm_cookie *ipc, bool allow_ipv6);
int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
int __user *optlen);

View File

@ -406,7 +406,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
struct ip6_flowlabel *fl,
struct ipv6_txoptions *fopt);
void fl6_free_socklist(struct sock *sk);
int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen);
int ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen);
int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
int flags);
int ip6_flowlabel_init(void);
@ -1084,8 +1084,8 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
* socket options (ipv6_sockglue.c)
*/
int ipv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
int ipv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);

View File

@ -431,7 +431,7 @@ struct sctp_af {
int (*setsockopt) (struct sock *sk,
int level,
int optname,
char __user *optval,
sockptr_t optval,
unsigned int optlen);
int (*getsockopt) (struct sock *sk,
int level,

View File

@ -59,6 +59,7 @@
#include <linux/filter.h>
#include <linux/rculist_nulls.h>
#include <linux/poll.h>
#include <linux/sockptr.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
@ -1140,7 +1141,7 @@ struct proto {
void (*destroy)(struct sock *sk);
void (*shutdown)(struct sock *sk, int how);
int (*setsockopt)(struct sock *sk, int level,
int optname, char __user *optval,
int optname, sockptr_t optval,
unsigned int optlen);
int (*getsockopt)(struct sock *sk, int level,
int optname, char __user *optval,
@ -1669,7 +1670,7 @@ void sock_pfree(struct sk_buff *skb);
#endif
int sock_setsockopt(struct socket *sock, int level, int op,
char __user *optval, unsigned int optlen);
sockptr_t optval, unsigned int optlen);
int sock_getsockopt(struct socket *sock, int level, int op,
char __user *optval, int __user *optlen);
@ -1733,7 +1734,7 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname,
int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags);
int sock_common_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen);
sockptr_t optval, unsigned int optlen);
void sk_common_release(struct sock *sk);

View File

@ -399,8 +399,8 @@ __poll_t tcp_poll(struct file *file, struct socket *sock,
struct poll_table_struct *wait);
int tcp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int tcp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
void tcp_set_keepalive(struct sock *sk, int val);
void tcp_syn_ack_timeout(const struct request_sock *req);
int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
@ -2002,7 +2002,7 @@ struct tcp_sock_af_ops {
const struct sk_buff *skb);
int (*md5_parse)(struct sock *sk,
int optname,
char __user *optval,
sockptr_t optval,
int optlen);
#endif
};

View File

@ -306,7 +306,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
int udp_lib_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen,
sockptr_t optval, unsigned int optlen,
int (*push_pending_frames)(struct sock *));
struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
__be32 daddr, __be16 dport, int dif);

View File

@ -15,6 +15,7 @@
#include <linux/audit.h>
#include <linux/slab.h>
#include <linux/refcount.h>
#include <linux/sockptr.h>
#include <net/sock.h>
#include <net/dst.h>
@ -1609,10 +1610,11 @@ int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu);
int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
int xfrm_user_policy(struct sock *sk, int optname,
u8 __user *optval, int optlen);
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval,
int optlen);
#else
static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
static inline int xfrm_user_policy(struct sock *sk, int optname,
sockptr_t optval, int optlen)
{
return -ENOPROTOOPT;
}

View File

@ -745,7 +745,7 @@ static int check_qos(const struct atm_qos *qos)
}
int vcc_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct atm_vcc *vcc;
unsigned long value;
@ -760,7 +760,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
{
struct atm_qos qos;
if (copy_from_user(&qos, optval, sizeof(qos)))
if (copy_from_sockptr(&qos, optval, sizeof(qos)))
return -EFAULT;
error = check_qos(&qos);
if (error)
@ -774,7 +774,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
return 0;
}
case SO_SETCLP:
if (get_user(value, (unsigned long __user *)optval))
if (copy_from_sockptr(&value, optval, sizeof(value)))
return -EFAULT;
if (value)
vcc->atm_options |= ATM_ATMOPT_CLP;

View File

@ -21,7 +21,7 @@ __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait);
int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int vcc_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen);
sockptr_t optval, unsigned int optlen);
int vcc_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen);
void vcc_process_recv_queue(struct atm_vcc *vcc);

View File

@ -63,7 +63,7 @@ static int pvc_connect(struct socket *sock, struct sockaddr *sockaddr,
}
static int pvc_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;
int error;

View File

@ -451,7 +451,7 @@ int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
}
static int svc_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 atm_vcc *vcc = ATM_SD(sock);
@ -464,7 +464,7 @@ static int svc_setsockopt(struct socket *sock, int level, int optname,
error = -EINVAL;
goto out;
}
if (copy_from_user(&vcc->sap, optval, optlen)) {
if (copy_from_sockptr(&vcc->sap, optval, optlen)) {
error = -EFAULT;
goto out;
}
@ -475,7 +475,7 @@ static int svc_setsockopt(struct socket *sock, int level, int optname,
error = -EINVAL;
goto out;
}
if (get_user(value, (int __user *)optval)) {
if (copy_from_sockptr(&value, optval, sizeof(int))) {
error = -EFAULT;
goto out;
}

View File

@ -528,7 +528,7 @@ ax25_cb *ax25_create_cb(void)
*/
static int ax25_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;
ax25_cb *ax25;
@ -543,7 +543,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(unsigned int))
return -EINVAL;
if (get_user(opt, (unsigned int __user *)optval))
if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
return -EFAULT;
lock_sock(sk);
@ -640,7 +640,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
memset(devname, 0, sizeof(devname));
if (copy_from_user(devname, optval, optlen)) {
if (copy_from_sockptr(devname, optval, optlen)) {
res = -EFAULT;
break;
}

View File

@ -1842,7 +1842,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
}
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int len)
sockptr_t optval, unsigned int len)
{
struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk;
@ -1862,7 +1862,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case HCI_DATA_DIR:
if (get_user(opt, (int __user *)optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(opt))) {
err = -EFAULT;
break;
}
@ -1874,7 +1874,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case HCI_TIME_STAMP:
if (get_user(opt, (int __user *)optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(opt))) {
err = -EFAULT;
break;
}
@ -1896,7 +1896,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
}
len = min_t(unsigned int, len, sizeof(uf));
if (copy_from_user(&uf, optval, len)) {
if (copy_from_sockptr(&uf, optval, len)) {
err = -EFAULT;
break;
}

View File

@ -703,7 +703,7 @@ static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
}
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@ -736,7 +736,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
opts.txwin_size = chan->tx_win;
len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *) &opts, optval, len)) {
if (copy_from_sockptr(&opts, optval, len)) {
err = -EFAULT;
break;
}
@ -782,7 +782,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break;
case L2CAP_LM:
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -859,7 +859,7 @@ static int l2cap_set_mode(struct l2cap_chan *chan, u8 mode)
}
static int l2cap_sock_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 l2cap_chan *chan = l2cap_pi(sk)->chan;
@ -891,7 +891,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
sec.level = BT_SECURITY_LOW;
len = min_t(unsigned int, sizeof(sec), optlen);
if (copy_from_user((char *) &sec, optval, len)) {
if (copy_from_sockptr(&sec, optval, len)) {
err = -EFAULT;
break;
}
@ -939,7 +939,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -954,7 +954,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_FLUSHABLE:
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -990,7 +990,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
len = min_t(unsigned int, sizeof(pwr), optlen);
if (copy_from_user((char *) &pwr, optval, len)) {
if (copy_from_sockptr(&pwr, optval, len)) {
err = -EFAULT;
break;
}
@ -1002,7 +1002,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_CHANNEL_POLICY:
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -1050,7 +1050,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u16 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
err = -EFAULT;
break;
}
@ -1081,7 +1081,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u8 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u8))) {
err = -EFAULT;
break;
}

View File

@ -644,7 +644,8 @@ static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg,
return len;
}
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err = 0;
@ -656,7 +657,7 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
switch (optname) {
case RFCOMM_LM:
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -685,7 +686,8 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
return err;
}
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct bt_security sec;
@ -713,7 +715,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
sec.level = BT_SECURITY_LOW;
len = min_t(unsigned int, sizeof(sec), optlen);
if (copy_from_user((char *) &sec, optval, len)) {
if (copy_from_sockptr(&sec, optval, len)) {
err = -EFAULT;
break;
}
@ -732,7 +734,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
break;
}
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}

View File

@ -791,7 +791,7 @@ static int sco_sock_recvmsg(struct socket *sock, struct msghdr *msg,
}
static int sco_sock_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;
int len, err = 0;
@ -810,7 +810,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -831,7 +831,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
voice.setting = sco_pi(sk)->setting;
len = min_t(unsigned int, sizeof(voice), optlen);
if (copy_from_user((char *)&voice, optval, len)) {
if (copy_from_sockptr(&voice, optval, len)) {
err = -EFAULT;
break;
}

View File

@ -31,48 +31,55 @@ static void __stop_umh(void)
shutdown_umh();
}
static int __bpfilter_process_sockopt(struct sock *sk, int optname,
char __user *optval,
unsigned int optlen, bool is_set)
static int bpfilter_send_req(struct mbox_request *req)
{
struct mbox_request req;
struct mbox_reply reply;
loff_t pos;
ssize_t n;
int ret = -EFAULT;
req.is_set = is_set;
req.pid = current->pid;
req.cmd = optname;
req.addr = (long __force __user)optval;
req.len = optlen;
if (!bpfilter_ops.info.tgid)
goto out;
return -EFAULT;
pos = 0;
n = kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
&pos);
if (n != sizeof(req)) {
if (n != sizeof(*req)) {
pr_err("write fail %zd\n", n);
__stop_umh();
ret = -EFAULT;
goto out;
goto stop;
}
pos = 0;
n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
&pos);
if (n != sizeof(reply)) {
pr_err("read fail %zd\n", n);
__stop_umh();
ret = -EFAULT;
goto out;
goto stop;
}
ret = reply.status;
out:
return ret;
return reply.status;
stop:
__stop_umh();
return -EFAULT;
}
static int bpfilter_process_sockopt(struct sock *sk, int optname,
sockptr_t optval, unsigned int optlen,
bool is_set)
{
struct mbox_request req = {
.is_set = is_set,
.pid = current->pid,
.cmd = optname,
.addr = (uintptr_t)optval.user,
.len = optlen,
};
if (uaccess_kernel() || sockptr_is_kernel(optval)) {
pr_err("kernel access not supported\n");
return -EFAULT;
}
return bpfilter_send_req(&req);
}
static int start_umh(void)
{
struct mbox_request req = { .pid = current->pid };
int err;
/* fork usermode process */
@ -82,7 +89,7 @@ static int start_umh(void)
pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
/* health check that usermode process started correctly */
if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {
if (bpfilter_send_req(&req) != 0) {
shutdown_umh();
return -EFAULT;
}
@ -103,7 +110,7 @@ static int __init load_umh(void)
mutex_lock(&bpfilter_ops.lock);
err = start_umh();
if (!err && IS_ENABLED(CONFIG_INET)) {
bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
bpfilter_ops.sockopt = &bpfilter_process_sockopt;
bpfilter_ops.start = &start_umh;
}
mutex_unlock(&bpfilter_ops.lock);

View File

@ -1063,14 +1063,13 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
}
/* replace the table */
static int do_replace(struct net *net, const void __user *user,
unsigned int len)
static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret, countersize;
struct ebt_table_info *newinfo;
struct ebt_replace tmp;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
if (len != sizeof(tmp) + tmp.entries_size)
@ -1242,9 +1241,8 @@ void ebt_unregister_table(struct net *net, struct ebt_table *table,
/* userspace just supplied us with counters */
static int do_update_counters(struct net *net, const char *name,
struct ebt_counter __user *counters,
unsigned int num_counters,
const void __user *user, unsigned int len)
struct ebt_counter __user *counters,
unsigned int num_counters, unsigned int len)
{
int i, ret;
struct ebt_counter *tmp;
@ -1287,19 +1285,18 @@ static int do_update_counters(struct net *net, const char *name,
return ret;
}
static int update_counters(struct net *net, const void __user *user,
unsigned int len)
static int update_counters(struct net *net, sockptr_t arg, unsigned int len)
{
struct ebt_replace hlp;
if (copy_from_user(&hlp, user, sizeof(hlp)))
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;
if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
return -EINVAL;
return do_update_counters(net, hlp.name, hlp.counters,
hlp.num_counters, user, len);
hlp.num_counters, len);
}
static inline int ebt_obj_to_user(char __user *um, const char *_name,
@ -2080,7 +2077,7 @@ static int compat_copy_entries(unsigned char *data, unsigned int size_user,
static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
void __user *user, unsigned int len)
sockptr_t arg, unsigned int len)
{
struct compat_ebt_replace tmp;
int i;
@ -2088,7 +2085,7 @@ static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
if (len < sizeof(tmp))
return -EINVAL;
if (copy_from_user(&tmp, user, sizeof(tmp)))
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)))
return -EFAULT;
if (len != sizeof(tmp) + tmp.entries_size)
@ -2115,8 +2112,7 @@ static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
return 0;
}
static int compat_do_replace(struct net *net, void __user *user,
unsigned int len)
static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret, i, countersize, size64;
struct ebt_table_info *newinfo;
@ -2124,10 +2120,10 @@ static int compat_do_replace(struct net *net, void __user *user,
struct ebt_entries_buf_state state;
void *entries_tmp;
ret = compat_copy_ebt_replace_from_user(&tmp, user, len);
ret = compat_copy_ebt_replace_from_user(&tmp, arg, len);
if (ret) {
/* try real handler in case userland supplied needed padding */
if (ret == -EINVAL && do_replace(net, user, len) == 0)
if (ret == -EINVAL && do_replace(net, arg, len) == 0)
ret = 0;
return ret;
}
@ -2218,20 +2214,20 @@ static int compat_do_replace(struct net *net, void __user *user,
goto free_entries;
}
static int compat_update_counters(struct net *net, void __user *user,
static int compat_update_counters(struct net *net, sockptr_t arg,
unsigned int len)
{
struct compat_ebt_replace hlp;
if (copy_from_user(&hlp, user, sizeof(hlp)))
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;
/* try real handler in case userland supplied needed padding */
if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
return update_counters(net, user, len);
return update_counters(net, arg, len);
return do_update_counters(net, hlp.name, compat_ptr(hlp.counters),
hlp.num_counters, user, len);
hlp.num_counters, len);
}
static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
@ -2369,7 +2365,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
return ret;
}
static int do_ebt_set_ctl(struct sock *sk, int cmd, void __user *user,
static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
unsigned int len)
{
struct net *net = sock_net(sk);
@ -2382,18 +2378,18 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, void __user *user,
case EBT_SO_SET_ENTRIES:
#ifdef CONFIG_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(net, user, len);
ret = compat_do_replace(net, arg, len);
else
#endif
ret = do_replace(net, user, len);
ret = do_replace(net, arg, len);
break;
case EBT_SO_SET_COUNTERS:
#ifdef CONFIG_COMPAT
if (in_compat_syscall())
ret = compat_update_counters(net, user, len);
ret = compat_update_counters(net, arg, len);
else
#endif
ret = update_counters(net, user, len);
ret = update_counters(net, arg, len);
break;
default:
ret = -EINVAL;

View File

@ -669,8 +669,8 @@ static int caif_stream_sendmsg(struct socket *sock, struct msghdr *msg,
return sent ? : err;
}
static int setsockopt(struct socket *sock,
int lvl, int opt, char __user *ov, unsigned int ol)
static int setsockopt(struct socket *sock, int lvl, int opt, sockptr_t ov,
unsigned int ol)
{
struct sock *sk = sock->sk;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
@ -685,7 +685,7 @@ static int setsockopt(struct socket *sock,
return -EINVAL;
if (lvl != SOL_CAIF)
goto bad_sol;
if (copy_from_user(&linksel, ov, sizeof(int)))
if (copy_from_sockptr(&linksel, ov, sizeof(int)))
return -EINVAL;
lock_sock(&(cf_sk->sk));
cf_sk->conn_req.link_selector = linksel;
@ -699,7 +699,7 @@ static int setsockopt(struct socket *sock,
return -ENOPROTOOPT;
lock_sock(&(cf_sk->sk));
if (ol > sizeof(cf_sk->conn_req.param.data) ||
copy_from_user(&cf_sk->conn_req.param.data, ov, ol)) {
copy_from_sockptr(&cf_sk->conn_req.param.data, ov, ol)) {
release_sock(&cf_sk->sk);
return -EINVAL;
}

View File

@ -627,14 +627,14 @@ static int j1939_sk_release(struct socket *sock)
return 0;
}
static int j1939_sk_setsockopt_flag(struct j1939_sock *jsk, char __user *optval,
static int j1939_sk_setsockopt_flag(struct j1939_sock *jsk, sockptr_t optval,
unsigned int optlen, int flag)
{
int tmp;
if (optlen != sizeof(tmp))
return -EINVAL;
if (copy_from_user(&tmp, optval, optlen))
if (copy_from_sockptr(&tmp, optval, optlen))
return -EFAULT;
lock_sock(&jsk->sk);
if (tmp)
@ -646,7 +646,7 @@ static int j1939_sk_setsockopt_flag(struct j1939_sock *jsk, char __user *optval,
}
static int j1939_sk_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 j1939_sock *jsk = j1939_sk(sk);
@ -658,7 +658,7 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case SO_J1939_FILTER:
if (optval) {
if (!sockptr_is_null(optval)) {
struct j1939_filter *f;
int c;
@ -670,7 +670,7 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
return -EINVAL;
count = optlen / sizeof(*filters);
filters = memdup_user(optval, optlen);
filters = memdup_sockptr(optval, optlen);
if (IS_ERR(filters))
return PTR_ERR(filters);
@ -703,7 +703,7 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname,
case SO_J1939_SEND_PRIO:
if (optlen != sizeof(tmp))
return -EINVAL;
if (copy_from_user(&tmp, optval, optlen))
if (copy_from_sockptr(&tmp, optval, optlen))
return -EFAULT;
if (tmp < 0 || tmp > 7)
return -EDOM;

View File

@ -485,7 +485,7 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
}
static int raw_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 raw_sock *ro = raw_sk(sk);
@ -511,11 +511,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
filter = memdup_user(optval, optlen);
filter = memdup_sockptr(optval, optlen);
if (IS_ERR(filter))
return PTR_ERR(filter);
} else if (count == 1) {
if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
if (copy_from_sockptr(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
}
@ -568,7 +568,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(err_mask))
return -EINVAL;
if (copy_from_user(&err_mask, optval, optlen))
if (copy_from_sockptr(&err_mask, optval, optlen))
return -EFAULT;
err_mask &= CAN_ERR_MASK;
@ -607,7 +607,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->loopback))
return -EINVAL;
if (copy_from_user(&ro->loopback, optval, optlen))
if (copy_from_sockptr(&ro->loopback, optval, optlen))
return -EFAULT;
break;
@ -616,7 +616,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->recv_own_msgs))
return -EINVAL;
if (copy_from_user(&ro->recv_own_msgs, optval, optlen))
if (copy_from_sockptr(&ro->recv_own_msgs, optval, optlen))
return -EFAULT;
break;
@ -625,7 +625,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->fd_frames))
return -EINVAL;
if (copy_from_user(&ro->fd_frames, optval, optlen))
if (copy_from_sockptr(&ro->fd_frames, optval, optlen))
return -EFAULT;
break;
@ -634,7 +634,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->join_filters))
return -EINVAL;
if (copy_from_user(&ro->join_filters, optval, optlen))
if (copy_from_sockptr(&ro->join_filters, optval, optlen))
return -EFAULT;
break;

View File

@ -77,14 +77,14 @@
#include <net/transp_v6.h>
#include <linux/btf_ids.h>
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)
{
if (in_compat_syscall()) {
struct compat_sock_fprog f32;
if (len != sizeof(f32))
return -EINVAL;
if (copy_from_user(&f32, src, sizeof(f32)))
if (copy_from_sockptr(&f32, src, sizeof(f32)))
return -EFAULT;
memset(dst, 0, sizeof(*dst));
dst->len = f32.len;
@ -92,7 +92,7 @@ int copy_bpf_fprog_from_user(struct sock_fprog *dst, void __user *src, int len)
} else {
if (len != sizeof(*dst))
return -EINVAL;
if (copy_from_user(dst, src, sizeof(*dst)))
if (copy_from_sockptr(dst, src, sizeof(*dst)))
return -EFAULT;
}

View File

@ -361,7 +361,8 @@ static int sock_get_timeout(long timeo, void *optval, bool old_timeval)
return sizeof(tv);
}
static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool old_timeval)
static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen,
bool old_timeval)
{
struct __kernel_sock_timeval tv;
@ -371,7 +372,7 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool
if (optlen < sizeof(tv32))
return -EINVAL;
if (copy_from_user(&tv32, optval, sizeof(tv32)))
if (copy_from_sockptr(&tv32, optval, sizeof(tv32)))
return -EFAULT;
tv.tv_sec = tv32.tv_sec;
tv.tv_usec = tv32.tv_usec;
@ -380,14 +381,14 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool
if (optlen < sizeof(old_tv))
return -EINVAL;
if (copy_from_user(&old_tv, optval, sizeof(old_tv)))
if (copy_from_sockptr(&old_tv, optval, sizeof(old_tv)))
return -EFAULT;
tv.tv_sec = old_tv.tv_sec;
tv.tv_usec = old_tv.tv_usec;
} else {
if (optlen < sizeof(tv))
return -EINVAL;
if (copy_from_user(&tv, optval, sizeof(tv)))
if (copy_from_sockptr(&tv, optval, sizeof(tv)))
return -EFAULT;
}
if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC)
@ -609,8 +610,7 @@ int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk)
}
EXPORT_SYMBOL(sock_bindtoindex);
static int sock_setbindtodevice(struct sock *sk, char __user *optval,
int optlen)
static int sock_setbindtodevice(struct sock *sk, sockptr_t optval, int optlen)
{
int ret = -ENOPROTOOPT;
#ifdef CONFIG_NETDEVICES
@ -632,7 +632,7 @@ static int sock_setbindtodevice(struct sock *sk, char __user *optval,
memset(devname, 0, sizeof(devname));
ret = -EFAULT;
if (copy_from_user(devname, optval, optlen))
if (copy_from_sockptr(devname, optval, optlen))
goto out;
index = 0;
@ -826,7 +826,7 @@ EXPORT_SYMBOL(sock_set_rcvbuf);
*/
int sock_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct sock_txtime sk_txtime;
struct sock *sk = sock->sk;
@ -845,7 +845,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
valbool = val ? 1 : 0;
@ -958,7 +958,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
ret = -EINVAL; /* 1003.1g */
break;
}
if (copy_from_user(&ling, optval, sizeof(ling))) {
if (copy_from_sockptr(&ling, optval, sizeof(ling))) {
ret = -EFAULT;
break;
}
@ -1052,12 +1052,14 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
case SO_RCVTIMEO_OLD:
case SO_RCVTIMEO_NEW:
ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen, optname == SO_RCVTIMEO_OLD);
ret = sock_set_timeout(&sk->sk_rcvtimeo, optval,
optlen, optname == SO_RCVTIMEO_OLD);
break;
case SO_SNDTIMEO_OLD:
case SO_SNDTIMEO_NEW:
ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen, optname == SO_SNDTIMEO_OLD);
ret = sock_set_timeout(&sk->sk_sndtimeo, optval,
optlen, optname == SO_SNDTIMEO_OLD);
break;
case SO_ATTACH_FILTER: {
@ -1074,7 +1076,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
u32 ufd;
ret = -EFAULT;
if (copy_from_user(&ufd, optval, sizeof(ufd)))
if (copy_from_sockptr(&ufd, optval, sizeof(ufd)))
break;
ret = sk_attach_bpf(ufd, sk);
@ -1095,7 +1097,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
u32 ufd;
ret = -EFAULT;
if (copy_from_user(&ufd, optval, sizeof(ufd)))
if (copy_from_sockptr(&ufd, optval, sizeof(ufd)))
break;
ret = sk_reuseport_attach_bpf(ufd, sk);
@ -1175,7 +1177,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
if (sizeof(ulval) != sizeof(val) &&
optlen >= sizeof(ulval) &&
get_user(ulval, (unsigned long __user *)optval)) {
copy_from_sockptr(&ulval, optval, sizeof(ulval))) {
ret = -EFAULT;
break;
}
@ -1218,7 +1220,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(struct sock_txtime)) {
ret = -EINVAL;
break;
} else if (copy_from_user(&sk_txtime, optval,
} else if (copy_from_sockptr(&sk_txtime, optval,
sizeof(struct sock_txtime))) {
ret = -EFAULT;
break;
@ -3209,7 +3211,7 @@ EXPORT_SYMBOL(sock_common_recvmsg);
* Set socket options on an inet socket.
*/
int sock_common_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;

View File

@ -295,7 +295,7 @@ int dccp_disconnect(struct sock *sk, int flags);
int dccp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int dccp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
sockptr_t optval, unsigned int optlen);
int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg);
int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,

View File

@ -411,7 +411,7 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
EXPORT_SYMBOL_GPL(dccp_ioctl);
static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_service_list *sl = NULL;
@ -426,9 +426,9 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
return -ENOMEM;
sl->dccpsl_nr = optlen / sizeof(u32) - 1;
if (copy_from_user(sl->dccpsl_list,
optval + sizeof(service),
optlen - sizeof(service)) ||
sockptr_advance(optval, sizeof(service));
if (copy_from_sockptr(sl->dccpsl_list, optval,
optlen - sizeof(service)) ||
dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
kfree(sl);
return -EFAULT;
@ -482,7 +482,7 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
}
static int dccp_setsockopt_ccid(struct sock *sk, int type,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
u8 *val;
int rc = 0;
@ -490,7 +490,7 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
return -EINVAL;
val = memdup_user(optval, optlen);
val = memdup_sockptr(optval, optlen);
if (IS_ERR(val))
return PTR_ERR(val);
@ -507,7 +507,7 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
}
static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct dccp_sock *dp = dccp_sk(sk);
int val, err = 0;
@ -529,7 +529,7 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
if (optlen < (int)sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
if (optname == DCCP_SOCKOPT_SERVICE)
@ -572,8 +572,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
return err;
}
int dccp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
int dccp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
if (level != SOL_DCCP)
return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,

View File

@ -150,7 +150,8 @@ static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
static struct hlist_head dn_wild_sk;
static atomic_long_t decnet_memory_allocated;
static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen, int flags);
static int __dn_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen, int flags);
static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags);
static struct hlist_head *dn_find_list(struct sock *sk)
@ -1320,7 +1321,8 @@ static int dn_shutdown(struct socket *sock, int how)
return err;
}
static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
static int dn_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err;
@ -1338,7 +1340,8 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
return err;
}
static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, unsigned int optlen, int flags)
static int __dn_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen, int flags)
{
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
@ -1354,13 +1357,13 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
} u;
int err;
if (optlen && !optval)
if (optlen && sockptr_is_null(optval))
return -EINVAL;
if (optlen > sizeof(u))
return -EINVAL;
if (copy_from_user(&u, optval, optlen))
if (copy_from_sockptr(&u, optval, optlen))
return -EFAULT;
switch (optname) {

View File

@ -382,7 +382,7 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
}
static int raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
return -EOPNOTSUPP;
}
@ -872,7 +872,7 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
}
static int dgram_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct dgram_sock *ro = dgram_sk(sk);
struct net *net = sock_net(sk);
@ -882,7 +882,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
lock_sock(sk);

View File

@ -21,8 +21,7 @@ void bpfilter_umh_cleanup(struct umd_info *info)
}
EXPORT_SYMBOL_GPL(bpfilter_umh_cleanup);
static int bpfilter_mbox_request(struct sock *sk, int optname,
char __user *optval,
static int bpfilter_mbox_request(struct sock *sk, int optname, sockptr_t optval,
unsigned int optlen, bool is_set)
{
int err;
@ -52,20 +51,23 @@ static int bpfilter_mbox_request(struct sock *sk, int optname,
return err;
}
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)
{
return bpfilter_mbox_request(sk, optname, optval, optlen, true);
}
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
int __user *optlen)
int bpfilter_ip_get_sockopt(struct sock *sk, int optname,
char __user *user_optval, int __user *optlen)
{
int len;
sockptr_t optval;
int err, len;
if (get_user(len, optlen))
return -EFAULT;
err = init_user_sockptr(&optval, user_optval);
if (err)
return err;
return bpfilter_mbox_request(sk, optname, optval, len, false);
}

View File

@ -519,15 +519,20 @@ void ip_options_undo(struct ip_options *opt)
}
}
static struct ip_options_rcu *ip_options_get_alloc(const int optlen)
int ip_options_get(struct net *net, struct ip_options_rcu **optp,
sockptr_t data, int optlen)
{
return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
GFP_KERNEL);
}
struct ip_options_rcu *opt;
opt = kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
GFP_KERNEL);
if (!opt)
return -ENOMEM;
if (optlen && copy_from_sockptr(opt->opt.__data, data, optlen)) {
kfree(opt);
return -EFAULT;
}
static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp,
struct ip_options_rcu *opt, int optlen)
{
while (optlen & 3)
opt->opt.__data[optlen++] = IPOPT_END;
opt->opt.optlen = optlen;
@ -540,32 +545,6 @@ static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp,
return 0;
}
int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp,
unsigned char __user *data, int optlen)
{
struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
if (!opt)
return -ENOMEM;
if (optlen && copy_from_user(opt->opt.__data, data, optlen)) {
kfree(opt);
return -EFAULT;
}
return ip_options_get_finish(net, optp, opt, optlen);
}
int ip_options_get(struct net *net, struct ip_options_rcu **optp,
unsigned char *data, int optlen)
{
struct ip_options_rcu *opt = ip_options_get_alloc(optlen);
if (!opt)
return -ENOMEM;
if (optlen)
memcpy(opt->opt.__data, data, optlen);
return ip_options_get_finish(net, optp, opt, optlen);
}
void ip_forward_options(struct sk_buff *skb)
{
struct ip_options *opt = &(IPCB(skb)->opt);

View File

@ -280,7 +280,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
err = cmsg->cmsg_len - sizeof(struct cmsghdr);
/* Our caller is responsible for freeing ipc->opt */
err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
err = ip_options_get(net, &ipc->opt,
KERNEL_SOCKPTR(CMSG_DATA(cmsg)),
err < 40 ? err : 40);
if (err)
return err;
@ -682,15 +683,15 @@ static int set_mcast_msfilter(struct sock *sk, int ifindex,
return -EADDRNOTAVAIL;
}
static int copy_group_source_from_user(struct group_source_req *greqs,
void __user *optval, int optlen)
static int copy_group_source_from_sockptr(struct group_source_req *greqs,
sockptr_t optval, int optlen)
{
if (in_compat_syscall()) {
struct compat_group_source_req gr32;
if (optlen != sizeof(gr32))
return -EINVAL;
if (copy_from_user(&gr32, optval, sizeof(gr32)))
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
return -EFAULT;
greqs->gsr_interface = gr32.gsr_interface;
greqs->gsr_group = gr32.gsr_group;
@ -698,7 +699,7 @@ static int copy_group_source_from_user(struct group_source_req *greqs,
} else {
if (optlen != sizeof(*greqs))
return -EINVAL;
if (copy_from_user(greqs, optval, sizeof(*greqs)))
if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
return -EFAULT;
}
@ -706,14 +707,14 @@ static int copy_group_source_from_user(struct group_source_req *greqs,
}
static int do_mcast_group_source(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct group_source_req greqs;
struct ip_mreq_source mreqs;
struct sockaddr_in *psin;
int omode, add, err;
err = copy_group_source_from_user(&greqs, optval, optlen);
err = copy_group_source_from_sockptr(&greqs, optval, optlen);
if (err)
return err;
@ -753,8 +754,7 @@ static int do_mcast_group_source(struct sock *sk, int optname,
return ip_mc_source(add, omode, sk, &mreqs, greqs.gsr_interface);
}
static int ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
int optlen)
static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
{
struct group_filter *gsf = NULL;
int err;
@ -764,7 +764,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
if (optlen > sysctl_optmem_max)
return -ENOBUFS;
gsf = memdup_user(optval, optlen);
gsf = memdup_sockptr(optval, optlen);
if (IS_ERR(gsf))
return PTR_ERR(gsf);
@ -785,7 +785,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
return err;
}
static int compat_ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
int optlen)
{
const int size0 = offsetof(struct compat_group_filter, gf_slist);
@ -805,7 +805,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
err = -EFAULT;
if (copy_from_user(gf32, optval, optlen))
if (copy_from_sockptr(gf32, optval, optlen))
goto out_free_gsf;
/* numsrc >= (4G-140)/128 overflow in 32 bits */
@ -830,7 +830,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
}
static int ip_mcast_join_leave(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct ip_mreqn mreq = { };
struct sockaddr_in *psin;
@ -838,7 +838,7 @@ static int ip_mcast_join_leave(struct sock *sk, int optname,
if (optlen < sizeof(struct group_req))
return -EINVAL;
if (copy_from_user(&greq, optval, sizeof(greq)))
if (copy_from_sockptr(&greq, optval, sizeof(greq)))
return -EFAULT;
psin = (struct sockaddr_in *)&greq.gr_group;
@ -852,7 +852,7 @@ static int ip_mcast_join_leave(struct sock *sk, int optname,
}
static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct compat_group_req greq;
struct ip_mreqn mreq = { };
@ -860,7 +860,7 @@ static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
if (optlen < sizeof(struct compat_group_req))
return -EINVAL;
if (copy_from_user(&greq, optval, sizeof(greq)))
if (copy_from_sockptr(&greq, optval, sizeof(greq)))
return -EFAULT;
psin = (struct sockaddr_in *)&greq.gr_group;
@ -874,8 +874,8 @@ static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
return ip_mc_leave_group(sk, &mreq);
}
static int do_ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, unsigned int optlen)
static int do_ip_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct inet_sock *inet = inet_sk(sk);
struct net *net = sock_net(sk);
@ -909,12 +909,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
case IP_RECVFRAGSIZE:
case IP_RECVERR_RFC4884:
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
} else if (optlen >= sizeof(char)) {
unsigned char ucval;
if (get_user(ucval, (unsigned char __user *) optval))
if (copy_from_sockptr(&ucval, optval, sizeof(ucval)))
return -EFAULT;
val = (int) ucval;
}
@ -939,8 +939,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
if (optlen > 40)
goto e_inval;
err = ip_options_get_from_user(sock_net(sk), &opt,
optval, optlen);
err = ip_options_get(sock_net(sk), &opt, optval, optlen);
if (err)
break;
old = rcu_dereference_protected(inet->inet_opt,
@ -1138,17 +1137,17 @@ static int do_ip_setsockopt(struct sock *sk, int level,
err = -EFAULT;
if (optlen >= sizeof(struct ip_mreqn)) {
if (copy_from_user(&mreq, optval, sizeof(mreq)))
if (copy_from_sockptr(&mreq, optval, sizeof(mreq)))
break;
} else {
memset(&mreq, 0, sizeof(mreq));
if (optlen >= sizeof(struct ip_mreq)) {
if (copy_from_user(&mreq, optval,
sizeof(struct ip_mreq)))
if (copy_from_sockptr(&mreq, optval,
sizeof(struct ip_mreq)))
break;
} else if (optlen >= sizeof(struct in_addr)) {
if (copy_from_user(&mreq.imr_address, optval,
sizeof(struct in_addr)))
if (copy_from_sockptr(&mreq.imr_address, optval,
sizeof(struct in_addr)))
break;
}
}
@ -1200,11 +1199,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
goto e_inval;
err = -EFAULT;
if (optlen >= sizeof(struct ip_mreqn)) {
if (copy_from_user(&mreq, optval, sizeof(mreq)))
if (copy_from_sockptr(&mreq, optval, sizeof(mreq)))
break;
} else {
memset(&mreq, 0, sizeof(mreq));
if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
if (copy_from_sockptr(&mreq, optval,
sizeof(struct ip_mreq)))
break;
}
@ -1224,7 +1224,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
err = -ENOBUFS;
break;
}
msf = memdup_user(optval, optlen);
msf = memdup_sockptr(optval, optlen);
if (IS_ERR(msf)) {
err = PTR_ERR(msf);
break;
@ -1255,7 +1255,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
if (optlen != sizeof(struct ip_mreq_source))
goto e_inval;
if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
if (copy_from_sockptr(&mreqs, optval, sizeof(mreqs))) {
err = -EFAULT;
break;
}
@ -1401,8 +1401,8 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
skb_dst_drop(skb);
}
int ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, unsigned int optlen)
int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
int err;

View File

@ -1341,7 +1341,7 @@ static void mrtsock_destruct(struct sock *sk)
* MOSPF/PIM router set up we can clean this up.
*/
int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
unsigned int optlen)
{
struct net *net = sock_net(sk);
@ -1413,7 +1413,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (copy_from_user(&vif, optval, sizeof(vif))) {
if (copy_from_sockptr(&vif, optval, sizeof(vif))) {
ret = -EFAULT;
break;
}
@ -1441,7 +1441,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (copy_from_user(&mfc, optval, sizeof(mfc))) {
if (copy_from_sockptr(&val, optval, sizeof(val))) {
ret = -EFAULT;
break;
}
@ -1459,7 +1459,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (get_user(val, (int __user *)optval)) {
if (copy_from_sockptr(&val, optval, sizeof(val))) {
ret = -EFAULT;
break;
}
@ -1471,7 +1471,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (get_user(val, (int __user *)optval)) {
if (copy_from_sockptr(&val, optval, sizeof(val))) {
ret = -EFAULT;
break;
}
@ -1486,7 +1486,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (get_user(val, (int __user *)optval)) {
if (copy_from_sockptr(&val, optval, sizeof(val))) {
ret = -EFAULT;
break;
}
@ -1508,7 +1508,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
ret = -EINVAL;
break;
}
if (get_user(uval, (u32 __user *)optval)) {
if (copy_from_sockptr(&uval, optval, sizeof(uval))) {
ret = -EFAULT;
break;
}

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Packet matching code for ARP packets.
*
@ -947,8 +947,7 @@ static int __do_replace(struct net *net, const char *name,
return ret;
}
static int do_replace(struct net *net, const void __user *user,
unsigned int len)
static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct arpt_replace tmp;
@ -956,7 +955,7 @@ static int do_replace(struct net *net, const void __user *user,
void *loc_cpu_entry;
struct arpt_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -972,8 +971,8 @@ static int do_replace(struct net *net, const void __user *user,
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -996,8 +995,7 @@ static int do_replace(struct net *net, const void __user *user,
return ret;
}
static int do_add_counters(struct net *net, const void __user *user,
unsigned int len)
static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
{
unsigned int i;
struct xt_counters_info tmp;
@ -1008,7 +1006,7 @@ static int do_add_counters(struct net *net, const void __user *user,
struct arpt_entry *iter;
unsigned int addend;
paddc = xt_copy_counters_from_user(user, len, &tmp);
paddc = xt_copy_counters(arg, len, &tmp);
if (IS_ERR(paddc))
return PTR_ERR(paddc);
@ -1245,8 +1243,7 @@ static int translate_compat_table(struct net *net,
return ret;
}
static int compat_do_replace(struct net *net, void __user *user,
unsigned int len)
static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct compat_arpt_replace tmp;
@ -1254,7 +1251,7 @@ static int compat_do_replace(struct net *net, void __user *user,
void *loc_cpu_entry;
struct arpt_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -1270,7 +1267,8 @@ static int compat_do_replace(struct net *net, void __user *user,
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -1402,7 +1400,8 @@ static int compat_get_entries(struct net *net,
}
#endif
static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
unsigned int len)
{
int ret;
@ -1413,14 +1412,14 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
case ARPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), user, len);
ret = compat_do_replace(sock_net(sk), arg, len);
else
#endif
ret = do_replace(sock_net(sk), user, len);
ret = do_replace(sock_net(sk), arg, len);
break;
case ARPT_SO_SET_ADD_COUNTERS:
ret = do_add_counters(sock_net(sk), user, len);
ret = do_add_counters(sock_net(sk), arg, len);
break;
default:

View File

@ -1102,7 +1102,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
do_replace(struct net *net, const void __user *user, unsigned int len)
do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct ipt_replace tmp;
@ -1110,7 +1110,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
void *loc_cpu_entry;
struct ipt_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -1126,8 +1126,8 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -1151,8 +1151,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
}
static int
do_add_counters(struct net *net, const void __user *user,
unsigned int len)
do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
{
unsigned int i;
struct xt_counters_info tmp;
@ -1163,7 +1162,7 @@ do_add_counters(struct net *net, const void __user *user,
struct ipt_entry *iter;
unsigned int addend;
paddc = xt_copy_counters_from_user(user, len, &tmp);
paddc = xt_copy_counters(arg, len, &tmp);
if (IS_ERR(paddc))
return PTR_ERR(paddc);
@ -1485,7 +1484,7 @@ translate_compat_table(struct net *net,
}
static int
compat_do_replace(struct net *net, void __user *user, unsigned int len)
compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct compat_ipt_replace tmp;
@ -1493,7 +1492,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
void *loc_cpu_entry;
struct ipt_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -1509,8 +1508,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -1611,7 +1610,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
#endif
static int
do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
{
int ret;
@ -1622,14 +1621,14 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
case IPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), user, len);
ret = compat_do_replace(sock_net(sk), arg, len);
else
#endif
ret = do_replace(sock_net(sk), user, len);
ret = do_replace(sock_net(sk), arg, len);
break;
case IPT_SO_SET_ADD_COUNTERS:
ret = do_add_counters(sock_net(sk), user, len);
ret = do_add_counters(sock_net(sk), arg, len);
break;
default:

View File

@ -809,11 +809,11 @@ static int raw_sk_init(struct sock *sk)
return 0;
}
static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen)
static int raw_seticmpfilter(struct sock *sk, sockptr_t optval, int optlen)
{
if (optlen > sizeof(struct icmp_filter))
optlen = sizeof(struct icmp_filter);
if (copy_from_user(&raw_sk(sk)->filter, optval, optlen))
if (copy_from_sockptr(&raw_sk(sk)->filter, optval, optlen))
return -EFAULT;
return 0;
}
@ -838,7 +838,7 @@ out: return ret;
}
static int do_raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
@ -850,7 +850,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname,
}
static int raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
if (level != SOL_RAW)
return ip_setsockopt(sk, level, optname, optval, optlen);

View File

@ -2764,7 +2764,7 @@ static inline bool tcp_can_repair_sock(const struct sock *sk)
(sk->sk_state != TCP_LISTEN);
}
static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len)
static int tcp_repair_set_window(struct tcp_sock *tp, sockptr_t optbuf, int len)
{
struct tcp_repair_window opt;
@ -2774,7 +2774,7 @@ static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int l
if (len != sizeof(opt))
return -EINVAL;
if (copy_from_user(&opt, optbuf, sizeof(opt)))
if (copy_from_sockptr(&opt, optbuf, sizeof(opt)))
return -EFAULT;
if (opt.max_window < opt.snd_wnd)
@ -2796,17 +2796,17 @@ static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int l
return 0;
}
static int tcp_repair_options_est(struct sock *sk,
struct tcp_repair_opt __user *optbuf, unsigned int len)
static int tcp_repair_options_est(struct sock *sk, sockptr_t optbuf,
unsigned int len)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_repair_opt opt;
while (len >= sizeof(opt)) {
if (copy_from_user(&opt, optbuf, sizeof(opt)))
if (copy_from_sockptr(&opt, optbuf, sizeof(opt)))
return -EFAULT;
optbuf++;
sockptr_advance(optbuf, sizeof(opt));
len -= sizeof(opt);
switch (opt.opt_code) {
@ -3020,8 +3020,8 @@ EXPORT_SYMBOL(tcp_sock_set_keepcnt);
/*
* Socket option code for TCP.
*/
static int do_tcp_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, unsigned int optlen)
static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
@ -3037,7 +3037,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (optlen < 1)
return -EINVAL;
val = strncpy_from_user(name, optval,
val = strncpy_from_sockptr(name, optval,
min_t(long, TCP_CA_NAME_MAX-1, optlen));
if (val < 0)
return -EFAULT;
@ -3056,7 +3056,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (optlen < 1)
return -EINVAL;
val = strncpy_from_user(name, optval,
val = strncpy_from_sockptr(name, optval,
min_t(long, TCP_ULP_NAME_MAX - 1,
optlen));
if (val < 0)
@ -3079,7 +3079,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
optlen != TCP_FASTOPEN_KEY_BUF_LENGTH)
return -EINVAL;
if (copy_from_user(key, optval, optlen))
if (copy_from_sockptr(key, optval, optlen))
return -EFAULT;
if (optlen == TCP_FASTOPEN_KEY_BUF_LENGTH)
@ -3095,7 +3095,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3174,9 +3174,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (!tp->repair)
err = -EINVAL;
else if (sk->sk_state == TCP_ESTABLISHED)
err = tcp_repair_options_est(sk,
(struct tcp_repair_opt __user *)optval,
optlen);
err = tcp_repair_options_est(sk, optval, optlen);
else
err = -EPERM;
break;
@ -3325,7 +3323,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
return err;
}
int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
const struct inet_connection_sock *icsk = inet_csk(sk);

View File

@ -1195,7 +1195,7 @@ static void tcp_clear_md5_list(struct sock *sk)
}
static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
char __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct tcp_md5sig cmd;
struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr;
@ -1206,7 +1206,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
if (optlen < sizeof(cmd))
return -EINVAL;
if (copy_from_user(&cmd, optval, sizeof(cmd)))
if (copy_from_sockptr(&cmd, optval, sizeof(cmd)))
return -EFAULT;
if (sin->sin_family != AF_INET)

View File

@ -2588,7 +2588,7 @@ void udp_destroy_sock(struct sock *sk)
* Socket option code for UDP
*/
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen,
sockptr_t optval, unsigned int optlen,
int (*push_pending_frames)(struct sock *))
{
struct udp_sock *up = udp_sk(sk);
@ -2599,7 +2599,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
valbool = val ? 1 : 0;
@ -2703,11 +2703,12 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
}
EXPORT_SYMBOL(udp_lib_setsockopt);
int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
int udp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
if (level == SOL_UDP || level == SOL_UDPLITE)
return udp_lib_setsockopt(sk, level, optname, optval, optlen,
return udp_lib_setsockopt(sk, level, optname,
optval, optlen,
udp_push_pending_frames);
return ip_setsockopt(sk, level, optname, optval, optlen);
}

View File

@ -12,8 +12,8 @@ int __udp4_lib_err(struct sk_buff *, u32, struct udp_table *);
int udp_v4_get_port(struct sock *sk, unsigned short snum);
void udp_v4_rehash(struct sock *sk);
int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
int udp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);

View File

@ -371,7 +371,7 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo
static struct ip6_flowlabel *
fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
char __user *optval, int optlen, int *err_p)
sockptr_t optval, int optlen, int *err_p)
{
struct ip6_flowlabel *fl = NULL;
int olen;
@ -401,7 +401,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
memset(fl->opt, 0, sizeof(*fl->opt));
fl->opt->tot_len = sizeof(*fl->opt) + olen;
err = -EFAULT;
if (copy_from_user(fl->opt+1, optval+CMSG_ALIGN(sizeof(*freq)), olen))
sockptr_advance(optval, CMSG_ALIGN(sizeof(*freq)));
if (copy_from_sockptr(fl->opt + 1, optval, olen))
goto done;
msg.msg_controllen = olen;
@ -533,187 +534,211 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
return -ENOENT;
}
int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
#define socklist_dereference(__sflp) \
rcu_dereference_protected(__sflp, lockdep_is_held(&ip6_sk_fl_lock))
static int ipv6_flowlabel_put(struct sock *sk, struct in6_flowlabel_req *freq)
{
int uninitialized_var(err);
struct net *net = sock_net(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_flowlabel_req freq;
struct ipv6_fl_socklist *sfl1 = NULL;
struct ipv6_fl_socklist *sfl;
struct ipv6_fl_socklist __rcu **sflp;
struct ipv6_fl_socklist *sfl;
if (freq->flr_flags & IPV6_FL_F_REFLECT) {
if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT;
if (!np->repflow)
return -ESRCH;
np->flow_label = 0;
np->repflow = 0;
return 0;
}
spin_lock_bh(&ip6_sk_fl_lock);
for (sflp = &np->ipv6_fl_list;
(sfl = socklist_dereference(*sflp)) != NULL;
sflp = &sfl->next) {
if (sfl->fl->label == freq->flr_label)
goto found;
}
spin_unlock_bh(&ip6_sk_fl_lock);
return -ESRCH;
found:
if (freq->flr_label == (np->flow_label & IPV6_FLOWLABEL_MASK))
np->flow_label &= ~IPV6_FLOWLABEL_MASK;
*sflp = sfl->next;
spin_unlock_bh(&ip6_sk_fl_lock);
fl_release(sfl->fl);
kfree_rcu(sfl, rcu);
return 0;
}
static int ipv6_flowlabel_renew(struct sock *sk, struct in6_flowlabel_req *freq)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk);
struct ipv6_fl_socklist *sfl;
int err;
rcu_read_lock_bh();
for_each_sk_fl_rcu(np, sfl) {
if (sfl->fl->label == freq->flr_label) {
err = fl6_renew(sfl->fl, freq->flr_linger,
freq->flr_expires);
rcu_read_unlock_bh();
return err;
}
}
rcu_read_unlock_bh();
if (freq->flr_share == IPV6_FL_S_NONE &&
ns_capable(net->user_ns, CAP_NET_ADMIN)) {
struct ip6_flowlabel *fl = fl_lookup(net, freq->flr_label);
if (fl) {
err = fl6_renew(fl, freq->flr_linger,
freq->flr_expires);
fl_release(fl);
return err;
}
}
return -ESRCH;
}
static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
sockptr_t optval, int optlen)
{
struct ipv6_fl_socklist *sfl, *sfl1 = NULL;
struct ip6_flowlabel *fl, *fl1 = NULL;
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk);
int uninitialized_var(err);
if (freq->flr_flags & IPV6_FL_F_REFLECT) {
if (net->ipv6.sysctl.flowlabel_consistency) {
net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n");
return -EPERM;
}
if (optlen < sizeof(freq))
if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT;
np->repflow = 1;
return 0;
}
if (freq->flr_label & ~IPV6_FLOWLABEL_MASK)
return -EINVAL;
if (net->ipv6.sysctl.flowlabel_state_ranges &&
(freq->flr_label & IPV6_FLOWLABEL_STATELESS_FLAG))
return -ERANGE;
if (copy_from_user(&freq, optval, sizeof(freq)))
return -EFAULT;
fl = fl_create(net, sk, freq, optval, optlen, &err);
if (!fl)
return err;
switch (freq.flr_action) {
case IPV6_FL_A_PUT:
if (freq.flr_flags & IPV6_FL_F_REFLECT) {
if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT;
if (!np->repflow)
return -ESRCH;
np->flow_label = 0;
np->repflow = 0;
return 0;
}
spin_lock_bh(&ip6_sk_fl_lock);
for (sflp = &np->ipv6_fl_list;
(sfl = rcu_dereference_protected(*sflp,
lockdep_is_held(&ip6_sk_fl_lock))) != NULL;
sflp = &sfl->next) {
if (sfl->fl->label == freq.flr_label) {
if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
np->flow_label &= ~IPV6_FLOWLABEL_MASK;
*sflp = sfl->next;
spin_unlock_bh(&ip6_sk_fl_lock);
fl_release(sfl->fl);
kfree_rcu(sfl, rcu);
return 0;
}
}
spin_unlock_bh(&ip6_sk_fl_lock);
return -ESRCH;
sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
case IPV6_FL_A_RENEW:
if (freq->flr_label) {
err = -EEXIST;
rcu_read_lock_bh();
for_each_sk_fl_rcu(np, sfl) {
if (sfl->fl->label == freq.flr_label) {
err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires);
rcu_read_unlock_bh();
return err;
if (sfl->fl->label == freq->flr_label) {
if (freq->flr_flags & IPV6_FL_F_EXCL) {
rcu_read_unlock_bh();
goto done;
}
fl1 = sfl->fl;
if (!atomic_inc_not_zero(&fl1->users))
fl1 = NULL;
break;
}
}
rcu_read_unlock_bh();
if (freq.flr_share == IPV6_FL_S_NONE &&
ns_capable(net->user_ns, CAP_NET_ADMIN)) {
fl = fl_lookup(net, freq.flr_label);
if (fl) {
err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
fl_release(fl);
return err;
}
}
return -ESRCH;
case IPV6_FL_A_GET:
if (freq.flr_flags & IPV6_FL_F_REFLECT) {
struct net *net = sock_net(sk);
if (net->ipv6.sysctl.flowlabel_consistency) {
net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n");
return -EPERM;
}
if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT;
np->repflow = 1;
return 0;
}
if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
return -EINVAL;
if (net->ipv6.sysctl.flowlabel_state_ranges &&
(freq.flr_label & IPV6_FLOWLABEL_STATELESS_FLAG))
return -ERANGE;
fl = fl_create(net, sk, &freq, optval, optlen, &err);
if (!fl)
return err;
sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
if (freq.flr_label) {
err = -EEXIST;
rcu_read_lock_bh();
for_each_sk_fl_rcu(np, sfl) {
if (sfl->fl->label == freq.flr_label) {
if (freq.flr_flags&IPV6_FL_F_EXCL) {
rcu_read_unlock_bh();
goto done;
}
fl1 = sfl->fl;
if (!atomic_inc_not_zero(&fl1->users))
fl1 = NULL;
break;
}
}
rcu_read_unlock_bh();
if (!fl1)
fl1 = fl_lookup(net, freq.flr_label);
if (fl1) {
if (!fl1)
fl1 = fl_lookup(net, freq->flr_label);
if (fl1) {
recheck:
err = -EEXIST;
if (freq.flr_flags&IPV6_FL_F_EXCL)
goto release;
err = -EPERM;
if (fl1->share == IPV6_FL_S_EXCL ||
fl1->share != fl->share ||
((fl1->share == IPV6_FL_S_PROCESS) &&
(fl1->owner.pid != fl->owner.pid)) ||
((fl1->share == IPV6_FL_S_USER) &&
!uid_eq(fl1->owner.uid, fl->owner.uid)))
goto release;
err = -EEXIST;
if (freq->flr_flags&IPV6_FL_F_EXCL)
goto release;
err = -EPERM;
if (fl1->share == IPV6_FL_S_EXCL ||
fl1->share != fl->share ||
((fl1->share == IPV6_FL_S_PROCESS) &&
(fl1->owner.pid != fl->owner.pid)) ||
((fl1->share == IPV6_FL_S_USER) &&
!uid_eq(fl1->owner.uid, fl->owner.uid)))
goto release;
err = -ENOMEM;
if (!sfl1)
goto release;
if (fl->linger > fl1->linger)
fl1->linger = fl->linger;
if ((long)(fl->expires - fl1->expires) > 0)
fl1->expires = fl->expires;
fl_link(np, sfl1, fl1);
fl_free(fl);
return 0;
err = -ENOMEM;
if (!sfl1)
goto release;
if (fl->linger > fl1->linger)
fl1->linger = fl->linger;
if ((long)(fl->expires - fl1->expires) > 0)
fl1->expires = fl->expires;
fl_link(np, sfl1, fl1);
fl_free(fl);
return 0;
release:
fl_release(fl1);
goto done;
}
fl_release(fl1);
goto done;
}
err = -ENOENT;
if (!(freq.flr_flags&IPV6_FL_F_CREATE))
goto done;
}
err = -ENOENT;
if (!(freq->flr_flags & IPV6_FL_F_CREATE))
goto done;
err = -ENOMEM;
if (!sfl1)
goto done;
err = -ENOMEM;
if (!sfl1)
goto done;
err = mem_check(sk);
if (err != 0)
goto done;
err = mem_check(sk);
if (err != 0)
goto done;
fl1 = fl_intern(net, fl, freq.flr_label);
if (fl1)
goto recheck;
fl1 = fl_intern(net, fl, freq->flr_label);
if (fl1)
goto recheck;
if (!freq.flr_label) {
if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label,
&fl->label, sizeof(fl->label))) {
/* Intentionally ignore fault. */
}
if (!freq->flr_label) {
sockptr_advance(optval,
offsetof(struct in6_flowlabel_req, flr_label));
if (copy_to_sockptr(optval, &fl->label, sizeof(fl->label))) {
/* Intentionally ignore fault. */
}
fl_link(np, sfl1, fl);
return 0;
default:
return -EINVAL;
}
fl_link(np, sfl1, fl);
return 0;
done:
fl_free(fl);
kfree(sfl1);
return err;
}
int ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen)
{
struct in6_flowlabel_req freq;
if (optlen < sizeof(freq))
return -EINVAL;
if (copy_from_sockptr(&freq, optval, sizeof(freq)))
return -EFAULT;
switch (freq.flr_action) {
case IPV6_FL_A_PUT:
return ipv6_flowlabel_put(sk, &freq);
case IPV6_FL_A_RENEW:
return ipv6_flowlabel_renew(sk, &freq);
case IPV6_FL_A_GET:
return ipv6_flowlabel_get(sk, &freq, optval, optlen);
default:
return -EINVAL;
}
}
#ifdef CONFIG_PROC_FS
struct ip6fl_iter_state {

View File

@ -1629,7 +1629,8 @@ EXPORT_SYMBOL(mroute6_is_socket);
* MOSPF/PIM router set up we can clean this up.
*/
int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
unsigned int optlen)
{
int ret, parent = 0;
struct mif6ctl vif;
@ -1665,7 +1666,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
case MRT6_ADD_MIF:
if (optlen < sizeof(vif))
return -EINVAL;
if (copy_from_user(&vif, optval, sizeof(vif)))
if (copy_from_sockptr(&vif, optval, sizeof(vif)))
return -EFAULT;
if (vif.mif6c_mifi >= MAXMIFS)
return -ENFILE;
@ -1678,7 +1679,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
case MRT6_DEL_MIF:
if (optlen < sizeof(mifi_t))
return -EINVAL;
if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
if (copy_from_sockptr(&mifi, optval, sizeof(mifi_t)))
return -EFAULT;
rtnl_lock();
ret = mif6_delete(mrt, mifi, 0, NULL);
@ -1697,7 +1698,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
case MRT6_DEL_MFC_PROXY:
if (optlen < sizeof(mfc))
return -EINVAL;
if (copy_from_user(&mfc, optval, sizeof(mfc)))
if (copy_from_sockptr(&mfc, optval, sizeof(mfc)))
return -EFAULT;
if (parent == 0)
parent = mfc.mf6cc_parent;
@ -1718,7 +1719,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (optlen != sizeof(flags))
return -EINVAL;
if (get_user(flags, (int __user *)optval))
if (copy_from_sockptr(&flags, optval, sizeof(flags)))
return -EFAULT;
rtnl_lock();
mroute_clean_tables(mrt, flags);
@ -1735,7 +1736,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (optlen != sizeof(v))
return -EINVAL;
if (get_user(v, (int __user *)optval))
if (copy_from_sockptr(&v, optval, sizeof(v)))
return -EFAULT;
mrt->mroute_do_assert = v;
return 0;
@ -1748,7 +1749,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (optlen != sizeof(v))
return -EINVAL;
if (get_user(v, (int __user *)optval))
if (copy_from_sockptr(&v, optval, sizeof(v)))
return -EFAULT;
v = !!v;
rtnl_lock();
@ -1769,7 +1770,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (optlen != sizeof(u32))
return -EINVAL;
if (get_user(v, (u32 __user *)optval))
if (copy_from_sockptr(&v, optval, sizeof(v)))
return -EFAULT;
/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
if (v != RT_TABLE_DEFAULT && v >= 100000000)

View File

@ -136,15 +136,15 @@ static bool setsockopt_needs_rtnl(int optname)
return false;
}
static int copy_group_source_from_user(struct group_source_req *greqs,
void __user *optval, int optlen)
static int copy_group_source_from_sockptr(struct group_source_req *greqs,
sockptr_t optval, int optlen)
{
if (in_compat_syscall()) {
struct compat_group_source_req gr32;
if (optlen < sizeof(gr32))
return -EINVAL;
if (copy_from_user(&gr32, optval, sizeof(gr32)))
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
return -EFAULT;
greqs->gsr_interface = gr32.gsr_interface;
greqs->gsr_group = gr32.gsr_group;
@ -152,7 +152,7 @@ static int copy_group_source_from_user(struct group_source_req *greqs,
} else {
if (optlen < sizeof(*greqs))
return -EINVAL;
if (copy_from_user(greqs, optval, sizeof(*greqs)))
if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
return -EFAULT;
}
@ -160,13 +160,13 @@ static int copy_group_source_from_user(struct group_source_req *greqs,
}
static int do_ipv6_mcast_group_source(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct group_source_req greqs;
int omode, add;
int ret;
ret = copy_group_source_from_user(&greqs, optval, optlen);
ret = copy_group_source_from_sockptr(&greqs, optval, optlen);
if (ret)
return ret;
@ -200,7 +200,7 @@ static int do_ipv6_mcast_group_source(struct sock *sk, int optname,
return ip6_mc_source(add, omode, sk, &greqs);
}
static int ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
int optlen)
{
struct group_filter *gsf;
@ -211,7 +211,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
if (optlen > sysctl_optmem_max)
return -ENOBUFS;
gsf = memdup_user(optval, optlen);
gsf = memdup_sockptr(optval, optlen);
if (IS_ERR(gsf))
return PTR_ERR(gsf);
@ -231,7 +231,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
return ret;
}
static int compat_ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
int optlen)
{
const int size0 = offsetof(struct compat_group_filter, gf_slist);
@ -251,7 +251,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
ret = -EFAULT;
if (copy_from_user(gf32, optval, optlen))
if (copy_from_sockptr(gf32, optval, optlen))
goto out_free_p;
/* numsrc >= (4G-140)/128 overflow in 32 bits */
@ -276,14 +276,14 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, void __user *optval,
}
static int ipv6_mcast_join_leave(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct sockaddr_in6 *psin6;
struct group_req greq;
if (optlen < sizeof(greq))
return -EINVAL;
if (copy_from_user(&greq, optval, sizeof(greq)))
if (copy_from_sockptr(&greq, optval, sizeof(greq)))
return -EFAULT;
if (greq.gr_group.ss_family != AF_INET6)
@ -296,14 +296,14 @@ static int ipv6_mcast_join_leave(struct sock *sk, int optname,
}
static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname,
void __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct compat_group_req gr32;
struct sockaddr_in6 *psin6;
if (optlen < sizeof(gr32))
return -EINVAL;
if (copy_from_user(&gr32, optval, sizeof(gr32)))
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
return -EFAULT;
if (gr32.gr_group.ss_family != AF_INET6)
@ -315,8 +315,82 @@ static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname,
return ipv6_sock_mc_drop(sk, gr32.gr_interface, &psin6->sin6_addr);
}
static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
int optlen)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_opt_hdr *new = NULL;
struct net *net = sock_net(sk);
struct ipv6_txoptions *opt;
int err;
/* hop-by-hop / destination options are privileged option */
if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
return -EPERM;
/* remove any sticky options header with a zero option
* length, per RFC3542.
*/
if (optlen > 0) {
if (sockptr_is_null(optval))
return -EINVAL;
if (optlen < sizeof(struct ipv6_opt_hdr) ||
optlen & 0x7 ||
optlen > 8 * 255)
return -EINVAL;
new = memdup_sockptr(optval, optlen);
if (IS_ERR(new))
return PTR_ERR(new);
if (unlikely(ipv6_optlen(new) > optlen)) {
kfree(new);
return -EINVAL;
}
}
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
opt = ipv6_renew_options(sk, opt, optname, new);
kfree(new);
if (IS_ERR(opt))
return PTR_ERR(opt);
/* routing header option needs extra check */
err = -EINVAL;
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
struct ipv6_rt_hdr *rthdr = opt->srcrt;
switch (rthdr->type) {
#if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPV6_SRCRT_TYPE_2:
if (rthdr->hdrlen != 2 || rthdr->segments_left != 1)
goto sticky_done;
break;
#endif
case IPV6_SRCRT_TYPE_4:
{
struct ipv6_sr_hdr *srh =
(struct ipv6_sr_hdr *)opt->srcrt;
if (!seg6_validate_srh(srh, optlen, false))
goto sticky_done;
break;
}
default:
goto sticky_done;
}
}
err = 0;
opt = ipv6_update_options(sk, opt);
sticky_done:
if (opt) {
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
txopt_put(opt);
}
return err;
}
static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk);
@ -324,11 +398,11 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
int retv = -ENOPROTOOPT;
bool needs_rtnl = setsockopt_needs_rtnl(optname);
if (!optval)
if (sockptr_is_null(optval))
val = 0;
else {
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
} else
val = 0;
@ -579,82 +653,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_RTHDRDSTOPTS:
case IPV6_RTHDR:
case IPV6_DSTOPTS:
{
struct ipv6_txoptions *opt;
struct ipv6_opt_hdr *new = NULL;
/* hop-by-hop / destination options are privileged option */
retv = -EPERM;
if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
break;
/* remove any sticky options header with a zero option
* length, per RFC3542.
*/
if (optlen == 0)
optval = NULL;
else if (!optval)
goto e_inval;
else if (optlen < sizeof(struct ipv6_opt_hdr) ||
optlen & 0x7 || optlen > 8 * 255)
goto e_inval;
else {
new = memdup_user(optval, optlen);
if (IS_ERR(new)) {
retv = PTR_ERR(new);
break;
}
if (unlikely(ipv6_optlen(new) > optlen)) {
kfree(new);
goto e_inval;
}
}
opt = rcu_dereference_protected(np->opt,
lockdep_sock_is_held(sk));
opt = ipv6_renew_options(sk, opt, optname, new);
kfree(new);
if (IS_ERR(opt)) {
retv = PTR_ERR(opt);
break;
}
/* routing header option needs extra check */
retv = -EINVAL;
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
struct ipv6_rt_hdr *rthdr = opt->srcrt;
switch (rthdr->type) {
#if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPV6_SRCRT_TYPE_2:
if (rthdr->hdrlen != 2 ||
rthdr->segments_left != 1)
goto sticky_done;
break;
#endif
case IPV6_SRCRT_TYPE_4:
{
struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)
opt->srcrt;
if (!seg6_validate_srh(srh, optlen, false))
goto sticky_done;
break;
}
default:
goto sticky_done;
}
}
retv = 0;
opt = ipv6_update_options(sk, opt);
sticky_done:
if (opt) {
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
txopt_put(opt);
}
retv = ipv6_set_opt_hdr(sk, optname, optval, optlen);
break;
}
case IPV6_PKTINFO:
{
@ -662,12 +662,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (optlen == 0)
goto e_inval;
else if (optlen < sizeof(struct in6_pktinfo) || !optval)
else if (optlen < sizeof(struct in6_pktinfo) ||
sockptr_is_null(optval))
goto e_inval;
if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) {
retv = -EFAULT;
break;
if (copy_from_sockptr(&pkt, optval, sizeof(pkt))) {
retv = -EFAULT;
break;
}
if (!sk_dev_equal_l3scope(sk, pkt.ipi6_ifindex))
goto e_inval;
@ -708,7 +709,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
refcount_set(&opt->refcnt, 1);
opt->tot_len = sizeof(*opt) + optlen;
retv = -EFAULT;
if (copy_from_user(opt+1, optval, optlen))
if (copy_from_sockptr(opt + 1, optval, optlen))
goto done;
msg.msg_controllen = optlen;
@ -830,7 +831,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
break;
retv = -EFAULT;
if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
break;
if (optname == IPV6_ADD_MEMBERSHIP)
@ -848,7 +849,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
goto e_inval;
retv = -EFAULT;
if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
break;
if (optname == IPV6_JOIN_ANYCAST)
@ -979,8 +980,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
return -EINVAL;
}
int ipv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
int err;

View File

@ -1119,7 +1119,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
do_replace(struct net *net, const void __user *user, unsigned int len)
do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct ip6t_replace tmp;
@ -1127,7 +1127,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
void *loc_cpu_entry;
struct ip6t_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -1143,8 +1143,8 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -1168,7 +1168,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
}
static int
do_add_counters(struct net *net, const void __user *user, unsigned int len)
do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
{
unsigned int i;
struct xt_counters_info tmp;
@ -1179,7 +1179,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len)
struct ip6t_entry *iter;
unsigned int addend;
paddc = xt_copy_counters_from_user(user, len, &tmp);
paddc = xt_copy_counters(arg, len, &tmp);
if (IS_ERR(paddc))
return PTR_ERR(paddc);
t = xt_find_table_lock(net, AF_INET6, tmp.name);
@ -1493,7 +1493,7 @@ translate_compat_table(struct net *net,
}
static int
compat_do_replace(struct net *net, void __user *user, unsigned int len)
compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
int ret;
struct compat_ip6t_replace tmp;
@ -1501,7 +1501,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
void *loc_cpu_entry;
struct ip6t_entry *iter;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
return -EFAULT;
/* overflow check */
@ -1517,8 +1517,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
return -ENOMEM;
loc_cpu_entry = newinfo->entries;
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
tmp.size) != 0) {
sockptr_advance(arg, sizeof(tmp));
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
ret = -EFAULT;
goto free_newinfo;
}
@ -1619,7 +1619,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
#endif
static int
do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
{
int ret;
@ -1630,14 +1630,14 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
case IP6T_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), user, len);
ret = compat_do_replace(sock_net(sk), arg, len);
else
#endif
ret = do_replace(sock_net(sk), user, len);
ret = do_replace(sock_net(sk), arg, len);
break;
case IP6T_SO_SET_ADD_COUNTERS:
ret = do_add_counters(sock_net(sk), user, len);
ret = do_add_counters(sock_net(sk), arg, len);
break;
default:

View File

@ -972,13 +972,13 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
sockptr_t optval, int optlen)
{
switch (optname) {
case ICMPV6_FILTER:
if (optlen > sizeof(struct icmp6_filter))
optlen = sizeof(struct icmp6_filter);
if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen))
if (copy_from_sockptr(&raw6_sk(sk)->filter, optval, optlen))
return -EFAULT;
return 0;
default:
@ -1015,12 +1015,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct raw6_sock *rp = raw6_sk(sk);
int val;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
switch (optname) {
@ -1062,7 +1062,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
}
static int rawv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
switch (level) {
case SOL_RAW:

View File

@ -567,7 +567,7 @@ static struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk,
}
static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
char __user *optval, int optlen)
sockptr_t optval, int optlen)
{
struct tcp_md5sig cmd;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
@ -577,7 +577,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
if (optlen < sizeof(cmd))
return -EINVAL;
if (copy_from_user(&cmd, optval, sizeof(cmd)))
if (copy_from_sockptr(&cmd, optval, sizeof(cmd)))
return -EFAULT;
if (sin6->sin6_family != AF_INET6)

View File

@ -1618,11 +1618,12 @@ void udpv6_destroy_sock(struct sock *sk)
/*
* Socket option code for UDP
*/
int udpv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
int udpv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
if (level == SOL_UDP || level == SOL_UDPLITE)
return udp_lib_setsockopt(sk, level, optname, optval, optlen,
return udp_lib_setsockopt(sk, level, optname,
optval, optlen,
udp_v6_push_pending_frames);
return ipv6_setsockopt(sk, level, optname, optval, optlen);
}

View File

@ -17,8 +17,8 @@ void udp_v6_rehash(struct sock *sk);
int udpv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int udpv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen);
int udpv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
unsigned int optlen);
int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
int flags, int *addr_len);

View File

@ -1494,7 +1494,7 @@ static int iucv_sock_release(struct socket *sock)
/* getsockopt and setsockopt */
static int iucv_sock_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 iucv_sock *iucv = iucv_sk(sk);
@ -1507,7 +1507,7 @@ static int iucv_sock_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *) optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
rc = 0;

View File

@ -1265,7 +1265,7 @@ static void kcm_recv_enable(struct kcm_sock *kcm)
}
static int kcm_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct kcm_sock *kcm = kcm_sk(sock->sk);
int val, valbool;
@ -1277,8 +1277,8 @@ static int kcm_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
return -EINVAL;
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
valbool = val ? 1 : 0;

View File

@ -1242,7 +1242,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
* session or the special tunnel type.
*/
static int pppol2tp_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 l2tp_session *session;
@ -1256,7 +1256,7 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
err = -ENOTCONN;

View File

@ -1053,7 +1053,7 @@ static int llc_ui_ioctl(struct socket *sock, unsigned int cmd,
* Set various connection specific parameters.
*/
static int llc_ui_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 llc_sock *llc = llc_sk(sk);
@ -1063,7 +1063,7 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
lock_sock(sk);
if (unlikely(level != SOL_LLC || optlen != sizeof(int)))
goto out;
rc = get_user(opt, (int __user *)optval);
rc = copy_from_sockptr(&opt, optval, sizeof(opt));
if (rc)
goto out;
rc = -EINVAL;

View File

@ -1632,7 +1632,7 @@ static void mptcp_destroy(struct sock *sk)
}
static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = (struct sock *)msk;
struct socket *ssock;
@ -1663,7 +1663,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
}
static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = (struct sock *)msk;
int ret = -EOPNOTSUPP;
@ -1690,7 +1690,7 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
}
static int mptcp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sock *ssk;

View File

@ -2434,7 +2434,7 @@ static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
}
static int
do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
do_ip_vs_set_ctl(struct sock *sk, int cmd, sockptr_t ptr, unsigned int len)
{
struct net *net = sock_net(sk);
int ret;
@ -2458,7 +2458,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
return -EINVAL;
}
if (copy_from_user(arg, user, len) != 0)
if (copy_from_sockptr(arg, ptr, len) != 0)
return -EFAULT;
/* Handle daemons since they have another lock */

View File

@ -89,7 +89,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
return ops;
}
int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt,
unsigned int len)
{
struct nf_sockopt_ops *ops;

View File

@ -1028,9 +1028,9 @@ int xt_check_target(struct xt_tgchk_param *par,
EXPORT_SYMBOL_GPL(xt_check_target);
/**
* xt_copy_counters_from_user - copy counters and metadata from userspace
* xt_copy_counters - copy counters and metadata from a sockptr_t
*
* @user: src pointer to userspace memory
* @arg: src sockptr
* @len: alleged size of userspace memory
* @info: where to store the xt_counters_info metadata
*
@ -1047,8 +1047,8 @@ EXPORT_SYMBOL_GPL(xt_check_target);
* Return: returns pointer that caller has to test via IS_ERR().
* If IS_ERR is false, caller has to vfree the pointer.
*/
void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
struct xt_counters_info *info)
void *xt_copy_counters(sockptr_t arg, unsigned int len,
struct xt_counters_info *info)
{
void *mem;
u64 size;
@ -1062,12 +1062,12 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
return ERR_PTR(-EINVAL);
len -= sizeof(compat_tmp);
if (copy_from_user(&compat_tmp, user, sizeof(compat_tmp)) != 0)
if (copy_from_sockptr(&compat_tmp, arg, sizeof(compat_tmp)) != 0)
return ERR_PTR(-EFAULT);
memcpy(info->name, compat_tmp.name, sizeof(info->name) - 1);
info->num_counters = compat_tmp.num_counters;
user += sizeof(compat_tmp);
sockptr_advance(arg, sizeof(compat_tmp));
} else
#endif
{
@ -1075,10 +1075,10 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
return ERR_PTR(-EINVAL);
len -= sizeof(*info);
if (copy_from_user(info, user, sizeof(*info)) != 0)
if (copy_from_sockptr(info, arg, sizeof(*info)) != 0)
return ERR_PTR(-EFAULT);
user += sizeof(*info);
sockptr_advance(arg, sizeof(*info));
}
info->name[sizeof(info->name) - 1] = '\0';
@ -1092,13 +1092,13 @@ void *xt_copy_counters_from_user(const void __user *user, unsigned int len,
if (!mem)
return ERR_PTR(-ENOMEM);
if (copy_from_user(mem, user, len) == 0)
if (copy_from_sockptr(mem, arg, len) == 0)
return mem;
vfree(mem);
return ERR_PTR(-EFAULT);
}
EXPORT_SYMBOL_GPL(xt_copy_counters_from_user);
EXPORT_SYMBOL_GPL(xt_copy_counters);
#ifdef CONFIG_COMPAT
int xt_compat_target_offset(const struct xt_target *target)

View File

@ -1621,7 +1621,7 @@ static void netlink_update_socket_mc(struct netlink_sock *nlk,
}
static int netlink_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 netlink_sock *nlk = nlk_sk(sk);
@ -1632,7 +1632,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
return -ENOPROTOOPT;
if (optlen >= sizeof(int) &&
get_user(val, (unsigned int __user *)optval))
copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
switch (optname) {

View File

@ -294,7 +294,7 @@ void nr_destroy_socket(struct sock *sk)
*/
static int nr_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 nr_sock *nr = nr_sk(sk);
@ -306,7 +306,7 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(unsigned int))
return -EINVAL;
if (get_user(opt, (unsigned int __user *)optval))
if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
return -EFAULT;
switch (optname) {

View File

@ -218,7 +218,7 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
}
static int nfc_llcp_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 nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@ -241,7 +241,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}
@ -263,7 +263,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (get_user(opt, (u32 __user *) optval)) {
if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
err = -EFAULT;
break;
}

View File

@ -1536,7 +1536,7 @@ static void __fanout_set_data_bpf(struct packet_fanout *f, struct bpf_prog *new)
}
}
static int fanout_set_data_cbpf(struct packet_sock *po, char __user *data,
static int fanout_set_data_cbpf(struct packet_sock *po, sockptr_t data,
unsigned int len)
{
struct bpf_prog *new;
@ -1558,7 +1558,7 @@ static int fanout_set_data_cbpf(struct packet_sock *po, char __user *data,
return 0;
}
static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data,
static int fanout_set_data_ebpf(struct packet_sock *po, sockptr_t data,
unsigned int len)
{
struct bpf_prog *new;
@ -1568,7 +1568,7 @@ static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data,
return -EPERM;
if (len != sizeof(fd))
return -EINVAL;
if (copy_from_user(&fd, data, len))
if (copy_from_sockptr(&fd, data, len))
return -EFAULT;
new = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER);
@ -1579,7 +1579,7 @@ static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data,
return 0;
}
static int fanout_set_data(struct packet_sock *po, char __user *data,
static int fanout_set_data(struct packet_sock *po, sockptr_t data,
unsigned int len)
{
switch (po->fanout->type) {
@ -3652,7 +3652,8 @@ static void packet_flush_mclist(struct sock *sk)
}
static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
unsigned int optlen)
{
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
@ -3672,7 +3673,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
return -EINVAL;
if (len > sizeof(mreq))
len = sizeof(mreq);
if (copy_from_user(&mreq, optval, len))
if (copy_from_sockptr(&mreq, optval, len))
return -EFAULT;
if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
return -EINVAL;
@ -3703,7 +3704,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen < len) {
ret = -EINVAL;
} else {
if (copy_from_user(&req_u.req, optval, len))
if (copy_from_sockptr(&req_u.req, optval, len))
ret = -EFAULT;
else
ret = packet_set_ring(sk, &req_u, 0,
@ -3718,7 +3719,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
pkt_sk(sk)->copy_thresh = val;
@ -3730,7 +3731,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
switch (val) {
case TPACKET_V1:
@ -3756,7 +3757,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
if (val > INT_MAX)
return -EINVAL;
@ -3776,7 +3777,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3795,7 +3796,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen < sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3809,7 +3810,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen < sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3825,7 +3826,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
return -EINVAL;
if (optlen < sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3844,7 +3845,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
po->tp_tstamp = val;
@ -3856,7 +3857,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
return fanout_add(sk, val & 0xffff, val >> 16);
@ -3874,7 +3875,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
if (val < 0 || val > 1)
return -EINVAL;
@ -3888,7 +3889,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
lock_sock(sk);
@ -3907,7 +3908,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
if (optlen != sizeof(val))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(val)))
if (copy_from_sockptr(&val, optval, sizeof(val)))
return -EFAULT;
po->xmit = val ? packet_direct_xmit : dev_queue_xmit;

View File

@ -975,7 +975,7 @@ static int pep_init(struct sock *sk)
}
static int pep_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct pep_sock *pn = pep_sk(sk);
int val = 0, err = 0;
@ -983,7 +983,7 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
if (level != SOL_PNPIPE)
return -ENOPROTOOPT;
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
}

View File

@ -290,8 +290,7 @@ static int rds_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return 0;
}
static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
int len)
static int rds_cancel_sent_to(struct rds_sock *rs, sockptr_t optval, int len)
{
struct sockaddr_in6 sin6;
struct sockaddr_in sin;
@ -308,14 +307,15 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
goto out;
} else if (len < sizeof(struct sockaddr_in6)) {
/* Assume IPv4 */
if (copy_from_user(&sin, optval, sizeof(struct sockaddr_in))) {
if (copy_from_sockptr(&sin, optval,
sizeof(struct sockaddr_in))) {
ret = -EFAULT;
goto out;
}
ipv6_addr_set_v4mapped(sin.sin_addr.s_addr, &sin6.sin6_addr);
sin6.sin6_port = sin.sin_port;
} else {
if (copy_from_user(&sin6, optval,
if (copy_from_sockptr(&sin6, optval,
sizeof(struct sockaddr_in6))) {
ret = -EFAULT;
goto out;
@ -327,21 +327,20 @@ static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
return ret;
}
static int rds_set_bool_option(unsigned char *optvar, char __user *optval,
static int rds_set_bool_option(unsigned char *optvar, sockptr_t optval,
int optlen)
{
int value;
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(value, (int __user *) optval))
if (copy_from_sockptr(&value, optval, sizeof(int)))
return -EFAULT;
*optvar = !!value;
return 0;
}
static int rds_cong_monitor(struct rds_sock *rs, char __user *optval,
int optlen)
static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen)
{
int ret;
@ -358,8 +357,7 @@ static int rds_cong_monitor(struct rds_sock *rs, char __user *optval,
return ret;
}
static int rds_set_transport(struct rds_sock *rs, char __user *optval,
int optlen)
static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen)
{
int t_type;
@ -369,7 +367,7 @@ static int rds_set_transport(struct rds_sock *rs, char __user *optval,
if (optlen != sizeof(int))
return -EINVAL;
if (copy_from_user(&t_type, (int __user *)optval, sizeof(t_type)))
if (copy_from_sockptr(&t_type, optval, sizeof(t_type)))
return -EFAULT;
if (t_type < 0 || t_type >= RDS_TRANS_COUNT)
@ -380,7 +378,7 @@ static int rds_set_transport(struct rds_sock *rs, char __user *optval,
return rs->rs_transport ? 0 : -ENOPROTOOPT;
}
static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
static int rds_enable_recvtstamp(struct sock *sk, sockptr_t optval,
int optlen, int optname)
{
int val, valbool;
@ -388,7 +386,7 @@ static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
if (optlen != sizeof(int))
return -EFAULT;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
valbool = val ? 1 : 0;
@ -404,7 +402,7 @@ static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
return 0;
}
static int rds_recv_track_latency(struct rds_sock *rs, char __user *optval,
static int rds_recv_track_latency(struct rds_sock *rs, sockptr_t optval,
int optlen)
{
struct rds_rx_trace_so trace;
@ -413,7 +411,7 @@ static int rds_recv_track_latency(struct rds_sock *rs, char __user *optval,
if (optlen != sizeof(struct rds_rx_trace_so))
return -EFAULT;
if (copy_from_user(&trace, optval, sizeof(trace)))
if (copy_from_sockptr(&trace, optval, sizeof(trace)))
return -EFAULT;
if (trace.rx_traces > RDS_MSG_RX_DGRAM_TRACE_MAX)
@ -432,7 +430,7 @@ static int rds_recv_track_latency(struct rds_sock *rs, char __user *optval,
}
static int rds_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct rds_sock *rs = rds_sk_to_rs(sock->sk);
int ret;

View File

@ -353,21 +353,20 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
return ret;
}
int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen)
int rds_get_mr(struct rds_sock *rs, sockptr_t optval, int optlen)
{
struct rds_get_mr_args args;
if (optlen != sizeof(struct rds_get_mr_args))
return -EINVAL;
if (copy_from_user(&args, (struct rds_get_mr_args __user *)optval,
sizeof(struct rds_get_mr_args)))
if (copy_from_sockptr(&args, optval, sizeof(struct rds_get_mr_args)))
return -EFAULT;
return __rds_rdma_map(rs, &args, NULL, NULL, NULL);
}
int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen)
int rds_get_mr_for_dest(struct rds_sock *rs, sockptr_t optval, int optlen)
{
struct rds_get_mr_for_dest_args args;
struct rds_get_mr_args new_args;
@ -375,7 +374,7 @@ int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen)
if (optlen != sizeof(struct rds_get_mr_for_dest_args))
return -EINVAL;
if (copy_from_user(&args, (struct rds_get_mr_for_dest_args __user *)optval,
if (copy_from_sockptr(&args, optval,
sizeof(struct rds_get_mr_for_dest_args)))
return -EFAULT;
@ -394,7 +393,7 @@ int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen)
/*
* Free the MR indicated by the given R_Key
*/
int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen)
int rds_free_mr(struct rds_sock *rs, sockptr_t optval, int optlen)
{
struct rds_free_mr_args args;
struct rds_mr *mr;
@ -403,8 +402,7 @@ int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen)
if (optlen != sizeof(struct rds_free_mr_args))
return -EINVAL;
if (copy_from_user(&args, (struct rds_free_mr_args __user *)optval,
sizeof(struct rds_free_mr_args)))
if (copy_from_sockptr(&args, optval, sizeof(struct rds_free_mr_args)))
return -EFAULT;
/* Special case - a null cookie means flush all unused MRs */

View File

@ -924,9 +924,9 @@ int rds_send_pong(struct rds_conn_path *cp, __be16 dport);
/* rdma.c */
void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force);
int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
int rds_get_mr(struct rds_sock *rs, sockptr_t optval, int optlen);
int rds_get_mr_for_dest(struct rds_sock *rs, sockptr_t optval, int optlen);
int rds_free_mr(struct rds_sock *rs, sockptr_t optval, int optlen);
void rds_rdma_drop_keys(struct rds_sock *rs);
int rds_rdma_extra_size(struct rds_rdma_args *args,
struct rds_iov_vector *iov);

View File

@ -365,7 +365,7 @@ void rose_destroy_socket(struct sock *sk)
*/
static int rose_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 rose_sock *rose = rose_sk(sk);
@ -377,7 +377,7 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(opt, (int __user *)optval))
if (copy_from_sockptr(&opt, optval, sizeof(int)))
return -EFAULT;
switch (optname) {

View File

@ -588,7 +588,7 @@ EXPORT_SYMBOL(rxrpc_sock_set_min_security_level);
* set RxRPC socket options
*/
static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
unsigned int min_sec_level;
@ -639,8 +639,8 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNBOUND)
goto error;
ret = get_user(min_sec_level,
(unsigned int __user *) optval);
ret = copy_from_sockptr(&min_sec_level, optval,
sizeof(unsigned int));
if (ret < 0)
goto error;
ret = -EINVAL;
@ -658,7 +658,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
if (rx->sk.sk_state != RXRPC_SERVER_BOUND2)
goto error;
ret = -EFAULT;
if (copy_from_user(service_upgrade, optval,
if (copy_from_sockptr(service_upgrade, optval,
sizeof(service_upgrade)) != 0)
goto error;
ret = -EINVAL;

View File

@ -909,8 +909,8 @@ extern const struct rxrpc_security rxrpc_no_security;
extern struct key_type key_type_rxrpc;
extern struct key_type key_type_rxrpc_s;
int rxrpc_request_key(struct rxrpc_sock *, char __user *, int);
int rxrpc_server_keyring(struct rxrpc_sock *, char __user *, int);
int rxrpc_request_key(struct rxrpc_sock *, sockptr_t , int);
int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);
int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time64_t,
u32);

View File

@ -896,7 +896,7 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
/*
* grab the security key for a socket
*/
int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
{
struct key *key;
char *description;
@ -906,7 +906,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;
description = memdup_user_nul(optval, optlen);
description = memdup_sockptr_nul(optval, optlen);
if (IS_ERR(description))
return PTR_ERR(description);
@ -926,8 +926,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
/*
* grab the security keyring for a server socket
*/
int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
int optlen)
int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
{
struct key *key;
char *description;
@ -937,7 +936,7 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;
description = memdup_user_nul(optval, optlen);
description = memdup_sockptr_nul(optval, optlen);
if (IS_ERR(description))
return PTR_ERR(description);

View File

@ -4429,7 +4429,7 @@ static int sctp_setsockopt_pf_expose(struct sock *sk,
* optlen - the size of the buffer.
*/
static int sctp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
void *kopt = NULL;
int retval = 0;
@ -4449,7 +4449,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
}
if (optlen > 0) {
kopt = memdup_user(optval, optlen);
kopt = memdup_sockptr(optval, optlen);
if (IS_ERR(kopt))
return PTR_ERR(kopt);
}

View File

@ -1731,7 +1731,7 @@ static int smc_shutdown(struct socket *sock, int how)
}
static int smc_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 smc_sock *smc;
@ -1754,7 +1754,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
if (copy_from_sockptr(&val, optval, sizeof(int)))
return -EFAULT;
lock_sock(sk);

View File

@ -2094,10 +2094,10 @@ static bool sock_use_custom_sol_socket(const struct socket *sock)
* Set a socket option. Because we don't know the option lengths we have
* to pass the user mode parameter for the protocols to sort out.
*/
int __sys_setsockopt(int fd, int level, int optname, char __user *optval,
int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
int optlen)
{
mm_segment_t oldfs = get_fs();
sockptr_t optval;
char *kernel_optval = NULL;
int err, fput_needed;
struct socket *sock;
@ -2105,6 +2105,10 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *optval,
if (optlen < 0)
return -EINVAL;
err = init_user_sockptr(&optval, user_optval);
if (err)
return err;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
return err;
@ -2115,7 +2119,7 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *optval,
if (!in_compat_syscall())
err = BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock->sk, &level, &optname,
optval, &optlen,
user_optval, &optlen,
&kernel_optval);
if (err < 0)
goto out_put;
@ -2124,11 +2128,8 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *optval,
goto out_put;
}
if (kernel_optval) {
set_fs(KERNEL_DS);
optval = (char __user __force *)kernel_optval;
}
if (kernel_optval)
optval = KERNEL_SOCKPTR(kernel_optval);
if (level == SOL_SOCKET && !sock_use_custom_sol_socket(sock))
err = sock_setsockopt(sock, level, optname, optval, optlen);
else if (unlikely(!sock->ops->setsockopt))
@ -2136,12 +2137,7 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *optval,
else
err = sock->ops->setsockopt(sock, level, optname, optval,
optlen);
if (kernel_optval) {
set_fs(oldfs);
kfree(kernel_optval);
}
kfree(kernel_optval);
out_put:
fput_light(sock->file, fput_needed);
return err;

View File

@ -3103,7 +3103,7 @@ static int tipc_sk_leave(struct tipc_sock *tsk)
* Returns 0 on success, errno otherwise
*/
static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
char __user *ov, unsigned int ol)
sockptr_t ov, unsigned int ol)
{
struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk);
@ -3124,17 +3124,17 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
case TIPC_NODELAY:
if (ol < sizeof(value))
return -EINVAL;
if (get_user(value, (u32 __user *)ov))
if (copy_from_sockptr(&value, ov, sizeof(u32)))
return -EFAULT;
break;
case TIPC_GROUP_JOIN:
if (ol < sizeof(mreq))
return -EINVAL;
if (copy_from_user(&mreq, ov, sizeof(mreq)))
if (copy_from_sockptr(&mreq, ov, sizeof(mreq)))
return -EFAULT;
break;
default:
if (ov || ol)
if (!sockptr_is_null(ov) || ol)
return -EINVAL;
}

View File

@ -450,7 +450,7 @@ static int tls_getsockopt(struct sock *sk, int level, int optname,
return do_tls_getsockopt(sk, optname, optval, optlen);
}
static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
unsigned int optlen, int tx)
{
struct tls_crypto_info *crypto_info;
@ -460,7 +460,7 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
int rc = 0;
int conf;
if (!optval || (optlen < sizeof(*crypto_info))) {
if (sockptr_is_null(optval) || (optlen < sizeof(*crypto_info))) {
rc = -EINVAL;
goto out;
}
@ -479,7 +479,7 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
goto out;
}
rc = copy_from_user(crypto_info, optval, sizeof(*crypto_info));
rc = copy_from_sockptr(crypto_info, optval, sizeof(*crypto_info));
if (rc) {
rc = -EFAULT;
goto err_crypto_info;
@ -522,8 +522,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
goto err_crypto_info;
}
rc = copy_from_user(crypto_info + 1, optval + sizeof(*crypto_info),
optlen - sizeof(*crypto_info));
sockptr_advance(optval, sizeof(*crypto_info));
rc = copy_from_sockptr(crypto_info + 1, optval,
optlen - sizeof(*crypto_info));
if (rc) {
rc = -EFAULT;
goto err_crypto_info;
@ -579,8 +580,8 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
return rc;
}
static int do_tls_setsockopt(struct sock *sk, int optname,
char __user *optval, unsigned int optlen)
static int do_tls_setsockopt(struct sock *sk, int optname, sockptr_t optval,
unsigned int optlen)
{
int rc = 0;
@ -600,7 +601,7 @@ static int do_tls_setsockopt(struct sock *sk, int optname,
}
static int tls_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);

View File

@ -1517,7 +1517,7 @@ static void vsock_update_buffer_size(struct vsock_sock *vsk,
static int vsock_stream_setsockopt(struct socket *sock,
int level,
int optname,
char __user *optval,
sockptr_t optval,
unsigned int optlen)
{
int err;
@ -1535,7 +1535,7 @@ static int vsock_stream_setsockopt(struct socket *sock,
err = -EINVAL; \
goto exit; \
} \
if (copy_from_user(&_v, optval, sizeof(_v)) != 0) { \
if (copy_from_sockptr(&_v, optval, sizeof(_v)) != 0) { \
err = -EFAULT; \
goto exit; \
} \

View File

@ -431,7 +431,7 @@ void x25_destroy_socket_from_timer(struct sock *sk)
*/
static int x25_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
sockptr_t optval, unsigned int optlen)
{
int opt;
struct sock *sk = sock->sk;
@ -445,7 +445,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
goto out;
rc = -EFAULT;
if (get_user(opt, (int __user *)optval))
if (copy_from_sockptr(&opt, optval, sizeof(int)))
goto out;
if (opt)

View File

@ -702,7 +702,7 @@ struct xdp_umem_reg_v1 {
};
static int xsk_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 xdp_sock *xs = xdp_sk(sk);
@ -720,7 +720,7 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
if (optlen < sizeof(entries))
return -EINVAL;
if (copy_from_user(&entries, optval, sizeof(entries)))
if (copy_from_sockptr(&entries, optval, sizeof(entries)))
return -EFAULT;
mutex_lock(&xs->mutex);
@ -747,7 +747,7 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
else if (optlen < sizeof(mr))
mr_size = sizeof(struct xdp_umem_reg_v1);
if (copy_from_user(&mr, optval, mr_size))
if (copy_from_sockptr(&mr, optval, mr_size))
return -EFAULT;
mutex_lock(&xs->mutex);
@ -774,7 +774,7 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
struct xsk_queue **q;
int entries;
if (copy_from_user(&entries, optval, sizeof(entries)))
if (copy_from_sockptr(&entries, optval, sizeof(entries)))
return -EFAULT;
mutex_lock(&xs->mutex);

View File

@ -2264,7 +2264,7 @@ static bool km_is_alive(const struct km_event *c)
return is_alive;
}
int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
{
int err;
u8 *data;
@ -2274,7 +2274,7 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
if (in_compat_syscall())
return -EOPNOTSUPP;
if (!optval && !optlen) {
if (sockptr_is_null(optval) && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
__sk_dst_reset(sk);
@ -2284,7 +2284,7 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
if (optlen <= 0 || optlen > PAGE_SIZE)
return -EMSGSIZE;
data = memdup_user(optval, optlen);
data = memdup_sockptr(optval, optlen);
if (IS_ERR(data))
return PTR_ERR(data);