From: "Maciej Żenczykowski" <maze@google.com>
To: "Maciej Żenczykowski" <zenczykowski@gmail.com>
Cc: "Linux Network Development Mailing List" <netdev@vger.kernel.org>,
"Fernando Fernandez Mancera" <fmancera@suse.de>,
"Maciej Żenczykowski" <maze@google.com>
Subject: [PATCH] [RFC] net-ipv6: ipv4 emulation support
Date: Mon, 13 Jul 2026 01:16:06 -0700 [thread overview]
Message-ID: <20260713081606.950892-1-maze@google.com> (raw)
Change-Id: Ibab1a59f4730f3fd0a7d14fffc5100a02a170ac6
---
gconfigs/Gconfig.net-configs.ipv6 | 2 +
include/linux/ipv6.h | 6 +-
include/linux/socket.h | 5 +-
include/net/compat.h | 2 +-
net/compat.c | 6 +-
net/core/iovec.c | 4 +-
net/ipv6/Kconfig | 19 +++
net/ipv6/af_inet6.c | 5 +
net/ipv6/ipv6_sockglue.c | 8 +-
net/ipv6/sysctl_net_ipv6.c | 26 ++++
net/socket.c | 211 +++++++++++++++++++++++++++---
11 files changed, 260 insertions(+), 34 deletions(-)
create mode 100644 gconfigs/Gconfig.net-configs.ipv6
diff --git a/gconfigs/Gconfig.net-configs.ipv6 b/gconfigs/Gconfig.net-configs.ipv6
new file mode 100644
index 000000000000..9eb5694bae8e
--- /dev/null
+++ b/gconfigs/Gconfig.net-configs.ipv6
@@ -0,0 +1,2 @@
+CONFIG_IPV6_IPV4_EMULATE=y
+CONFIG_IPV6_IPV4_EMULATE_SYSCTL_DEFAULT=y
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index ff560537dd61..8bc5306094b5 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -157,11 +157,13 @@ struct ipv6_pinfo {
#if defined(__BIG_ENDIAN_BITFIELD)
/* Packed in 16bits. */
__s16 mcast_hops:9;
- __u16 __unused_2:6,
+ __u16 __unused_2:5,
+ ipv4emu:1,
mc_loop:1;
#else
__u16 mc_loop:1,
- __unused_2:6;
+ ipv4emu:1,
+ __unused_2:5;
__s16 mcast_hops:9;
#endif
int ucast_oif;
diff --git a/include/linux/socket.h b/include/linux/socket.h
index bb9b83640070..4ae959a3443b 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -8,6 +8,7 @@
#include <linux/types.h> /* pid_t */
#include <linux/compiler.h> /* __user */
#include <uapi/linux/socket.h>
+struct sock; /* from net/sock.h */
struct pid;
struct cred;
@@ -312,8 +313,8 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
extern unsigned long iov_pages(const struct iovec *iov, int offset,
unsigned long nr_segs);
-extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode);
-extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
+extern int verify_iovec(struct sock *sk, struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode);
+extern int move_addr_to_kernel(struct sock *sk, void __user *uaddr, int *ulen, struct sockaddr_storage *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
struct timespec;
diff --git a/include/net/compat.h b/include/net/compat.h
index 3b603b199c01..b9ee7aa5a31f 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -41,7 +41,7 @@ int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
#endif /* defined(CONFIG_COMPAT) */
int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *);
-int verify_compat_iovec(struct msghdr *, struct iovec *,
+int verify_compat_iovec(struct sock *, struct msghdr *, struct iovec *,
struct sockaddr_storage *, int);
asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *,
unsigned int);
diff --git a/net/compat.c b/net/compat.c
index bc8aeefddf3f..f66bd6552204 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -80,15 +80,15 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg)
}
/* I've named the args so it is easy to tell whose space the pointers are in. */
-int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
+int verify_compat_iovec(struct sock *sk, struct msghdr *kern_msg, struct iovec *kern_iov,
struct sockaddr_storage *kern_address, int mode)
{
int tot_len;
if (kern_msg->msg_name && kern_msg->msg_namelen) {
if (mode == VERIFY_READ) {
- int err = move_addr_to_kernel(kern_msg->msg_name,
- kern_msg->msg_namelen,
+ int err = move_addr_to_kernel(sk, kern_msg->msg_name,
+ &kern_msg->msg_namelen,
kern_address);
if (err < 0)
return err;
diff --git a/net/core/iovec.c b/net/core/iovec.c
index e1ec45ab1e63..a7a393cae2a7 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -35,7 +35,7 @@
* in any case.
*/
-int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode)
+int verify_iovec(struct sock *sk, struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode)
{
int size, ct, err;
@@ -43,7 +43,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
if (mode == VERIFY_READ) {
void __user *namep;
namep = (void __user __force *) m->msg_name;
- err = move_addr_to_kernel(namep, m->msg_namelen,
+ err = move_addr_to_kernel(sk, namep, &m->msg_namelen,
address);
if (err < 0)
return err;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 438a73aa777c..69924a6c2257 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -21,6 +21,25 @@ menuconfig IPV6
if IPV6
+config IPV6_IPV4_EMULATE
+ bool "IPv6: IPv4 socket interface emulation support"
+ default n
+ depends on IPV6=y
+ ---help---
+ Whether to include support code which allows using a kernel IPv6
+ socket from userspace as if it was an IPv4 socket.
+
+ ie. this is a userspace-kernel IP address translation shim layer.
+
+config IPV6_IPV4_EMULATE_SYSCTL_DEFAULT
+ bool "IPv6: IPv4 socket emulation - default sysctl setting"
+ default n
+ depends on IPV6_IPV4_EMULATE
+ ---help---
+ Default value for /proc/sys/net/ipv6/ipv4_emulation
+ The content of this sysctl file determines whether userspace asking
+ for IPv4 sockets gets IPv6 sockets with IPv4 emulation turned on.
+
config IPV6_ROUTER_PREF
bool "IPv6: Router Preference (RFC 4191) support"
---help---
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e8c4400f23e9..4f08abdf06e0 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -476,6 +476,11 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk;
struct net *net = sock_net(sk);
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ if (inet6_sk(sk)->ipv4emu)
+ return inet_ioctl(sock, cmd, arg);
+#endif
+
switch (cmd) {
case SIOCGSTAMP:
return sock_get_timestamp(sk, (struct timeval __user *)arg);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index e1a9583bb419..2e97c6d55b62 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -857,7 +857,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
- if (level != SOL_IPV6)
+ if ((level != SOL_IPV6) || (inet6_sk(sk)->ipv4emu))
return -ENOPROTOOPT;
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
@@ -888,7 +888,7 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
}
- if (level != SOL_IPV6)
+ if ((level != SOL_IPV6) || (inet6_sk(sk)->ipv4emu))
return -ENOPROTOOPT;
if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
@@ -1297,7 +1297,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
- if (level != SOL_IPV6)
+ if ((level != SOL_IPV6) || (inet6_sk(sk)->ipv4emu))
return -ENOPROTOOPT;
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
@@ -1334,7 +1334,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
}
- if (level != SOL_IPV6)
+ if ((level != SOL_IPV6) || (inet6_sk(sk)->ipv4emu))
return -ENOPROTOOPT;
if (optname == MCAST_MSFILTER)
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index c5c10fafcfe2..0ab6a8d5aa57 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -6,6 +6,7 @@
*/
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/sysctl.h>
#include <linux/in6.h>
#include <linux/ipv6.h>
@@ -18,6 +19,20 @@
static int one = 1;
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+static int zero;
+
+# if defined(CONFIG_IPV6_IPV4_EMULATE_SYSCTL_DEFAULT)
+bool sysctl_ipv4_emulation = true;
+# else
+bool sysctl_ipv4_emulation = false;
+# endif
+
+module_param_named(ipv4_emulation, sysctl_ipv4_emulation, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ipv4_emulation,
+ "Auto promote PF_INET sockets into PF_INET6 sockets, with IPv4 API emulation.");
+#endif
+
static struct ctl_table ipv6_table_template[] = {
{
.procname = "bindv6only",
@@ -73,6 +88,17 @@ static struct ctl_table ipv6_rotable[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &one
},
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ {
+ .procname = "ipv4_emulation",
+ .data = &sysctl_ipv4_emulation,
+ .maxlen = sizeof(bool),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
{ }
};
diff --git a/net/socket.c b/net/socket.c
index fe20c319a0bb..e7d2f5281ff3 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -101,6 +101,7 @@
#include <linux/netfilter.h>
#include <linux/if_tun.h>
+#include <linux/ipv6.h>
#include <linux/ipv6_route.h>
#include <linux/route.h>
#include <linux/sockios.h>
@@ -178,30 +179,171 @@ static DEFINE_PER_CPU(int, sockets_in_use);
* divide and look after the messy bits.
*/
+static int ipv6_promote_ipv4_address(struct sock *sk,
+ struct sockaddr_storage * kaddr, int * addr_len)
+{
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ if (!sk) {
+ pr_warning("ipv6_promote_ipv4_address: no sk\n");
+ return 0;
+ }
+
+ if (sk->sk_family != PF_INET6) {
+ //pr_warning("ipv6_promote_ipv4_address: sk_family == %d\n", sk->sk_family);
+ return 0;
+ }
+
+ if (!inet6_sk(sk)->ipv4emu) {
+ //pr_warning("ipv6_promote_ipv4_address: not ipv4emu\n");
+ return 0;
+ }
+
+ if (kaddr->ss_family == AF_UNSPEC) {
+ //pr_warning("ipv6_promote_ipv4_address: unspec\n");
+ return 0;
+ }
+
+ if (kaddr->ss_family != AF_INET) {
+ pr_warning("ipv6_promote_ipv4_address: addr is %d\n", kaddr->ss_family);
+ return -EAFNOSUPPORT;
+ }
+
+ if (*addr_len < sizeof(struct sockaddr_in)) {
+ pr_warning("ipv6_promote_ipv4_address: addr_len == %d\n", *addr_len);
+ return -EINVAL;
+ }
+
+ {
+ const struct sockaddr_in * kaddr4 = (const struct sockaddr_in *)kaddr;
+ struct sockaddr_in6 * kaddr6 = (struct sockaddr_in6 *)kaddr;
+ __be16 port = kaddr4->sin_port;
+ __be32 ipv4 = kaddr4->sin_addr.s_addr;
+
+ //*addr_len = sizeof(struct sockaddr_in6);
+ *addr_len = 24; //SIN6_LEN_RFC2133; /* 24 = 2+2+4+16, ie. without scope id */
+// Why not fill in scope_id with 0 ?
+// One way to avoid the magic 24 constant is to use offsetof(struct sockaddr_in6, scope_id)
+ kaddr6->sin6_family = AF_INET6;
+ kaddr6->sin6_port = port;
+ kaddr6->sin6_flowinfo = htonl(0);
+ kaddr6->sin6_addr.s6_addr32[0] = htonl(0);
+ kaddr6->sin6_addr.s6_addr32[1] = htonl(0);
+ kaddr6->sin6_addr.s6_addr32[2] = ntohl(ipv4) ? htonl(0xFFFF) : htonl(0);
+ kaddr6->sin6_addr.s6_addr32[3] = ipv4;
+ kaddr6->sin6_scope_id = 0;
+
+ pr_debug("ipv6_promote_ipv4_address: ok [%08X:%d]\n", ntohl(ipv4), ntohs(port));
+ }
+#endif
+ return 0;
+}
+
+static int ipv6_demote_ipv6_address(struct sock *sk, struct sockaddr_storage * kaddr, int * addr_len) {
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ if (!sk) {
+ pr_warning("ipv6_demote_ipv6_address: no sk\n");
+ return 0;
+ }
+
+ if (sk->sk_family != PF_INET6) {
+ //pr_warning("ipv6_demote_ipv6_address: sk_family == %d\n", sk->sk_family);
+ return 0;
+ }
+
+ if (!inet6_sk(sk)->ipv4emu) {
+ //pr_warning("ipv6_demote_ipv6_address: not ipv4emu\n");
+ return 0;
+ }
+
+ if (kaddr->ss_family != AF_INET6) {
+ pr_warning("ipv6_demote_ipv6_address: addr is %d\n", kaddr->ss_family);
+ return -EAFNOSUPPORT;
+ }
+
+ if (*addr_len < sizeof(struct sockaddr_in6)) {
+ pr_warning("ipv6_demote_ipv6_address: addr_len == %d\n", *addr_len);
+ return -EINVAL;
+ }
+
+ {
+ struct sockaddr_in6 const * kaddr6 = (struct sockaddr_in6 const *)kaddr;
+ struct sockaddr_in * kaddr4 = (struct sockaddr_in *)kaddr;
+ __be16 port = kaddr6->sin6_port;
+ __be32 ipv6a = kaddr6->sin6_addr.s6_addr32[0];
+ __be32 ipv6b = kaddr6->sin6_addr.s6_addr32[1];
+ __be32 ipv6c = kaddr6->sin6_addr.s6_addr32[2];
+ __be32 ipv4 = kaddr6->sin6_addr.s6_addr32[3];
+
+// please use ipv6_addr_v4mapped()
+
+ if (ipv6a) {
+ pr_warning("ipv6_demote_ipv6_address: not mapped [1]\n");
+ return -EINVAL;
+ }
+
+ if (ipv6b) {
+ pr_warning("ipv6_demote_ipv6_address: not mapped [2]\n");
+ return -EINVAL;
+ }
+
+ if ((ipv6c != htonl(0)) && (ipv6c != htonl(0xFFFF))) {
+ pr_warning("ipv6_demote_ipv6_address: not mapped [3]\n");
+ return -EINVAL;
+ }
+
+ if ((ipv6c == htonl(0)) && (ipv4 != htonl(0))) {
+ pr_warning("ipv6_demote_ipv6_address: not mapped [4]\n");
+ return -EINVAL;
+ }
+
+// Really avoid those magic values...
+// Since I doubt this is performance critical, just do the whole struct clear at the beginning:
+// memset(uaddr4, 0, sizeof(*uaddr4));
+
+ *addr_len = sizeof(struct sockaddr_in); // 2 + 2 + 4 + 8 padding
+ kaddr4->sin_family = AF_INET;
+ kaddr4->sin_port = port;
+ kaddr4->sin_addr.s_addr = ipv4;
+ memset(kaddr4->sin_zero, 0, 8);
+
+ pr_debug("ipv6_demote_ipv6_address: ok [%08X:%d]\n", ntohl(ipv4), ntohs(port));
+ }
+#endif
+ return 0;
+}
+
/**
* move_addr_to_kernel - copy a socket address into kernel space
+ * @sk: socket which is receiving the address (or NULL)
* @uaddr: Address in user space
* @kaddr: Address in kernel space
- * @ulen: Length in user space
+ * @ulen: pointer to user space length
*
* The address is copied into kernel space. If the provided address is
* too long an error code of -EINVAL is returned. If the copy gives
* invalid addresses -EFAULT is returned. On a success 0 is returned.
*/
-int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
+int move_addr_to_kernel(struct sock *sk, void __user *uaddr, int *ulen,
+ struct sockaddr_storage *kaddr)
{
- if (ulen < 0 || ulen > sizeof(struct sockaddr_storage))
+ int err;
+
+ if (*ulen < 0 || *ulen > sizeof(struct sockaddr_storage))
return -EINVAL;
- if (ulen == 0)
+ if (*ulen == 0)
return 0;
- if (copy_from_user(kaddr, uaddr, ulen))
+ if (copy_from_user(kaddr, uaddr, *ulen))
return -EFAULT;
- return audit_sockaddr(ulen, kaddr);
+ err = audit_sockaddr(*ulen, kaddr);
+ if (err)
+ return err;
+ return ipv6_promote_ipv4_address(sk, kaddr, ulen);
}
/**
* move_addr_to_user - copy an address to user space
+ * @sk: socket which is generating the address (or NULL)
* @kaddr: kernel space address
* @klen: length of address in kernel
* @uaddr: user space address
@@ -217,7 +359,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *k
* specified. Zero is returned for a success.
*/
-static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
+static int move_addr_to_user(struct sock *sk, struct sockaddr_storage *kaddr, int klen,
void __user *uaddr, int __user *ulen)
{
int err;
@@ -225,6 +367,9 @@ static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
BUG_ON(klen > sizeof(struct sockaddr_storage));
err = get_user(len, ulen);
+ if (err)
+ return err;
+ err = ipv6_demote_ipv6_address(sk, kaddr, &klen);
if (err)
return err;
if (len > klen)
@@ -1249,12 +1394,19 @@ call_kill:
}
EXPORT_SYMBOL(sock_wake_async);
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+extern bool sysctl_ipv4_emulation;
+#endif
+
int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
{
int err;
struct socket *sock;
const struct net_proto_family *pf;
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ bool ipv4emu = false;
+#endif
/*
* Check protocol is in range
@@ -1283,6 +1435,13 @@ int __sock_create(struct net *net, int family, int type, int protocol,
if (err)
return err;
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ if (sysctl_ipv4_emulation && !kern && family == PF_INET) {
+ family = PF_INET6;
+ ipv4emu = true;
+ }
+#endif
+
/*
* Allocate the socket and allow the family to set things up. if
* the protocol is 0, the family is instructed to select an appropriate
@@ -1328,6 +1487,14 @@ int __sock_create(struct net *net, int family, int type, int protocol,
if (err < 0)
goto out_module_put;
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ if (ipv4emu) {
+ inet6_sk(sock->sk)->ipv4emu = 1;
+ /* we need to clear ipv6only, since it could have defaulted to true via sysctl */
+ sock->sk->sk_ipv6only = 0;
+ }
+#endif
+
/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
@@ -1532,7 +1699,7 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
- err = move_addr_to_kernel(umyaddr, addrlen, &address);
+ err = move_addr_to_kernel(sock->sk, umyaddr, &addrlen, &address);
if (err >= 0) {
err = security_socket_bind(sock,
(struct sockaddr *)&address,
@@ -1646,7 +1813,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
err = -ECONNABORTED;
goto out_fd;
}
- err = move_addr_to_user(&address,
+ err = move_addr_to_user(newsock->sk, &address,
len, upeer_sockaddr, upeer_addrlen);
if (err < 0)
goto out_fd;
@@ -1695,7 +1862,7 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
- err = move_addr_to_kernel(uservaddr, addrlen, &address);
+ err = move_addr_to_kernel(sock->sk, uservaddr, &addrlen, &address);
if (err < 0)
goto out_put;
@@ -1735,7 +1902,7 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
if (err)
goto out_put;
- err = move_addr_to_user(&address, len, usockaddr, usockaddr_len);
+ err = move_addr_to_user(sock->sk, &address, len, usockaddr, usockaddr_len);
out_put:
fput_light(sock->file, fput_needed);
@@ -1767,7 +1934,7 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
sock->ops->getname(sock, (struct sockaddr *)&address, &len,
1);
if (!err)
- err = move_addr_to_user(&address, len, usockaddr,
+ err = move_addr_to_user(sock->sk, &address, len, usockaddr,
usockaddr_len);
fput_light(sock->file, fput_needed);
}
@@ -1806,7 +1973,7 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
msg.msg_controllen = 0;
msg.msg_namelen = 0;
if (addr) {
- err = move_addr_to_kernel(addr, addr_len, &address);
+ err = move_addr_to_kernel(sock->sk, addr, &addr_len, &address);
if (err < 0)
goto out_put;
msg.msg_name = (struct sockaddr *)&address;
@@ -1871,7 +2038,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
err = sock_recvmsg(sock, &msg, size, flags);
if (err >= 0 && addr != NULL) {
- err2 = move_addr_to_user(&address,
+ err2 = move_addr_to_user(sock->sk, &address,
msg.msg_namelen, addr, addr_len);
if (err2 < 0)
err = err2;
@@ -2042,9 +2209,9 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
/* This will also move the address data into kernel space */
if (MSG_CMSG_COMPAT & flags) {
- err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ);
+ err = verify_compat_iovec(sock->sk, msg_sys, iov, &address, VERIFY_READ);
} else
- err = verify_iovec(msg_sys, iov, &address, VERIFY_READ);
+ err = verify_iovec(sock->sk, msg_sys, iov, &address, VERIFY_READ);
if (err < 0)
goto out_freeiov;
total_len = err;
@@ -2258,9 +2425,9 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
uaddr = (__force void __user *)msg_sys->msg_name;
uaddr_len = COMPAT_NAMELEN(msg);
if (MSG_CMSG_COMPAT & flags)
- err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
+ err = verify_compat_iovec(sock->sk, msg_sys, iov, &addr, VERIFY_WRITE);
else
- err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
+ err = verify_iovec(sock->sk, msg_sys, iov, &addr, VERIFY_WRITE);
if (err < 0)
goto out_freeiov;
total_len = err;
@@ -2280,7 +2447,7 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
len = err;
if (uaddr != NULL) {
- err = move_addr_to_user(&addr,
+ err = move_addr_to_user(sock->sk, &addr,
msg_sys->msg_namelen, uaddr,
uaddr_len);
if (err < 0)
@@ -3159,7 +3326,11 @@ static int routing_ioctl(struct net *net, struct socket *sock,
u32 rtdev;
mm_segment_t old_fs = get_fs();
- if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
+ if (sock && sock->sk && sock->sk->sk_family == AF_INET6
+#if defined(CONFIG_IPV6_IPV4_EMULATE)
+ && !inet6_sk(sock->sk)->ipv4emu
+#endif
+ ) { /* ipv6 */
struct in6_rtmsg32 __user *ur6 = argp;
ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
3 * sizeof(struct in6_addr));
--
2.55.0.795.g602f6c329a-goog
next reply other threads:[~2026-07-13 8:16 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 8:16 Maciej Żenczykowski [this message]
2026-07-13 9:05 ` [PATCH] [RFC] net-ipv6: ipv4 emulation support Maciej Żenczykowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260713081606.950892-1-maze@google.com \
--to=maze@google.com \
--cc=fmancera@suse.de \
--cc=netdev@vger.kernel.org \
--cc=zenczykowski@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.