From 9eac9d1b5e0f3350dff931c51a08b07fe23e12b9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 23 Apr 2023 15:32:41 +0200 Subject: [PATCH] 4.14-stable patches added patches: ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch --- ...e-after-free-in-ext4_xattr_set_entry.patch | 127 ++++++++++++++++ ...ition-of-ext4_xattr_ibody_inline_set.patch | 129 ++++++++++++++++ ...e-after-free-in-ext4_xattr_set_entry.patch | 52 +++++++ queue-4.14/series | 5 + ..._destroy_sock-in-ipv6-sk-sk_destruct.patch | 143 ++++++++++++++++++ ...roy_sock-in-setsockopt-ipv6_addrform.patch | 106 +++++++++++++ 6 files changed, 562 insertions(+) create mode 100644 queue-4.14/ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch create mode 100644 queue-4.14/ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch create mode 100644 queue-4.14/revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch create mode 100644 queue-4.14/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch create mode 100644 queue-4.14/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch diff --git a/queue-4.14/ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch b/queue-4.14/ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch new file mode 100644 index 00000000000..6be616ee119 --- /dev/null +++ b/queue-4.14/ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch @@ -0,0 +1,127 @@ +From stable-owner@vger.kernel.org Wed Apr 19 08:46:51 2023 +From: Tudor Ambarus +Date: Wed, 19 Apr 2023 06:46:10 +0000 +Subject: ext4: fix use-after-free in ext4_xattr_set_entry +To: stable@vger.kernel.org +Cc: tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, joneslee@google.com, Baokun Li , stable@kernel.org, Hulk Robot , Ritesh Harjani , Jan Kara , Tudor Ambarus +Message-ID: <20230419064610.1918038-4-tudor.ambarus@linaro.org> + +From: Baokun Li + +[ Upstream commit 67d7d8ad99beccd9fe92d585b87f1760dc9018e3 ] + +Hulk Robot reported a issue: +================================================================== +BUG: KASAN: use-after-free in ext4_xattr_set_entry+0x18ab/0x3500 +Write of size 4105 at addr ffff8881675ef5f4 by task syz-executor.0/7092 + +CPU: 1 PID: 7092 Comm: syz-executor.0 Not tainted 4.19.90-dirty #17 +Call Trace: +[...] + memcpy+0x34/0x50 mm/kasan/kasan.c:303 + ext4_xattr_set_entry+0x18ab/0x3500 fs/ext4/xattr.c:1747 + ext4_xattr_ibody_inline_set+0x86/0x2a0 fs/ext4/xattr.c:2205 + ext4_xattr_set_handle+0x940/0x1300 fs/ext4/xattr.c:2386 + ext4_xattr_set+0x1da/0x300 fs/ext4/xattr.c:2498 + __vfs_setxattr+0x112/0x170 fs/xattr.c:149 + __vfs_setxattr_noperm+0x11b/0x2a0 fs/xattr.c:180 + __vfs_setxattr_locked+0x17b/0x250 fs/xattr.c:238 + vfs_setxattr+0xed/0x270 fs/xattr.c:255 + setxattr+0x235/0x330 fs/xattr.c:520 + path_setxattr+0x176/0x190 fs/xattr.c:539 + __do_sys_lsetxattr fs/xattr.c:561 [inline] + __se_sys_lsetxattr fs/xattr.c:557 [inline] + __x64_sys_lsetxattr+0xc2/0x160 fs/xattr.c:557 + do_syscall_64+0xdf/0x530 arch/x86/entry/common.c:298 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 +RIP: 0033:0x459fe9 +RSP: 002b:00007fa5e54b4c08 EFLAGS: 00000246 ORIG_RAX: 00000000000000bd +RAX: ffffffffffffffda RBX: 000000000051bf60 RCX: 0000000000459fe9 +RDX: 00000000200003c0 RSI: 0000000020000180 RDI: 0000000020000140 +RBP: 000000000051bf60 R08: 0000000000000001 R09: 0000000000000000 +R10: 0000000000001009 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007ffc73c93fc0 R14: 000000000051bf60 R15: 00007fa5e54b4d80 +[...] +================================================================== + +Above issue may happen as follows: +------------------------------------- +ext4_xattr_set + ext4_xattr_set_handle + ext4_xattr_ibody_find + >> s->end < s->base + >> no EXT4_STATE_XATTR + >> xattr_check_inode is not executed + ext4_xattr_ibody_set + ext4_xattr_set_entry + >> size_t min_offs = s->end - s->base + >> UAF in memcpy + +we can easily reproduce this problem with the following commands: + mkfs.ext4 -F /dev/sda + mount -o debug_want_extra_isize=128 /dev/sda /mnt + touch /mnt/file + setfattr -n user.cat -v `seq -s z 4096|tr -d '[:digit:]'` /mnt/file + +In ext4_xattr_ibody_find, we have the following assignment logic: + header = IHDR(inode, raw_inode) + = raw_inode + EXT4_GOOD_OLD_INODE_SIZE + i_extra_isize + is->s.base = IFIRST(header) + = header + sizeof(struct ext4_xattr_ibody_header) + is->s.end = raw_inode + s_inode_size + +In ext4_xattr_set_entry + min_offs = s->end - s->base + = s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - i_extra_isize - + sizeof(struct ext4_xattr_ibody_header) + last = s->first + free = min_offs - ((void *)last - s->base) - sizeof(__u32) + = s_inode_size - EXT4_GOOD_OLD_INODE_SIZE - i_extra_isize - + sizeof(struct ext4_xattr_ibody_header) - sizeof(__u32) + +In the calculation formula, all values except s_inode_size and +i_extra_size are fixed values. When i_extra_size is the maximum value +s_inode_size - EXT4_GOOD_OLD_INODE_SIZE, min_offs is -4 and free is -8. +The value overflows. As a result, the preceding issue is triggered when +memcpy is executed. + +Therefore, when finding xattr or setting xattr, check whether +there is space for storing xattr in the inode to resolve this issue. + +Cc: stable@kernel.org +Reported-by: Hulk Robot +Signed-off-by: Baokun Li +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20220616021358.2504451-3-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Tudor Ambarus +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -2200,8 +2200,9 @@ int ext4_xattr_ibody_find(struct inode * + struct ext4_inode *raw_inode; + int error; + +- if (EXT4_I(inode)->i_extra_isize == 0) ++ if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) + return 0; ++ + raw_inode = ext4_raw_inode(&is->iloc); + header = IHDR(inode, raw_inode); + is->s.base = is->s.first = IFIRST(header); +@@ -2229,8 +2230,9 @@ int ext4_xattr_ibody_set(handle_t *handl + struct ext4_xattr_search *s = &is->s; + int error; + +- if (EXT4_I(inode)->i_extra_isize == 0) ++ if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) + return -ENOSPC; ++ + error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); + if (error) + return error; diff --git a/queue-4.14/ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch b/queue-4.14/ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch new file mode 100644 index 00000000000..52cdd34a0e3 --- /dev/null +++ b/queue-4.14/ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch @@ -0,0 +1,129 @@ +From stable-owner@vger.kernel.org Wed Apr 19 08:46:43 2023 +From: Tudor Ambarus +Date: Wed, 19 Apr 2023 06:46:09 +0000 +Subject: ext4: remove duplicate definition of ext4_xattr_ibody_inline_set() +To: stable@vger.kernel.org +Cc: tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, joneslee@google.com, Ritesh Harjani , Tudor Ambarus +Message-ID: <20230419064610.1918038-3-tudor.ambarus@linaro.org> + +From: Ritesh Harjani + +[ Upstream commit 310c097c2bdbea253d6ee4e064f3e65580ef93ac ] + +ext4_xattr_ibody_inline_set() & ext4_xattr_ibody_set() have the exact +same definition. Hence remove ext4_xattr_ibody_inline_set() and all +its call references. Convert the callers of it to call +ext4_xattr_ibody_set() instead. + +[ Modified to preserve ext4_xattr_ibody_set() and remove + ext4_xattr_ibody_inline_set() instead. -- TYT ] + +Signed-off-by: Ritesh Harjani +Link: https://lore.kernel.org/r/fd566b799bbbbe9b668eb5eecde5b5e319e3694f.1622685482.git.riteshh@linux.ibm.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Tudor Ambarus +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inline.c | 11 +++++------ + fs/ext4/xattr.c | 26 +------------------------- + fs/ext4/xattr.h | 6 +++--- + 3 files changed, 9 insertions(+), 34 deletions(-) + +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -212,7 +212,7 @@ out: + /* + * write the buffer to the inline inode. + * If 'create' is set, we don't need to do the extra copy in the xattr +- * value since it is already handled by ext4_xattr_ibody_inline_set. ++ * value since it is already handled by ext4_xattr_ibody_set. + * That saves us one memcpy. + */ + static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, +@@ -294,7 +294,7 @@ static int ext4_create_inline_data(handl + + BUG_ON(!is.s.not_found); + +- error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); ++ error = ext4_xattr_ibody_set(handle, inode, &i, &is); + if (error) { + if (error == -ENOSPC) + ext4_clear_inode_state(inode, +@@ -366,7 +366,7 @@ static int ext4_update_inline_data(handl + i.value = value; + i.value_len = len; + +- error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); ++ error = ext4_xattr_ibody_set(handle, inode, &i, &is); + if (error) + goto out; + +@@ -439,7 +439,7 @@ static int ext4_destroy_inline_data_nolo + if (error) + goto out; + +- error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); ++ error = ext4_xattr_ibody_set(handle, inode, &i, &is); + if (error) + goto out; + +@@ -1951,8 +1951,7 @@ int ext4_inline_data_truncate(struct ino + i.value = value; + i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ? + i_size - EXT4_MIN_INLINE_DATA_SIZE : 0; +- err = ext4_xattr_ibody_inline_set(handle, inode, +- &i, &is); ++ err = ext4_xattr_ibody_set(handle, inode, &i, &is); + if (err) + goto out_error; + } +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -2221,31 +2221,7 @@ int ext4_xattr_ibody_find(struct inode * + return 0; + } + +-int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, +- struct ext4_xattr_info *i, +- struct ext4_xattr_ibody_find *is) +-{ +- struct ext4_xattr_ibody_header *header; +- struct ext4_xattr_search *s = &is->s; +- int error; +- +- if (EXT4_I(inode)->i_extra_isize == 0) +- return -ENOSPC; +- error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); +- if (error) +- return error; +- header = IHDR(inode, ext4_raw_inode(&is->iloc)); +- if (!IS_LAST_ENTRY(s->first)) { +- header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); +- ext4_set_inode_state(inode, EXT4_STATE_XATTR); +- } else { +- header->h_magic = cpu_to_le32(0); +- ext4_clear_inode_state(inode, EXT4_STATE_XATTR); +- } +- return 0; +-} +- +-static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, ++int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, + struct ext4_xattr_info *i, + struct ext4_xattr_ibody_find *is) + { +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -198,9 +198,9 @@ extern int ext4_xattr_ibody_find(struct + extern int ext4_xattr_ibody_get(struct inode *inode, int name_index, + const char *name, + void *buffer, size_t buffer_size); +-extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, +- struct ext4_xattr_info *i, +- struct ext4_xattr_ibody_find *is); ++extern int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, ++ struct ext4_xattr_info *i, ++ struct ext4_xattr_ibody_find *is); + + extern struct mb_cache *ext4_xattr_create_cache(void); + extern void ext4_xattr_destroy_cache(struct mb_cache *); diff --git a/queue-4.14/revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch b/queue-4.14/revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch new file mode 100644 index 00000000000..b18eb8bb511 --- /dev/null +++ b/queue-4.14/revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch @@ -0,0 +1,52 @@ +From stable-owner@vger.kernel.org Wed Apr 19 08:46:43 2023 +From: Tudor Ambarus +Date: Wed, 19 Apr 2023 06:46:08 +0000 +Subject: Revert "ext4: fix use-after-free in ext4_xattr_set_entry" +To: stable@vger.kernel.org +Cc: tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, joneslee@google.com, Tudor Ambarus +Message-ID: <20230419064610.1918038-2-tudor.ambarus@linaro.org> + +From: Tudor Ambarus + +This reverts commit bb8592efcf8ef2f62947745d3182ea05b5256a15 which is +commit 67d7d8ad99beccd9fe92d585b87f1760dc9018e3 upstream. + +The order in which patches are queued to stable matters. This patch +has a logical dependency on commit 310c097c2bdbea253d6ee4e064f3e65580ef93ac +upstream, and failing to queue the latter results in a null-ptr-deref +reported at the Link below. + +In order to avoid conflicts on stable, revert the commit just so that we +can queue its prerequisite patch first and then queue the same after. + +Link: https://syzkaller.appspot.com/bug?extid=d5ebf56f3b1268136afd +Signed-off-by: Tudor Ambarus +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -2200,9 +2200,8 @@ int ext4_xattr_ibody_find(struct inode * + struct ext4_inode *raw_inode; + int error; + +- if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) ++ if (EXT4_I(inode)->i_extra_isize == 0) + return 0; +- + raw_inode = ext4_raw_inode(&is->iloc); + header = IHDR(inode, raw_inode); + is->s.base = is->s.first = IFIRST(header); +@@ -2230,9 +2229,8 @@ int ext4_xattr_ibody_inline_set(handle_t + struct ext4_xattr_search *s = &is->s; + int error; + +- if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) ++ if (EXT4_I(inode)->i_extra_isize == 0) + return -ENOSPC; +- + error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); + if (error) + return error; diff --git a/queue-4.14/series b/queue-4.14/series index 882fb95c6b7..412c5f62552 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -15,3 +15,8 @@ xen-netback-use-same-error-messages-for-same-errors.patch nilfs2-initialize-unused-bytes-in-segment-summary-blocks.patch memstick-fix-memory-leak-if-card-device-is-never-registered.patch x86-purgatory-don-t-generate-debug-info-for-purgatory.ro.patch +revert-ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch +ext4-remove-duplicate-definition-of-ext4_xattr_ibody_inline_set.patch +ext4-fix-use-after-free-in-ext4_xattr_set_entry.patch +udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch +tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch diff --git a/queue-4.14/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch b/queue-4.14/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch new file mode 100644 index 00000000000..ace3136b282 --- /dev/null +++ b/queue-4.14/tcp-udp-call-inet6_destroy_sock-in-ipv6-sk-sk_destruct.patch @@ -0,0 +1,143 @@ +From d38afeec26ed4739c640bf286c270559aab2ba5f Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 6 Oct 2022 11:53:47 -0700 +Subject: tcp/udp: Call inet6_destroy_sock() in IPv6 sk->sk_destruct(). + +From: Kuniyuki Iwashima + +commit d38afeec26ed4739c640bf286c270559aab2ba5f upstream. + +Originally, inet6_sk(sk)->XXX were changed under lock_sock(), so we were +able to clean them up by calling inet6_destroy_sock() during the IPv6 -> +IPv4 conversion by IPV6_ADDRFORM. However, commit 03485f2adcde ("udpv6: +Add lockless sendmsg() support") added a lockless memory allocation path, +which could cause a memory leak: + +setsockopt(IPV6_ADDRFORM) sendmsg() ++-----------------------+ +-------+ +- do_ipv6_setsockopt(sk, ...) - udpv6_sendmsg(sk, ...) + - sockopt_lock_sock(sk) ^._ called via udpv6_prot + - lock_sock(sk) before WRITE_ONCE() + - WRITE_ONCE(sk->sk_prot, &tcp_prot) + - inet6_destroy_sock() - if (!corkreq) + - sockopt_release_sock(sk) - ip6_make_skb(sk, ...) + - release_sock(sk) ^._ lockless fast path for + the non-corking case + + - __ip6_append_data(sk, ...) + - ipv6_local_rxpmtu(sk, ...) + - xchg(&np->rxpmtu, skb) + ^._ rxpmtu is never freed. + + - goto out_no_dst; + + - lock_sock(sk) + +For now, rxpmtu is only the case, but not to miss the future change +and a similar bug fixed in commit e27326009a3d ("net: ping6: Fix +memleak in ipv6_renew_options()."), let's set a new function to IPv6 +sk->sk_destruct() and call inet6_cleanup_sock() there. Since the +conversion does not change sk->sk_destruct(), we can guarantee that +we can clean up IPv6 resources finally. + +We can now remove all inet6_destroy_sock() calls from IPv6 protocol +specific ->destroy() functions, but such changes are invasive to +backport. So they can be posted as a follow-up later for net-next. + +Fixes: 03485f2adcde ("udpv6: Add lockless sendmsg() support") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Ziyang Xuan +Signed-off-by: Greg Kroah-Hartman +--- + net/dccp/dccp.h | 1 + + net/dccp/ipv6.c | 15 ++++++++------- + net/dccp/proto.c | 8 +++++++- + net/ipv6/af_inet6.c | 1 + + 4 files changed, 17 insertions(+), 8 deletions(-) + +--- a/net/dccp/dccp.h ++++ b/net/dccp/dccp.h +@@ -291,6 +291,7 @@ int dccp_rcv_state_process(struct sock * + int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, + const struct dccp_hdr *dh, const unsigned int len); + ++void dccp_destruct_common(struct sock *sk); + int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized); + void dccp_destroy_sock(struct sock *sk); + +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -1000,6 +1000,12 @@ static const struct inet_connection_sock + #endif + }; + ++static void dccp_v6_sk_destruct(struct sock *sk) ++{ ++ dccp_destruct_common(sk); ++ inet6_sock_destruct(sk); ++} ++ + /* NOTE: A lot of things set to zero explicitly by call to + * sk_alloc() so need not be done here. + */ +@@ -1012,17 +1018,12 @@ static int dccp_v6_init_sock(struct sock + if (unlikely(!dccp_v6_ctl_sock_initialized)) + dccp_v6_ctl_sock_initialized = 1; + inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; ++ sk->sk_destruct = dccp_v6_sk_destruct; + } + + return err; + } + +-static void dccp_v6_destroy_sock(struct sock *sk) +-{ +- dccp_destroy_sock(sk); +- inet6_destroy_sock(sk); +-} +- + static struct timewait_sock_ops dccp6_timewait_sock_ops = { + .twsk_obj_size = sizeof(struct dccp6_timewait_sock), + }; +@@ -1045,7 +1046,7 @@ static struct proto dccp_v6_prot = { + .accept = inet_csk_accept, + .get_port = inet_csk_get_port, + .shutdown = dccp_shutdown, +- .destroy = dccp_v6_destroy_sock, ++ .destroy = dccp_destroy_sock, + .orphan_count = &dccp_orphan_count, + .max_header = MAX_DCCP_HEADER, + .obj_size = sizeof(struct dccp6_sock), +--- a/net/dccp/proto.c ++++ b/net/dccp/proto.c +@@ -171,12 +171,18 @@ const char *dccp_packet_name(const int t + + EXPORT_SYMBOL_GPL(dccp_packet_name); + +-static void dccp_sk_destruct(struct sock *sk) ++void dccp_destruct_common(struct sock *sk) + { + struct dccp_sock *dp = dccp_sk(sk); + + ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); + dp->dccps_hc_tx_ccid = NULL; ++} ++EXPORT_SYMBOL_GPL(dccp_destruct_common); ++ ++static void dccp_sk_destruct(struct sock *sk) ++{ ++ dccp_destruct_common(sk); + inet_sock_destruct(sk); + } + +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -106,6 +106,7 @@ static __inline__ struct ipv6_pinfo *ine + + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } ++EXPORT_SYMBOL_GPL(inet6_sock_destruct); + + static int inet6_create(struct net *net, struct socket *sock, int protocol, + int kern) diff --git a/queue-4.14/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch b/queue-4.14/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch new file mode 100644 index 00000000000..e75021f08ee --- /dev/null +++ b/queue-4.14/udp-call-inet6_destroy_sock-in-setsockopt-ipv6_addrform.patch @@ -0,0 +1,106 @@ +From 21985f43376cee092702d6cb963ff97a9d2ede68 Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Thu, 6 Oct 2022 11:53:46 -0700 +Subject: udp: Call inet6_destroy_sock() in setsockopt(IPV6_ADDRFORM). + +From: Kuniyuki Iwashima + +commit 21985f43376cee092702d6cb963ff97a9d2ede68 upstream. + +Commit 4b340ae20d0e ("IPv6: Complete IPV6_DONTFRAG support") forgot +to add a change to free inet6_sk(sk)->rxpmtu while converting an IPv6 +socket into IPv4 with IPV6_ADDRFORM. After conversion, sk_prot is +changed to udp_prot and ->destroy() never cleans it up, resulting in +a memory leak. + +This is due to the discrepancy between inet6_destroy_sock() and +IPV6_ADDRFORM, so let's call inet6_destroy_sock() from IPV6_ADDRFORM +to remove the difference. + +However, this is not enough for now because rxpmtu can be changed +without lock_sock() after commit 03485f2adcde ("udpv6: Add lockless +sendmsg() support"). We will fix this case in the following patch. + +Note we will rename inet6_destroy_sock() to inet6_cleanup_sock() and +remove unnecessary inet6_destroy_sock() calls in sk_prot->destroy() +in the future. + +Fixes: 4b340ae20d0e ("IPv6: Complete IPV6_DONTFRAG support") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Jakub Kicinski +Signed-off-by: Ziyang Xuan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ipv6.h | 1 + + net/ipv6/af_inet6.c | 6 ++++++ + net/ipv6/ipv6_sockglue.c | 20 ++++++++------------ + 3 files changed, 15 insertions(+), 12 deletions(-) + +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -942,6 +942,7 @@ void ipv6_icmp_error(struct sock *sk, st + void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); + void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); + ++void inet6_cleanup_sock(struct sock *sk); + int inet6_release(struct socket *sock); + int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); + int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -480,6 +480,12 @@ void inet6_destroy_sock(struct sock *sk) + } + EXPORT_SYMBOL_GPL(inet6_destroy_sock); + ++void inet6_cleanup_sock(struct sock *sk) ++{ ++ inet6_destroy_sock(sk); ++} ++EXPORT_SYMBOL_GPL(inet6_cleanup_sock); ++ + /* + * This does both peername and sockname. + */ +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -178,9 +178,6 @@ static int do_ipv6_setsockopt(struct soc + if (optlen < sizeof(int)) + goto e_inval; + if (val == PF_INET) { +- struct ipv6_txoptions *opt; +- struct sk_buff *pktopt; +- + if (sk->sk_type == SOCK_RAW) + break; + +@@ -211,7 +208,6 @@ static int do_ipv6_setsockopt(struct soc + break; + } + +- fl6_free_socklist(sk); + __ipv6_sock_mc_close(sk); + __ipv6_sock_ac_close(sk); + +@@ -246,14 +242,14 @@ static int do_ipv6_setsockopt(struct soc + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; + } +- opt = xchg((__force struct ipv6_txoptions **)&np->opt, +- NULL); +- if (opt) { +- atomic_sub(opt->tot_len, &sk->sk_omem_alloc); +- txopt_put(opt); +- } +- pktopt = xchg(&np->pktoptions, NULL); +- kfree_skb(pktopt); ++ ++ /* Disable all options not to allocate memory anymore, ++ * but there is still a race. See the lockless path ++ * in udpv6_sendmsg() and ipv6_local_rxpmtu(). ++ */ ++ np->rxopt.all = 0; ++ ++ inet6_cleanup_sock(sk); + + /* + * ... and add it to the refcnt debug socks count -- 2.47.3