mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ipv4: igmp: convert ip_mc_msfget() to sockopt_t
IP_MSFILTER reads its reply through ip_mc_msfget(), reached from do_ip_getsockopt() and from nowhere else. Convert it, and build the sockopt_t at the call site for as long as the caller still carries a sockptr_t pair. optlen here only has to cover the header, and the real reply size comes from the imsf_numsrc field inside it. This is nasty, but userspace relies on it, so sockopt_expand_out() preserves the same mechanism: it grows optval only for a user address, and assumes the caller left room for the size its own header asked for. The *optlen store moves out of ip_mc_msfget() and into the call site, guarded by !err so the -EINVAL, -ENODEV and -EADDRNOTAVAIL returns still leave the caller's optlen word untouched. The source list also moves from copy_to_sockptr_offset() to a sequential copy_to_iter(). IP_MSFILTER_SIZE(0) and offsetof(struct ip_msfilter, imsf_slist_flex) are both 16, so the bytes land where they did. Signed-off-by: Breno Leitao <leitao@debian.org> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20260914-getsockopt_phase6-v2-2-e48befc9602e@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
0093f7db9c
commit
e12e04f5ab
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/timer.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/sockptr.h>
|
||||
#include <uapi/linux/igmp.h>
|
||||
|
|
@ -273,7 +274,7 @@ extern int ip_mc_source(int add, int omode, struct sock *sk,
|
|||
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_msfget(struct sock *sk, struct ip_msfilter *msf,
|
||||
sockptr_t optval, sockptr_t optlen);
|
||||
sockopt_t *opt);
|
||||
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
|
||||
sockptr_t optval, size_t offset);
|
||||
extern int ip_mc_sf_allow(const struct sock *sk, __be32 local, __be32 rmt,
|
||||
|
|
|
|||
|
|
@ -2709,8 +2709,8 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
|
|||
err = ip_mc_leave_group(sk, &imr);
|
||||
return err;
|
||||
}
|
||||
int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
|
||||
sockptr_t optval, sockptr_t optlen)
|
||||
|
||||
int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, sockopt_t *opt)
|
||||
{
|
||||
int err, len, count, copycount, msf_size;
|
||||
struct ip_mreqn imr;
|
||||
|
|
@ -2755,14 +2755,19 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
|
|||
len = flex_array_size(psl, sl_addr, copycount);
|
||||
msf->imsf_numsrc = count;
|
||||
msf_size = IP_MSFILTER_SIZE(copycount);
|
||||
if (copy_to_sockptr(optlen, &msf_size, sizeof(int)) ||
|
||||
copy_to_sockptr(optval, msf, IP_MSFILTER_SIZE(0))) {
|
||||
|
||||
/* The source list is sized by the imsf_numsrc the caller left in
|
||||
* optval, not by optlen, which only has to cover the fixed part.
|
||||
*/
|
||||
err = sockopt_expand_out(opt, msf_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
opt->optlen = msf_size;
|
||||
if (copy_to_iter(msf, IP_MSFILTER_SIZE(0), &opt->iter_out) !=
|
||||
IP_MSFILTER_SIZE(0))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (len &&
|
||||
copy_to_sockptr_offset(optval,
|
||||
offsetof(struct ip_msfilter, imsf_slist_flex),
|
||||
psl->sl_addr, len))
|
||||
if (len && copy_to_iter(psl->sl_addr, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
|
|||
case IP_MSFILTER:
|
||||
{
|
||||
struct ip_msfilter msf;
|
||||
struct kvec kvec;
|
||||
sockopt_t opt;
|
||||
|
||||
if (len < IP_MSFILTER_SIZE(0)) {
|
||||
err = -EINVAL;
|
||||
|
|
@ -1715,7 +1717,13 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
|
|||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
err = ip_mc_msfget(sk, &msf, optval, optlen);
|
||||
err = sockptr_to_sockopt(&opt, optval, optlen, &kvec);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ip_mc_msfget(sk, &msf, &opt);
|
||||
if (!err && copy_to_sockptr(optlen, &opt.optlen, sizeof(int)))
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
case MCAST_MSFILTER:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user