Commit 728f064c authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Alexei Starovoitov

bpf: net: Change do_ip_getsockopt() to take the sockptr_t argument

Similar to the earlier patch that changes sk_getsockopt() to
take the sockptr_t argument.  This patch also changes
do_ip_getsockopt() to take the sockptr_t argument such that
a latter patch can make bpf_getsockopt(SOL_IP) to reuse
do_ip_getsockopt().

Note on the change in ip_mc_gsfget().  This function is to
return an array of sockaddr_storage in optval.  This function
is shared between ip_get_mcast_msfilter() and
compat_ip_get_mcast_msfilter().  However, the sockaddr_storage
is stored at different offset of the optval because of
the difference between group_filter and compat_group_filter.
Thus, a new 'ss_offset' argument is added to ip_mc_gsfget().
Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20220902002828.2890585-1-kafai@fb.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent d51bbff2
...@@ -118,9 +118,9 @@ extern int ip_mc_source(int add, int omode, struct sock *sk, ...@@ -118,9 +118,9 @@ extern int ip_mc_source(int add, int omode, struct sock *sk,
struct ip_mreq_source *mreqs, int ifindex); struct ip_mreq_source *mreqs, int ifindex);
extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex); extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);
extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_msfilter __user *optval, int __user *optlen); sockptr_t optval, sockptr_t optlen);
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct sockaddr_storage __user *p); sockptr_t optval, size_t offset);
extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt,
int dif, int sdif); int dif, int sdif);
extern void ip_mc_init_dev(struct in_device *); extern void ip_mc_init_dev(struct in_device *);
......
...@@ -17,7 +17,7 @@ static inline int ip_mroute_opt(int opt) ...@@ -17,7 +17,7 @@ static inline int ip_mroute_opt(int opt)
} }
int ip_mroute_setsockopt(struct sock *, int, sockptr_t, 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 ip_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t);
int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
int ip_mr_init(void); int ip_mr_init(void);
...@@ -29,8 +29,8 @@ static inline int ip_mroute_setsockopt(struct sock *sock, int optname, ...@@ -29,8 +29,8 @@ static inline int ip_mroute_setsockopt(struct sock *sock, int optname,
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
static inline int ip_mroute_getsockopt(struct sock *sock, int optname, static inline int ip_mroute_getsockopt(struct sock *sk, int optname,
char __user *optval, int __user *optlen) sockptr_t optval, sockptr_t optlen)
{ {
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
......
...@@ -2529,11 +2529,10 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) ...@@ -2529,11 +2529,10 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
err = ip_mc_leave_group(sk, &imr); err = ip_mc_leave_group(sk, &imr);
return err; return err;
} }
int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_msfilter __user *optval, int __user *optlen) sockptr_t optval, sockptr_t optlen)
{ {
int err, len, count, copycount; int err, len, count, copycount, msf_size;
struct ip_mreqn imr; struct ip_mreqn imr;
__be32 addr = msf->imsf_multiaddr; __be32 addr = msf->imsf_multiaddr;
struct ip_mc_socklist *pmc; struct ip_mc_socklist *pmc;
...@@ -2575,12 +2574,15 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, ...@@ -2575,12 +2574,15 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc; copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc;
len = flex_array_size(psl, sl_addr, copycount); len = flex_array_size(psl, sl_addr, copycount);
msf->imsf_numsrc = count; msf->imsf_numsrc = count;
if (put_user(IP_MSFILTER_SIZE(copycount), optlen) || msf_size = IP_MSFILTER_SIZE(copycount);
copy_to_user(optval, msf, IP_MSFILTER_SIZE(0))) { if (copy_to_sockptr(optlen, &msf_size, sizeof(int)) ||
copy_to_sockptr(optval, msf, IP_MSFILTER_SIZE(0))) {
return -EFAULT; return -EFAULT;
} }
if (len && if (len &&
copy_to_user(&optval->imsf_slist_flex[0], psl->sl_addr, len)) copy_to_sockptr_offset(optval,
offsetof(struct ip_msfilter, imsf_slist_flex),
psl->sl_addr, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
done: done:
...@@ -2588,7 +2590,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, ...@@ -2588,7 +2590,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
} }
int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct sockaddr_storage __user *p) sockptr_t optval, size_t ss_offset)
{ {
int i, count, copycount; int i, count, copycount;
struct sockaddr_in *psin; struct sockaddr_in *psin;
...@@ -2618,15 +2620,17 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, ...@@ -2618,15 +2620,17 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
count = psl ? psl->sl_count : 0; count = psl ? psl->sl_count : 0;
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
gsf->gf_numsrc = count; gsf->gf_numsrc = count;
for (i = 0; i < copycount; i++, p++) { for (i = 0; i < copycount; i++) {
struct sockaddr_storage ss; struct sockaddr_storage ss;
psin = (struct sockaddr_in *)&ss; psin = (struct sockaddr_in *)&ss;
memset(&ss, 0, sizeof(ss)); memset(&ss, 0, sizeof(ss));
psin->sin_family = AF_INET; psin->sin_family = AF_INET;
psin->sin_addr.s_addr = psl->sl_addr[i]; psin->sin_addr.s_addr = psl->sl_addr[i];
if (copy_to_user(p, &ss, sizeof(ss))) if (copy_to_sockptr_offset(optval, ss_offset,
&ss, sizeof(ss)))
return -EFAULT; return -EFAULT;
ss_offset += sizeof(ss);
} }
return 0; return 0;
} }
......
...@@ -1462,37 +1462,37 @@ static bool getsockopt_needs_rtnl(int optname) ...@@ -1462,37 +1462,37 @@ static bool getsockopt_needs_rtnl(int optname)
return false; return false;
} }
static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval, static int ip_get_mcast_msfilter(struct sock *sk, sockptr_t optval,
int __user *optlen, int len) sockptr_t optlen, int len)
{ {
const int size0 = offsetof(struct group_filter, gf_slist_flex); const int size0 = offsetof(struct group_filter, gf_slist_flex);
struct group_filter __user *p = optval;
struct group_filter gsf; struct group_filter gsf;
int num; int num, gsf_size;
int err; int err;
if (len < size0) if (len < size0)
return -EINVAL; return -EINVAL;
if (copy_from_user(&gsf, p, size0)) if (copy_from_sockptr(&gsf, optval, size0))
return -EFAULT; return -EFAULT;
num = gsf.gf_numsrc; num = gsf.gf_numsrc;
err = ip_mc_gsfget(sk, &gsf, p->gf_slist_flex); err = ip_mc_gsfget(sk, &gsf, optval,
offsetof(struct group_filter, gf_slist_flex));
if (err) if (err)
return err; return err;
if (gsf.gf_numsrc < num) if (gsf.gf_numsrc < num)
num = gsf.gf_numsrc; num = gsf.gf_numsrc;
if (put_user(GROUP_FILTER_SIZE(num), optlen) || gsf_size = GROUP_FILTER_SIZE(num);
copy_to_user(p, &gsf, size0)) if (copy_to_sockptr(optlen, &gsf_size, sizeof(int)) ||
copy_to_sockptr(optval, &gsf, size0))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval, static int compat_ip_get_mcast_msfilter(struct sock *sk, sockptr_t optval,
int __user *optlen, int len) sockptr_t optlen, int len)
{ {
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex); const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
struct compat_group_filter __user *p = optval;
struct compat_group_filter gf32; struct compat_group_filter gf32;
struct group_filter gf; struct group_filter gf;
int num; int num;
...@@ -1500,7 +1500,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval, ...@@ -1500,7 +1500,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
if (len < size0) if (len < size0)
return -EINVAL; return -EINVAL;
if (copy_from_user(&gf32, p, size0)) if (copy_from_sockptr(&gf32, optval, size0))
return -EFAULT; return -EFAULT;
gf.gf_interface = gf32.gf_interface; gf.gf_interface = gf32.gf_interface;
...@@ -1508,21 +1508,24 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval, ...@@ -1508,21 +1508,24 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
num = gf.gf_numsrc = gf32.gf_numsrc; num = gf.gf_numsrc = gf32.gf_numsrc;
gf.gf_group = gf32.gf_group; gf.gf_group = gf32.gf_group;
err = ip_mc_gsfget(sk, &gf, p->gf_slist_flex); err = ip_mc_gsfget(sk, &gf, optval,
offsetof(struct compat_group_filter, gf_slist_flex));
if (err) if (err)
return err; return err;
if (gf.gf_numsrc < num) if (gf.gf_numsrc < num)
num = gf.gf_numsrc; num = gf.gf_numsrc;
len = GROUP_FILTER_SIZE(num) - (sizeof(gf) - sizeof(gf32)); len = GROUP_FILTER_SIZE(num) - (sizeof(gf) - sizeof(gf32));
if (put_user(len, optlen) || if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
put_user(gf.gf_fmode, &p->gf_fmode) || copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_fmode),
put_user(gf.gf_numsrc, &p->gf_numsrc)) &gf.gf_fmode, sizeof(gf.gf_fmode)) ||
copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_numsrc),
&gf.gf_numsrc, sizeof(gf.gf_numsrc)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
static int do_ip_getsockopt(struct sock *sk, int level, int optname, static int do_ip_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) sockptr_t optval, sockptr_t optlen)
{ {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
bool needs_rtnl = getsockopt_needs_rtnl(optname); bool needs_rtnl = getsockopt_needs_rtnl(optname);
...@@ -1535,7 +1538,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1535,7 +1538,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (ip_mroute_opt(optname)) if (ip_mroute_opt(optname))
return ip_mroute_getsockopt(sk, optname, optval, optlen); return ip_mroute_getsockopt(sk, optname, optval, optlen);
if (get_user(len, optlen)) if (copy_from_sockptr(&len, optlen, sizeof(int)))
return -EFAULT; return -EFAULT;
if (len < 0) if (len < 0)
return -EINVAL; return -EINVAL;
...@@ -1560,15 +1563,17 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1560,15 +1563,17 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
inet_opt->opt.optlen); inet_opt->opt.optlen);
release_sock(sk); release_sock(sk);
if (opt->optlen == 0) if (opt->optlen == 0) {
return put_user(0, optlen); len = 0;
return copy_to_sockptr(optlen, &len, sizeof(int));
}
ip_options_undo(opt); ip_options_undo(opt);
len = min_t(unsigned int, len, opt->optlen); len = min_t(unsigned int, len, opt->optlen);
if (put_user(len, optlen)) if (copy_to_sockptr(optlen, &len, sizeof(int)))
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, opt->__data, len)) if (copy_to_sockptr(optval, opt->__data, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -1659,9 +1664,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1659,9 +1664,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
addr.s_addr = inet->mc_addr; addr.s_addr = inet->mc_addr;
release_sock(sk); release_sock(sk);
if (put_user(len, optlen)) if (copy_to_sockptr(optlen, &len, sizeof(int)))
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, &addr, len)) if (copy_to_sockptr(optval, &addr, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -1673,12 +1678,11 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1673,12 +1678,11 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) { if (copy_from_sockptr(&msf, optval, IP_MSFILTER_SIZE(0))) {
err = -EFAULT; err = -EFAULT;
goto out; goto out;
} }
err = ip_mc_msfget(sk, &msf, err = ip_mc_msfget(sk, &msf, optval, optlen);
(struct ip_msfilter __user *)optval, optlen);
goto out; goto out;
} }
case MCAST_MSFILTER: case MCAST_MSFILTER:
...@@ -1700,8 +1704,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1700,8 +1704,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (sk->sk_type != SOCK_STREAM) if (sk->sk_type != SOCK_STREAM)
return -ENOPROTOOPT; return -ENOPROTOOPT;
msg.msg_control_is_user = true; if (optval.is_kernel) {
msg.msg_control_user = optval; msg.msg_control_is_user = false;
msg.msg_control = optval.kernel;
} else {
msg.msg_control_is_user = true;
msg.msg_control_user = optval.user;
}
msg.msg_controllen = len; msg.msg_controllen = len;
msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0; msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;
...@@ -1722,7 +1731,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1722,7 +1731,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos); put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
} }
len -= msg.msg_controllen; len -= msg.msg_controllen;
return put_user(len, optlen); return copy_to_sockptr(optlen, &len, sizeof(int));
} }
case IP_FREEBIND: case IP_FREEBIND:
val = inet->freebind; val = inet->freebind;
...@@ -1742,15 +1751,15 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1742,15 +1751,15 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
unsigned char ucval = (unsigned char)val; unsigned char ucval = (unsigned char)val;
len = 1; len = 1;
if (put_user(len, optlen)) if (copy_to_sockptr(optlen, &len, sizeof(int)))
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, &ucval, 1)) if (copy_to_sockptr(optval, &ucval, 1))
return -EFAULT; return -EFAULT;
} else { } else {
len = min_t(unsigned int, sizeof(int), len); len = min_t(unsigned int, sizeof(int), len);
if (put_user(len, optlen)) if (copy_to_sockptr(optlen, &len, sizeof(int)))
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, &val, len)) if (copy_to_sockptr(optval, &val, len))
return -EFAULT; return -EFAULT;
} }
return 0; return 0;
...@@ -1767,7 +1776,8 @@ int ip_getsockopt(struct sock *sk, int level, ...@@ -1767,7 +1776,8 @@ int ip_getsockopt(struct sock *sk, int level,
{ {
int err; int err;
err = do_ip_getsockopt(sk, level, optname, optval, optlen); err = do_ip_getsockopt(sk, level, optname,
USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
#if IS_ENABLED(CONFIG_BPFILTER_UMH) #if IS_ENABLED(CONFIG_BPFILTER_UMH)
if (optname >= BPFILTER_IPT_SO_GET_INFO && if (optname >= BPFILTER_IPT_SO_GET_INFO &&
......
...@@ -1546,7 +1546,8 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, ...@@ -1546,7 +1546,8 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
} }
/* Getsock opt support for the multicast routing system. */ /* Getsock opt support for the multicast routing system. */
int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen) int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
sockptr_t optlen)
{ {
int olr; int olr;
int val; int val;
...@@ -1577,14 +1578,14 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int ...@@ -1577,14 +1578,14 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
if (get_user(olr, optlen)) if (copy_from_sockptr(&olr, optlen, sizeof(int)))
return -EFAULT; return -EFAULT;
olr = min_t(unsigned int, olr, sizeof(int)); olr = min_t(unsigned int, olr, sizeof(int));
if (olr < 0) if (olr < 0)
return -EINVAL; return -EINVAL;
if (put_user(olr, optlen)) if (copy_to_sockptr(optlen, &olr, sizeof(int)))
return -EFAULT; return -EFAULT;
if (copy_to_user(optval, &val, olr)) if (copy_to_sockptr(optval, &val, olr))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment