From: Greg Kroah-Hartman Date: Tue, 27 Feb 2024 10:48:40 +0000 (+0100) Subject: drop queue-6.1/net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch X-Git-Tag: v4.19.308~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=26778e2e1681d9036cef7765d4ec26181c902429;p=thirdparty%2Fkernel%2Fstable-queue.git drop queue-6.1/net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch Not really needed. --- diff --git a/queue-6.1/net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch b/queue-6.1/net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch deleted file mode 100644 index 994244ae120..00000000000 --- a/queue-6.1/net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch +++ /dev/null @@ -1,1078 +0,0 @@ -From 411791fe82c0b08a8c4ee827713133f47c2e890d Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Fri, 9 Jun 2023 08:27:42 -0700 -Subject: net: ioctl: Use kernel memory on protocol ioctl callbacks - -From: Breno Leitao - -[ Upstream commit e1d001fa5b477c4da46a29be1fcece91db7c7c6f ] - -Most of the ioctls to net protocols operates directly on userspace -argument (arg). Usually doing get_user()/put_user() directly in the -ioctl callback. This is not flexible, because it is hard to reuse these -functions without passing userspace buffers. - -Change the "struct proto" ioctls to avoid touching userspace memory and -operate on kernel buffers, i.e., all protocol's ioctl callbacks is -adapted to operate on a kernel memory other than on userspace (so, no -more {put,get}_user() and friends being called in the ioctl callback). - -This changes the "struct proto" ioctl format in the following way: - - int (*ioctl)(struct sock *sk, int cmd, -- unsigned long arg); -+ int *karg); - -(Important to say that this patch does not touch the "struct proto_ops" -protocols) - -So, the "karg" argument, which is passed to the ioctl callback, is a -pointer allocated to kernel space memory (inside a function wrapper). -This buffer (karg) may contain input argument (copied from userspace in -a prep function) and it might return a value/buffer, which is copied -back to userspace if necessary. There is not one-size-fits-all format -(that is I am using 'may' above), but basically, there are three type of -ioctls: - -1) Do not read from userspace, returns a result to userspace -2) Read an input parameter from userspace, and does not return anything - to userspace -3) Read an input from userspace, and return a buffer to userspace. - -The default case (1) (where no input parameter is given, and an "int" is -returned to userspace) encompasses more than 90% of the cases, but there -are two other exceptions. Here is a list of exceptions: - -* Protocol RAW: - * cmd = SIOCGETVIFCNT: - * input and output = struct sioc_vif_req - * cmd = SIOCGETSGCNT - * input and output = struct sioc_sg_req - * Explanation: for the SIOCGETVIFCNT case, userspace passes the input - argument, which is struct sioc_vif_req. Then the callback populates - the struct, which is copied back to userspace. - -* Protocol RAW6: - * cmd = SIOCGETMIFCNT_IN6 - * input and output = struct sioc_mif_req6 - * cmd = SIOCGETSGCNT_IN6 - * input and output = struct sioc_sg_req6 - -* Protocol PHONET: - * cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE - * input int (4 bytes) - * Nothing is copied back to userspace. - -For the exception cases, functions sock_sk_ioctl_inout() will -copy the userspace input, and copy it back to kernel space. - -The wrapper that prepare the buffer and put the buffer back to user is -sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now -calls sk_ioctl(), which will handle all cases. - -Signed-off-by: Breno Leitao -Reviewed-by: Willem de Bruijn -Reviewed-by: David Ahern -Reviewed-by: Kuniyuki Iwashima -Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org -Signed-off-by: Jakub Kicinski -Stable-dep-of: 3b2d9bc4d4ac ("phonet: take correct lock to peek at the RX queue") -Signed-off-by: Sasha Levin ---- - include/linux/icmpv6.h | 6 ++++ - include/linux/mroute.h | 22 +++++++++++-- - include/linux/mroute6.h | 31 ++++++++++++++++-- - include/net/phonet/phonet.h | 21 ++++++++++++ - include/net/sock.h | 5 ++- - include/net/tcp.h | 2 +- - include/net/udp.h | 2 +- - net/core/sock.c | 64 +++++++++++++++++++++++++++++++++++++ - net/dccp/dccp.h | 2 +- - net/dccp/proto.c | 12 +++---- - net/ieee802154/socket.c | 15 ++++----- - net/ipv4/af_inet.c | 2 +- - net/ipv4/ipmr.c | 63 ++++++++++++++++++++++-------------- - net/ipv4/raw.c | 16 +++++----- - net/ipv4/tcp.c | 5 +-- - net/ipv4/udp.c | 12 +++---- - net/ipv6/af_inet6.c | 2 +- - net/ipv6/ip6mr.c | 44 +++++++++++-------------- - net/ipv6/raw.c | 16 +++++----- - net/l2tp/l2tp_core.h | 2 +- - net/l2tp/l2tp_ip.c | 9 +++--- - net/mptcp/protocol.c | 11 +++---- - net/phonet/datagram.c | 11 +++---- - net/phonet/pep.c | 11 +++---- - net/phonet/socket.c | 2 +- - net/sctp/socket.c | 8 ++--- - 26 files changed, 267 insertions(+), 129 deletions(-) - -diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h -index db0f4fcfdaf4f..1fe33e6741cca 100644 ---- a/include/linux/icmpv6.h -+++ b/include/linux/icmpv6.h -@@ -111,4 +111,10 @@ static inline bool icmpv6_is_err(int type) - return false; - } - -+static inline int sk_is_icmpv6(struct sock *sk) -+{ -+ return sk->sk_family == AF_INET6 && -+ inet_sk(sk)->inet_num == IPPROTO_ICMPV6; -+} -+ - #endif -diff --git a/include/linux/mroute.h b/include/linux/mroute.h -index 80b8400ab8b24..94c6e6f549f0a 100644 ---- a/include/linux/mroute.h -+++ b/include/linux/mroute.h -@@ -16,12 +16,19 @@ static inline int ip_mroute_opt(int opt) - return opt >= MRT_BASE && opt <= MRT_MAX; - } - -+static inline int sk_is_ipmr(struct sock *sk) -+{ -+ return sk->sk_family == AF_INET && -+ inet_sk(sk)->inet_num == IPPROTO_IGMP; -+} -+ - int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int); - 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 *arg); - int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); - int ip_mr_init(void); - bool ipmr_rule_default(const struct fib_rule *rule); -+int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); - #else - static inline int ip_mroute_setsockopt(struct sock *sock, int optname, - sockptr_t optval, unsigned int optlen) -@@ -35,7 +42,7 @@ static inline int ip_mroute_getsockopt(struct sock *sk, int optname, - return -ENOPROTOOPT; - } - --static inline int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) -+static inline int ipmr_ioctl(struct sock *sk, int cmd, void *arg) - { - return -ENOIOCTLCMD; - } -@@ -50,10 +57,21 @@ static inline int ip_mroute_opt(int opt) - return 0; - } - -+static inline int sk_is_ipmr(struct sock *sk) -+{ -+ return 0; -+} -+ - static inline bool ipmr_rule_default(const struct fib_rule *rule) - { - return true; - } -+ -+static inline int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, -+ void __user *arg) -+{ -+ return 1; -+} - #endif - - #define VIFF_STATIC 0x8000 -diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h -index 8f2b307fb1241..2f95d5b4e47af 100644 ---- a/include/linux/mroute6.h -+++ b/include/linux/mroute6.h -@@ -29,10 +29,10 @@ struct sock; - extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int); - extern int ip6_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t); - extern int ip6_mr_input(struct sk_buff *skb); --extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); - extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); - extern int ip6_mr_init(void); - extern void ip6_mr_cleanup(void); -+int ip6mr_ioctl(struct sock *sk, int cmd, void *arg); - #else - static inline int ip6_mroute_setsockopt(struct sock *sock, int optname, - sockptr_t optval, unsigned int optlen) -@@ -48,7 +48,7 @@ int ip6_mroute_getsockopt(struct sock *sock, - } - - static inline --int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) -+int ip6mr_ioctl(struct sock *sk, int cmd, void *arg) - { - return -ENOIOCTLCMD; - } -@@ -100,6 +100,27 @@ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb, - #ifdef CONFIG_IPV6_MROUTE - bool mroute6_is_socket(struct net *net, struct sk_buff *skb); - extern int ip6mr_sk_done(struct sock *sk); -+static inline int ip6mr_sk_ioctl(struct sock *sk, unsigned int cmd, -+ void __user *arg) -+{ -+ switch (cmd) { -+ /* These userspace buffers will be consumed by ip6mr_ioctl() */ -+ case SIOCGETMIFCNT_IN6: { -+ struct sioc_mif_req6 buffer; -+ -+ return sock_ioctl_inout(sk, cmd, arg, &buffer, -+ sizeof(buffer)); -+ } -+ case SIOCGETSGCNT_IN6: { -+ struct sioc_mif_req6 buffer; -+ -+ return sock_ioctl_inout(sk, cmd, arg, &buffer, -+ sizeof(buffer)); -+ } -+ } -+ -+ return 1; -+} - #else - static inline bool mroute6_is_socket(struct net *net, struct sk_buff *skb) - { -@@ -109,5 +130,11 @@ static inline int ip6mr_sk_done(struct sock *sk) - { - return 0; - } -+ -+static inline int ip6mr_sk_ioctl(struct sock *sk, unsigned int cmd, -+ void __user *arg) -+{ -+ return 1; -+} - #endif - #endif -diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h -index 862f1719b5230..cf5ecae4a2fcd 100644 ---- a/include/net/phonet/phonet.h -+++ b/include/net/phonet/phonet.h -@@ -109,4 +109,25 @@ void phonet_sysctl_exit(void); - int isi_register(void); - void isi_unregister(void); - -+static inline bool sk_is_phonet(struct sock *sk) -+{ -+ return sk->sk_family == PF_PHONET; -+} -+ -+static inline int phonet_sk_ioctl(struct sock *sk, unsigned int cmd, -+ void __user *arg) -+{ -+ int karg; -+ -+ switch (cmd) { -+ case SIOCPNADDRESOURCE: -+ case SIOCPNDELRESOURCE: -+ if (get_user(karg, (int __user *)arg)) -+ return -EFAULT; -+ -+ return sk->sk_prot->ioctl(sk, cmd, &karg); -+ } -+ /* A positive return value means that the ioctl was not processed */ -+ return 1; -+} - #endif -diff --git a/include/net/sock.h b/include/net/sock.h -index 579732d47dfc4..6ea961ee257d2 100644 ---- a/include/net/sock.h -+++ b/include/net/sock.h -@@ -1258,7 +1258,7 @@ struct proto { - bool kern); - - int (*ioctl)(struct sock *sk, int cmd, -- unsigned long arg); -+ int *karg); - int (*init)(struct sock *sk); - void (*destroy)(struct sock *sk); - void (*shutdown)(struct sock *sk, int how); -@@ -3048,6 +3048,9 @@ int sock_get_timeout(long timeo, void *optval, bool old_timeval); - int sock_copy_user_timeval(struct __kernel_sock_timeval *tv, - sockptr_t optval, int optlen, bool old_timeval); - -+int sock_ioctl_inout(struct sock *sk, unsigned int cmd, -+ void __user *arg, void *karg, size_t size); -+int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); - static inline bool sk_is_readable(struct sock *sk) - { - if (sk->sk_prot->sock_is_readable) -diff --git a/include/net/tcp.h b/include/net/tcp.h -index 8ea1fba84eff9..8d3777e476e0e 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -346,7 +346,7 @@ void tcp_release_cb(struct sock *sk); - void tcp_wfree(struct sk_buff *skb); - void tcp_write_timer_handler(struct sock *sk); - void tcp_delack_timer_handler(struct sock *sk); --int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); -+int tcp_ioctl(struct sock *sk, int cmd, int *karg); - int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb); - void tcp_rcv_established(struct sock *sk, struct sk_buff *skb); - void tcp_rcv_space_adjust(struct sock *sk); -diff --git a/include/net/udp.h b/include/net/udp.h -index fa4cdbe55552c..b5e5d5e2b4e1b 100644 ---- a/include/net/udp.h -+++ b/include/net/udp.h -@@ -275,7 +275,7 @@ void udp_flush_pending_frames(struct sock *sk); - int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size); - void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst); - int udp_rcv(struct sk_buff *skb); --int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); -+int udp_ioctl(struct sock *sk, int cmd, int *karg); - int udp_init_sock(struct sock *sk); - int udp_pre_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); - int __udp_disconnect(struct sock *sk, int flags); -diff --git a/net/core/sock.c b/net/core/sock.c -index c8803b95ea0da..e55220cc08640 100644 ---- a/net/core/sock.c -+++ b/net/core/sock.c -@@ -115,6 +115,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include - -@@ -139,6 +142,7 @@ - - #include - #include -+#include - - #include - -@@ -4129,3 +4133,63 @@ int sock_bind_add(struct sock *sk, struct sockaddr *addr, int addr_len) - return sk->sk_prot->bind_add(sk, addr, addr_len); - } - EXPORT_SYMBOL(sock_bind_add); -+ -+/* Copy 'size' bytes from userspace and return `size` back to userspace */ -+int sock_ioctl_inout(struct sock *sk, unsigned int cmd, -+ void __user *arg, void *karg, size_t size) -+{ -+ int ret; -+ -+ if (copy_from_user(karg, arg, size)) -+ return -EFAULT; -+ -+ ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, karg); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(arg, karg, size)) -+ return -EFAULT; -+ -+ return 0; -+} -+EXPORT_SYMBOL(sock_ioctl_inout); -+ -+/* This is the most common ioctl prep function, where the result (4 bytes) is -+ * copied back to userspace if the ioctl() returns successfully. No input is -+ * copied from userspace as input argument. -+ */ -+static int sock_ioctl_out(struct sock *sk, unsigned int cmd, void __user *arg) -+{ -+ int ret, karg = 0; -+ -+ ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, &karg); -+ if (ret) -+ return ret; -+ -+ return put_user(karg, (int __user *)arg); -+} -+ -+/* A wrapper around sock ioctls, which copies the data from userspace -+ * (depending on the protocol/ioctl), and copies back the result to userspace. -+ * The main motivation for this function is to pass kernel memory to the -+ * protocol ioctl callbacks, instead of userspace memory. -+ */ -+int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) -+{ -+ int rc = 1; -+ -+ if (sk_is_ipmr(sk)) -+ rc = ipmr_sk_ioctl(sk, cmd, arg); -+ else if (sk_is_icmpv6(sk)) -+ rc = ip6mr_sk_ioctl(sk, cmd, arg); -+ else if (sk_is_phonet(sk)) -+ rc = phonet_sk_ioctl(sk, cmd, arg); -+ -+ /* If ioctl was processed, returns its value */ -+ if (rc <= 0) -+ return rc; -+ -+ /* Otherwise call the default handler */ -+ return sock_ioctl_out(sk, cmd, arg); -+} -+EXPORT_SYMBOL(sk_ioctl); -diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h -index 9ddc3a9e89e40..1f748ed1279d3 100644 ---- a/net/dccp/dccp.h -+++ b/net/dccp/dccp.h -@@ -292,7 +292,7 @@ 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, - sockptr_t optval, unsigned int optlen); --int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); -+int dccp_ioctl(struct sock *sk, int cmd, int *karg); - 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 flags, - int *addr_len); -diff --git a/net/dccp/proto.c b/net/dccp/proto.c -index c522c76a9f89f..1d25cfcdbe5dc 100644 ---- a/net/dccp/proto.c -+++ b/net/dccp/proto.c -@@ -363,7 +363,7 @@ __poll_t dccp_poll(struct file *file, struct socket *sock, - } - EXPORT_SYMBOL_GPL(dccp_poll); - --int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+int dccp_ioctl(struct sock *sk, int cmd, int *karg) - { - int rc = -ENOTCONN; - -@@ -374,17 +374,17 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) - - switch (cmd) { - case SIOCOUTQ: { -- int amount = sk_wmem_alloc_get(sk); -+ *karg = sk_wmem_alloc_get(sk); - /* Using sk_wmem_alloc here because sk_wmem_queued is not used by DCCP and - * always 0, comparably to UDP. - */ - -- rc = put_user(amount, (int __user *)arg); -+ rc = 0; - } - break; - case SIOCINQ: { - struct sk_buff *skb; -- unsigned long amount = 0; -+ *karg = 0; - - skb = skb_peek(&sk->sk_receive_queue); - if (skb != NULL) { -@@ -392,9 +392,9 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) - * We will only return the amount of this packet since - * that is all that will be read. - */ -- amount = skb->len; -+ *karg = skb->len; - } -- rc = put_user(amount, (int __user *)arg); -+ rc = 0; - } - break; - default: -diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c -index 1fa2fe041ec03..9c124705120dd 100644 ---- a/net/ieee802154/socket.c -+++ b/net/ieee802154/socket.c -@@ -162,7 +162,7 @@ static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, - default: - if (!sk->sk_prot->ioctl) - return -ENOIOCTLCMD; -- return sk->sk_prot->ioctl(sk, cmd, arg); -+ return sk_ioctl(sk, cmd, (void __user *)arg); - } - } - -@@ -531,22 +531,21 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) - return err; - } - --static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int dgram_ioctl(struct sock *sk, int cmd, int *karg) - { - switch (cmd) { - case SIOCOUTQ: - { -- int amount = sk_wmem_alloc_get(sk); -+ *karg = sk_wmem_alloc_get(sk); - -- return put_user(amount, (int __user *)arg); -+ return 0; - } - - case SIOCINQ: - { - struct sk_buff *skb; -- unsigned long amount; - -- amount = 0; -+ *karg = 0; - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) { -@@ -554,10 +553,10 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) - * of this packet since that is all - * that will be read. - */ -- amount = skb->len - ieee802154_hdr_length(skb); -+ *karg = skb->len - ieee802154_hdr_length(skb); - } - spin_unlock_bh(&sk->sk_receive_queue.lock); -- return put_user(amount, (int __user *)arg); -+ return 0; - } - } - -diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index 9408dc3bb42d3..eddedc2f8c5c9 100644 ---- a/net/ipv4/af_inet.c -+++ b/net/ipv4/af_inet.c -@@ -1007,7 +1007,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) - break; - default: - if (sk->sk_prot->ioctl) -- err = sk->sk_prot->ioctl(sk, cmd, arg); -+ err = sk_ioctl(sk, cmd, (void __user *)arg); - else - err = -ENOIOCTLCMD; - break; -diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c -index d5421c38c2aae..e20f7ab8099ad 100644 ---- a/net/ipv4/ipmr.c -+++ b/net/ipv4/ipmr.c -@@ -1546,6 +1546,28 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, - return ret; - } - -+/* Execute if this ioctl is a special mroute ioctl */ -+int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) -+{ -+ switch (cmd) { -+ /* These userspace buffers will be consumed by ipmr_ioctl() */ -+ case SIOCGETVIFCNT: { -+ struct sioc_vif_req buffer; -+ -+ return sock_ioctl_inout(sk, cmd, arg, &buffer, -+ sizeof(buffer)); -+ } -+ case SIOCGETSGCNT: { -+ struct sioc_sg_req buffer; -+ -+ return sock_ioctl_inout(sk, cmd, arg, &buffer, -+ sizeof(buffer)); -+ } -+ } -+ /* return code > 0 means that the ioctl was not executed */ -+ return 1; -+} -+ - /* Getsock opt support for the multicast routing system. */ - int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, - sockptr_t optlen) -@@ -1592,13 +1614,13 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, - } - - /* The IP multicast ioctl support routines. */ --int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) -+int ipmr_ioctl(struct sock *sk, int cmd, void *arg) - { -- struct sioc_sg_req sr; -- struct sioc_vif_req vr; - struct vif_device *vif; - struct mfc_cache *c; - struct net *net = sock_net(sk); -+ struct sioc_vif_req *vr; -+ struct sioc_sg_req *sr; - struct mr_table *mrt; - - mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); -@@ -1607,40 +1629,33 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) - - switch (cmd) { - case SIOCGETVIFCNT: -- if (copy_from_user(&vr, arg, sizeof(vr))) -- return -EFAULT; -- if (vr.vifi >= mrt->maxvif) -+ vr = (struct sioc_vif_req *)arg; -+ if (vr->vifi >= mrt->maxvif) - return -EINVAL; -- vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif); -+ vr->vifi = array_index_nospec(vr->vifi, mrt->maxvif); - rcu_read_lock(); -- vif = &mrt->vif_table[vr.vifi]; -- if (VIF_EXISTS(mrt, vr.vifi)) { -- vr.icount = READ_ONCE(vif->pkt_in); -- vr.ocount = READ_ONCE(vif->pkt_out); -- vr.ibytes = READ_ONCE(vif->bytes_in); -- vr.obytes = READ_ONCE(vif->bytes_out); -+ vif = &mrt->vif_table[vr->vifi]; -+ if (VIF_EXISTS(mrt, vr->vifi)) { -+ vr->icount = READ_ONCE(vif->pkt_in); -+ vr->ocount = READ_ONCE(vif->pkt_out); -+ vr->ibytes = READ_ONCE(vif->bytes_in); -+ vr->obytes = READ_ONCE(vif->bytes_out); - rcu_read_unlock(); - -- if (copy_to_user(arg, &vr, sizeof(vr))) -- return -EFAULT; - return 0; - } - rcu_read_unlock(); - return -EADDRNOTAVAIL; - case SIOCGETSGCNT: -- if (copy_from_user(&sr, arg, sizeof(sr))) -- return -EFAULT; -+ sr = (struct sioc_sg_req *)arg; - - rcu_read_lock(); -- c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr); -+ c = ipmr_cache_find(mrt, sr->src.s_addr, sr->grp.s_addr); - if (c) { -- sr.pktcnt = c->_c.mfc_un.res.pkt; -- sr.bytecnt = c->_c.mfc_un.res.bytes; -- sr.wrong_if = c->_c.mfc_un.res.wrong_if; -+ sr->pktcnt = c->_c.mfc_un.res.pkt; -+ sr->bytecnt = c->_c.mfc_un.res.bytes; -+ sr->wrong_if = c->_c.mfc_un.res.wrong_if; - rcu_read_unlock(); -- -- if (copy_to_user(arg, &sr, sizeof(sr))) -- return -EFAULT; - return 0; - } - rcu_read_unlock(); -diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c -index 7c63b91edbf7a..a2d1f1ee7df59 100644 ---- a/net/ipv4/raw.c -+++ b/net/ipv4/raw.c -@@ -858,29 +858,29 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, - return do_raw_getsockopt(sk, level, optname, optval, optlen); - } - --static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int raw_ioctl(struct sock *sk, int cmd, int *karg) - { - switch (cmd) { - case SIOCOUTQ: { -- int amount = sk_wmem_alloc_get(sk); -- -- return put_user(amount, (int __user *)arg); -+ *karg = sk_wmem_alloc_get(sk); -+ return 0; - } - case SIOCINQ: { - struct sk_buff *skb; -- int amount = 0; - - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) -- amount = skb->len; -+ *karg = skb->len; -+ else -+ *karg = 0; - spin_unlock_bh(&sk->sk_receive_queue.lock); -- return put_user(amount, (int __user *)arg); -+ return 0; - } - - default: - #ifdef CONFIG_IP_MROUTE -- return ipmr_ioctl(sk, cmd, (void __user *)arg); -+ return ipmr_ioctl(sk, cmd, karg); - #else - return -ENOIOCTLCMD; - #endif -diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 86e7695d91adf..dcbcf238bf3ab 100644 ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -598,7 +598,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) - } - EXPORT_SYMBOL(tcp_poll); - --int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+int tcp_ioctl(struct sock *sk, int cmd, int *karg) - { - struct tcp_sock *tp = tcp_sk(sk); - int answ; -@@ -640,7 +640,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) - return -ENOIOCTLCMD; - } - -- return put_user(answ, (int __user *)arg); -+ *karg = answ; -+ return 0; - } - EXPORT_SYMBOL(tcp_ioctl); - -diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c -index 87d759bab0012..2a5748c246e24 100644 ---- a/net/ipv4/udp.c -+++ b/net/ipv4/udp.c -@@ -1694,21 +1694,19 @@ static int first_packet_length(struct sock *sk) - * IOCTL requests applicable to the UDP protocol - */ - --int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+int udp_ioctl(struct sock *sk, int cmd, int *karg) - { - switch (cmd) { - case SIOCOUTQ: - { -- int amount = sk_wmem_alloc_get(sk); -- -- return put_user(amount, (int __user *)arg); -+ *karg = sk_wmem_alloc_get(sk); -+ return 0; - } - - case SIOCINQ: - { -- int amount = max_t(int, 0, first_packet_length(sk)); -- -- return put_user(amount, (int __user *)arg); -+ *karg = max_t(int, 0, first_packet_length(sk)); -+ return 0; - } - - default: -diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c -index 0b42eb8c55aaf..37190217d650c 100644 ---- a/net/ipv6/af_inet6.c -+++ b/net/ipv6/af_inet6.c -@@ -598,7 +598,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) - prot = READ_ONCE(sk->sk_prot); - if (!prot->ioctl) - return -ENOIOCTLCMD; -- return prot->ioctl(sk, cmd, arg); -+ return sk_ioctl(sk, cmd, (void __user *)arg); - } - /*NOTREACHED*/ - return 0; -diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c -index 27fb5479988af..76db80a7124c8 100644 ---- a/net/ipv6/ip6mr.c -+++ b/net/ipv6/ip6mr.c -@@ -1879,11 +1879,10 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, - /* - * The IP multicast ioctl support routines. - */ -- --int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) -+int ip6mr_ioctl(struct sock *sk, int cmd, void *arg) - { -- struct sioc_sg_req6 sr; -- struct sioc_mif_req6 vr; -+ struct sioc_sg_req6 *sr; -+ struct sioc_mif_req6 *vr; - struct vif_device *vif; - struct mfc6_cache *c; - struct net *net = sock_net(sk); -@@ -1895,40 +1894,33 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) - - switch (cmd) { - case SIOCGETMIFCNT_IN6: -- if (copy_from_user(&vr, arg, sizeof(vr))) -- return -EFAULT; -- if (vr.mifi >= mrt->maxvif) -+ vr = (struct sioc_mif_req6 *)arg; -+ if (vr->mifi >= mrt->maxvif) - return -EINVAL; -- vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif); -+ vr->mifi = array_index_nospec(vr->mifi, mrt->maxvif); - rcu_read_lock(); -- vif = &mrt->vif_table[vr.mifi]; -- if (VIF_EXISTS(mrt, vr.mifi)) { -- vr.icount = READ_ONCE(vif->pkt_in); -- vr.ocount = READ_ONCE(vif->pkt_out); -- vr.ibytes = READ_ONCE(vif->bytes_in); -- vr.obytes = READ_ONCE(vif->bytes_out); -+ vif = &mrt->vif_table[vr->mifi]; -+ if (VIF_EXISTS(mrt, vr->mifi)) { -+ vr->icount = READ_ONCE(vif->pkt_in); -+ vr->ocount = READ_ONCE(vif->pkt_out); -+ vr->ibytes = READ_ONCE(vif->bytes_in); -+ vr->obytes = READ_ONCE(vif->bytes_out); - rcu_read_unlock(); -- -- if (copy_to_user(arg, &vr, sizeof(vr))) -- return -EFAULT; - return 0; - } - rcu_read_unlock(); - return -EADDRNOTAVAIL; - case SIOCGETSGCNT_IN6: -- if (copy_from_user(&sr, arg, sizeof(sr))) -- return -EFAULT; -+ sr = (struct sioc_sg_req6 *)arg; - - rcu_read_lock(); -- c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); -+ c = ip6mr_cache_find(mrt, &sr->src.sin6_addr, -+ &sr->grp.sin6_addr); - if (c) { -- sr.pktcnt = c->_c.mfc_un.res.pkt; -- sr.bytecnt = c->_c.mfc_un.res.bytes; -- sr.wrong_if = c->_c.mfc_un.res.wrong_if; -+ sr->pktcnt = c->_c.mfc_un.res.pkt; -+ sr->bytecnt = c->_c.mfc_un.res.bytes; -+ sr->wrong_if = c->_c.mfc_un.res.wrong_if; - rcu_read_unlock(); -- -- if (copy_to_user(arg, &sr, sizeof(sr))) -- return -EFAULT; - return 0; - } - rcu_read_unlock(); -diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c -index dc31752a7edcc..e361953ca7f45 100644 ---- a/net/ipv6/raw.c -+++ b/net/ipv6/raw.c -@@ -1116,29 +1116,29 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, - return do_rawv6_getsockopt(sk, level, optname, optval, optlen); - } - --static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int rawv6_ioctl(struct sock *sk, int cmd, int *karg) - { - switch (cmd) { - case SIOCOUTQ: { -- int amount = sk_wmem_alloc_get(sk); -- -- return put_user(amount, (int __user *)arg); -+ *karg = sk_wmem_alloc_get(sk); -+ return 0; - } - case SIOCINQ: { - struct sk_buff *skb; -- int amount = 0; - - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) -- amount = skb->len; -+ *karg = skb->len; -+ else -+ *karg = 0; - spin_unlock_bh(&sk->sk_receive_queue.lock); -- return put_user(amount, (int __user *)arg); -+ return 0; - } - - default: - #ifdef CONFIG_IPV6_MROUTE -- return ip6mr_ioctl(sk, cmd, (void __user *)arg); -+ return ip6mr_ioctl(sk, cmd, karg); - #else - return -ENOIOCTLCMD; - #endif -diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h -index a88e070b431d8..91ebf0a3f4997 100644 ---- a/net/l2tp/l2tp_core.h -+++ b/net/l2tp/l2tp_core.h -@@ -272,7 +272,7 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops - void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); - - /* IOCTL helper for IP encap modules. */ --int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg); -+int l2tp_ioctl(struct sock *sk, int cmd, int *karg); - - /* Extract the tunnel structure from a socket's sk_user_data pointer, - * validating the tunnel magic feather. -diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c -index 41a74fc84ca13..2b795c1064f5c 100644 ---- a/net/l2tp/l2tp_ip.c -+++ b/net/l2tp/l2tp_ip.c -@@ -562,19 +562,18 @@ static int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg, - return err ? err : copied; - } - --int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+int l2tp_ioctl(struct sock *sk, int cmd, int *karg) - { - struct sk_buff *skb; -- int amount; - - switch (cmd) { - case SIOCOUTQ: -- amount = sk_wmem_alloc_get(sk); -+ *karg = sk_wmem_alloc_get(sk); - break; - case SIOCINQ: - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); -- amount = skb ? skb->len : 0; -+ *karg = skb ? skb->len : 0; - spin_unlock_bh(&sk->sk_receive_queue.lock); - break; - -@@ -582,7 +581,7 @@ int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg) - return -ENOIOCTLCMD; - } - -- return put_user(amount, (int __user *)arg); -+ return 0; - } - EXPORT_SYMBOL_GPL(l2tp_ioctl); - -diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c -index 859b18cb8e4f6..7ea10d7aec961 100644 ---- a/net/mptcp/protocol.c -+++ b/net/mptcp/protocol.c -@@ -3640,11 +3640,10 @@ static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v) - return (int)delta; - } - --static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int mptcp_ioctl(struct sock *sk, int cmd, int *karg) - { - struct mptcp_sock *msk = mptcp_sk(sk); - bool slow; -- int answ; - - switch (cmd) { - case SIOCINQ: -@@ -3653,24 +3652,24 @@ static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg) - - lock_sock(sk); - __mptcp_move_skbs(msk); -- answ = mptcp_inq_hint(sk); -+ *karg = mptcp_inq_hint(sk); - release_sock(sk); - break; - case SIOCOUTQ: - slow = lock_sock_fast(sk); -- answ = mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una)); -+ *karg = mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una)); - unlock_sock_fast(sk, slow); - break; - case SIOCOUTQNSD: - slow = lock_sock_fast(sk); -- answ = mptcp_ioctl_outq(msk, msk->snd_nxt); -+ *karg = mptcp_ioctl_outq(msk, msk->snd_nxt); - unlock_sock_fast(sk, slow); - break; - default: - return -ENOIOCTLCMD; - } - -- return put_user(answ, (int __user *)arg); -+ return 0; - } - - static void mptcp_subflow_early_fallback(struct mptcp_sock *msk, -diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c -index ff5f49ab236ed..3aa50dc7535b7 100644 ---- a/net/phonet/datagram.c -+++ b/net/phonet/datagram.c -@@ -28,24 +28,21 @@ static void pn_sock_close(struct sock *sk, long timeout) - sk_common_release(sk); - } - --static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int pn_ioctl(struct sock *sk, int cmd, int *karg) - { - struct sk_buff *skb; -- int answ; - - switch (cmd) { - case SIOCINQ: - lock_sock(sk); - skb = skb_peek(&sk->sk_receive_queue); -- answ = skb ? skb->len : 0; -+ *karg = skb ? skb->len : 0; - release_sock(sk); -- return put_user(answ, (int __user *)arg); -+ return 0; - - case SIOCPNADDRESOURCE: - case SIOCPNDELRESOURCE: { -- u32 res; -- if (get_user(res, (u32 __user *)arg)) -- return -EFAULT; -+ u32 res = *karg; - if (res >= 256) - return -EINVAL; - if (cmd == SIOCPNADDRESOURCE) -diff --git a/net/phonet/pep.c b/net/phonet/pep.c -index 83ea13a50690b..faba31f2eff29 100644 ---- a/net/phonet/pep.c -+++ b/net/phonet/pep.c -@@ -917,10 +917,9 @@ static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) - return 0; - } - --static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int pep_ioctl(struct sock *sk, int cmd, int *karg) - { - struct pep_sock *pn = pep_sk(sk); -- int answ; - int ret = -ENOIOCTLCMD; - - switch (cmd) { -@@ -933,13 +932,13 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) - lock_sock(sk); - if (sock_flag(sk, SOCK_URGINLINE) && - !skb_queue_empty(&pn->ctrlreq_queue)) -- answ = skb_peek(&pn->ctrlreq_queue)->len; -+ *karg = skb_peek(&pn->ctrlreq_queue)->len; - else if (!skb_queue_empty(&sk->sk_receive_queue)) -- answ = skb_peek(&sk->sk_receive_queue)->len; -+ *karg = skb_peek(&sk->sk_receive_queue)->len; - else -- answ = 0; -+ *karg = 0; - release_sock(sk); -- ret = put_user(answ, (int __user *)arg); -+ ret = 0; - break; - - case SIOCPNENABLEPIPE: -diff --git a/net/phonet/socket.c b/net/phonet/socket.c -index 71e2caf6ab859..967f9b4dc0265 100644 ---- a/net/phonet/socket.c -+++ b/net/phonet/socket.c -@@ -387,7 +387,7 @@ static int pn_socket_ioctl(struct socket *sock, unsigned int cmd, - return put_user(handle, (__u16 __user *)arg); - } - -- return sk->sk_prot->ioctl(sk, cmd, arg); -+ return sk_ioctl(sk, cmd, (void __user *)arg); - } - - static int pn_socket_listen(struct socket *sock, int backlog) -diff --git a/net/sctp/socket.c b/net/sctp/socket.c -index 237a6b04adf6f..9c29bff647a11 100644 ---- a/net/sctp/socket.c -+++ b/net/sctp/socket.c -@@ -4902,7 +4902,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern) - } - - /* The SCTP ioctl handler. */ --static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) -+static int sctp_ioctl(struct sock *sk, int cmd, int *karg) - { - int rc = -ENOTCONN; - -@@ -4918,7 +4918,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) - switch (cmd) { - case SIOCINQ: { - struct sk_buff *skb; -- unsigned int amount = 0; -+ *karg = 0; - - skb = skb_peek(&sk->sk_receive_queue); - if (skb != NULL) { -@@ -4926,9 +4926,9 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) - * We will only return the amount of this packet since - * that is all that will be read. - */ -- amount = skb->len; -+ *karg = skb->len; - } -- rc = put_user(amount, (int __user *)arg); -+ rc = 0; - break; - } - default: --- -2.43.0 - diff --git a/queue-6.1/phonet-pep-fix-racy-skb_queue_empty-use.patch b/queue-6.1/phonet-pep-fix-racy-skb_queue_empty-use.patch index 7152549d075..e526f8470c4 100644 --- a/queue-6.1/phonet-pep-fix-racy-skb_queue_empty-use.patch +++ b/queue-6.1/phonet-pep-fix-racy-skb_queue_empty-use.patch @@ -20,14 +20,12 @@ Link: https://lore.kernel.org/r/20240218081214.4806-2-remi@remlab.net Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- - net/phonet/pep.c | 41 ++++++++++++++++++++++++++++++++--------- + net/phonet/pep.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) -diff --git a/net/phonet/pep.c b/net/phonet/pep.c -index faba31f2eff29..3dd5f52bc1b58 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c -@@ -917,6 +917,37 @@ static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) +@@ -917,6 +917,37 @@ static int pep_sock_enable(struct sock * return 0; } @@ -62,26 +60,23 @@ index faba31f2eff29..3dd5f52bc1b58 100644 + return len; +} + - static int pep_ioctl(struct sock *sk, int cmd, int *karg) + static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) { struct pep_sock *pn = pep_sk(sk); -@@ -929,15 +960,7 @@ static int pep_ioctl(struct sock *sk, int cmd, int *karg) +@@ -930,15 +961,7 @@ static int pep_ioctl(struct sock *sk, in break; } - lock_sock(sk); - if (sock_flag(sk, SOCK_URGINLINE) && - !skb_queue_empty(&pn->ctrlreq_queue)) -- *karg = skb_peek(&pn->ctrlreq_queue)->len; +- answ = skb_peek(&pn->ctrlreq_queue)->len; - else if (!skb_queue_empty(&sk->sk_receive_queue)) -- *karg = skb_peek(&sk->sk_receive_queue)->len; +- answ = skb_peek(&sk->sk_receive_queue)->len; - else -- *karg = 0; +- answ = 0; - release_sock(sk); -+ *karg = pep_first_packet_length(sk); - ret = 0; ++ answ = pep_first_packet_length(sk); + ret = put_user(answ, (int __user *)arg); break; --- -2.43.0 - diff --git a/queue-6.1/phonet-take-correct-lock-to-peek-at-the-rx-queue.patch b/queue-6.1/phonet-take-correct-lock-to-peek-at-the-rx-queue.patch index 711d9e3495f..0d814ad56e9 100644 --- a/queue-6.1/phonet-take-correct-lock-to-peek-at-the-rx-queue.patch +++ b/queue-6.1/phonet-take-correct-lock-to-peek-at-the-rx-queue.patch @@ -21,26 +21,21 @@ Link: https://lore.kernel.org/r/20240218081214.4806-1-remi@remlab.net Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- - net/phonet/datagram.c | 4 ++-- + net/phonet/datagram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c -index 3aa50dc7535b7..976fe250b5095 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c -@@ -34,10 +34,10 @@ static int pn_ioctl(struct sock *sk, int cmd, int *karg) +@@ -35,10 +35,10 @@ static int pn_ioctl(struct sock *sk, int switch (cmd) { case SIOCINQ: - lock_sock(sk); + spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); - *karg = skb ? skb->len : 0; + answ = skb ? skb->len : 0; - release_sock(sk); + spin_unlock_bh(&sk->sk_receive_queue.lock); - return 0; + return put_user(answ, (int __user *)arg); case SIOCPNADDRESOURCE: --- -2.43.0 - diff --git a/queue-6.1/series b/queue-6.1/series index 847a3990833..647f260ccea 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -175,7 +175,6 @@ netfilter-nf_tables-register-hooks-last-when-adding-.patch netfilter-nf_tables-use-kzalloc-for-hook-allocation.patch net-mctp-put-sock-on-tag-allocation-failure.patch net-sparx5-add-spinlock-for-frame-transmission-from-.patch -net-ioctl-use-kernel-memory-on-protocol-ioctl-callba.patch phonet-take-correct-lock-to-peek-at-the-rx-queue.patch phonet-pep-fix-racy-skb_queue_empty-use.patch fix-write-to-cloned-skb-in-ipv6_hop_ioam.patch