From 03c812cebee68066888ca0d1577785e1af5a8f12 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 5 Jan 2022 17:09:43 +0800 Subject: [PATCH 01/10] drm/amdkfd: Check for null pointer after calling kmemdup mainline inclusion from mainline-5.17-rc1 commit abfaf0eee97925905e742aa3b0b72e04a918fa9e category: bugfix issue: I66OGA CVE: CVE-2022-3108 Signed-off-by: gaochao --------------------------------------- As the possible failure of the allocation, kmemdup() may return NULL pointer. Therefore, it should be better to check the 'props2' in order to prevent the dereference of NULL pointer. Fixes: 3a87177eb141 ("drm/amdkfd: Add topology support for dGPUs") Signed-off-by: Jiasheng Jiang Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 31d793ee0836..6866fa94df97 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -408,6 +408,9 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, return -ENODEV; /* same everything but the other direction */ props2 = kmemdup(props, sizeof(*props2), GFP_KERNEL); + if (!props2) + return -ENOMEM; + props2->node_from = id_to; props2->node_to = id_from; props2->kobj = NULL; -- Gitee From 90050aeb80c2b9a1d636cb9581c3a39d018a0bce Mon Sep 17 00:00:00 2001 From: Phil Turnbull Date: Wed, 23 Nov 2022 10:35:43 -0500 Subject: [PATCH 02/10] wifi: wilc1000: validate number of channels stable inclusion from stable-5.10.157 commit 3eb6b89a4e9f9e44c3170d70d8d16c3c8dc8c800 category: bugfix issue: I673ZW CVE: CVE-2022-47518 Signed-off-by: gaochao --------------------------------------- commit 0cdfa9e6f0915e3d243e2393bfa8a22e12d553b0 upstream. There is no validation of 'e->no_of_channels' which can trigger an out-of-bounds write in the following 'memset' call. Validate that the number of channels does not extends beyond the size of the channel list element. Signed-off-by: Phil Turnbull Tested-by: Ajay Kathat Acked-by: Ajay Kathat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221123153543.8568-5-philipturnbull@github.com Signed-off-by: Greg Kroah-Hartman --- .../wireless/microchip/wilc1000/cfg80211.c | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index c1ac1d84790f..d3380fea9082 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -951,19 +951,30 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch) } if (ch_list_idx) { - u16 attr_size; - struct wilc_ch_list_elem *e; - int i; + unsigned int i; + u16 elem_size; ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx]; - attr_size = le16_to_cpu(ch_list->attr_len); - for (i = 0; i < attr_size;) { + /* the number of bytes following the final 'elem' member */ + elem_size = le16_to_cpu(ch_list->attr_len) - + (sizeof(*ch_list) - sizeof(struct wilc_attr_entry)); + for (i = 0; i < elem_size;) { + struct wilc_ch_list_elem *e; + e = (struct wilc_ch_list_elem *)(ch_list->elem + i); + + i += sizeof(*e); + if (i > elem_size) + break; + + i += e->no_of_channels; + if (i > elem_size) + break; + if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) { memset(e->ch_list, sta_ch, e->no_of_channels); break; } - i += e->no_of_channels; } } -- Gitee From b069d610bf9e733df3aef3006e903b6c187356d5 Mon Sep 17 00:00:00 2001 From: Phil Turnbull Date: Wed, 23 Nov 2022 10:35:42 -0500 Subject: [PATCH 03/10] wifi: wilc1000: validate length of IEEE80211_P2P_ATTR_CHANNEL_LIST attribute stable inclusion from stable-5.10.157 commit 5a068535c0073c8402aa0755e8ef259fb98a33c5 category: bugfix issue: I6718W CVE: CVE-2022-47521 Signed-off-by: gaochao --------------------------------------- commit f9b62f9843c7b0afdaecabbcebf1dbba18599408 upstream. Validate that the IEEE80211_P2P_ATTR_CHANNEL_LIST attribute contains enough space for a 'struct wilc_attr_oper_ch'. If the attribute is too small then it can trigger an out-of-bounds write later in the function. 'struct wilc_attr_oper_ch' is variable sized so also check 'attr_len' does not extend beyond the end of 'buf'. Signed-off-by: Phil Turnbull Tested-by: Ajay Kathat Acked-by: Ajay Kathat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221123153543.8568-4-philipturnbull@github.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index d3380fea9082..4cdbcfc36051 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -941,7 +941,14 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch) while (index + sizeof(*e) <= len) { e = (struct wilc_attr_entry *)&buf[index]; - if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST) + + attr_size = le16_to_cpu(e->attr_len); + + if (index + sizeof(*e) + attr_size > len) + return; + + if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST && + attr_size >= (sizeof(struct wilc_attr_ch_list) - sizeof(*e))) ch_list_idx = index; else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL) op_ch_idx = index; -- Gitee From 2ded61724301821715623b05a3b72e1f5e320058 Mon Sep 17 00:00:00 2001 From: Phil Turnbull Date: Wed, 23 Nov 2022 10:35:41 -0500 Subject: [PATCH 04/10] wifi: wilc1000: validate length of IEEE80211_P2P_ATTR_OPER_CHANNEL attribute stable inclusion from stable-5.10.157 commit 905f886eae4b065656a575e8a02544045cbaadcf category: bugfix issue: I673ZZ CVE: CVE-2022-47519 Signed-off-by: gaochao --------------------------------------- commit 051ae669e4505abbe05165bebf6be7922de11f41 upstream. Validate that the IEEE80211_P2P_ATTR_OPER_CHANNEL attribute contains enough space for a 'struct struct wilc_attr_oper_ch'. If the attribute is too small then it triggers an out-of-bounds write later in the function. Signed-off-by: Phil Turnbull Tested-by: Ajay Kathat Acked-by: Ajay Kathat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221123153543.8568-3-philipturnbull@github.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 4cdbcfc36051..a57b87f11fb9 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -940,21 +940,24 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch) return; while (index + sizeof(*e) <= len) { - e = (struct wilc_attr_entry *)&buf[index]; + u16 attr_size; + e = (struct wilc_attr_entry *)&buf[index]; attr_size = le16_to_cpu(e->attr_len); if (index + sizeof(*e) + attr_size > len) return; - if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST && - attr_size >= (sizeof(struct wilc_attr_ch_list) - sizeof(*e))) + if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST) ch_list_idx = index; - else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL) + else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL && + attr_size == (sizeof(struct wilc_attr_oper_ch) - sizeof(*e))) op_ch_idx = index; + if (ch_list_idx && op_ch_idx) break; - index += le16_to_cpu(e->attr_len) + sizeof(*e); + + index += sizeof(*e) + attr_size; } if (ch_list_idx) { -- Gitee From 4a4a72fc3b543838fa29d8676db7f94479a5568b Mon Sep 17 00:00:00 2001 From: Phil Turnbull Date: Wed, 23 Nov 2022 10:35:40 -0500 Subject: [PATCH 05/10] wifi: wilc1000: validate pairwise and authentication suite offsets stable inclusion from stable-5.10.157 commit 7c6535fb4d67ea37c98a1d1d24ca33dd5ec42693 category: bugfix issue: I67191 CVE: CVE-2022-47520 Signed-off-by: gaochao --------------------------------------- commit cd21d99e595ec1d8721e1058dcdd4f1f7de1d793 upstream. There is no validation of 'offset' which can trigger an out-of-bounds read when extracting RSN capabilities. Signed-off-by: Phil Turnbull Tested-by: Ajay Kathat Acked-by: Ajay Kathat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221123153543.8568-2-philipturnbull@github.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/microchip/wilc1000/hif.c | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index d025a3093015..b25847799138 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -467,14 +467,25 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); if (rsn_ie) { + int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; int offset = 8; - param->mode_802_11i = 2; - param->rsn_found = true; /* extract RSN capabilities */ - offset += (rsn_ie[offset] * 4) + 2; - offset += (rsn_ie[offset] * 4) + 2; - memcpy(param->rsn_cap, &rsn_ie[offset], 2); + if (offset < rsn_ie_len) { + /* skip over pairwise suites */ + offset += (rsn_ie[offset] * 4) + 2; + + if (offset < rsn_ie_len) { + /* skip over authentication suites */ + offset += (rsn_ie[offset] * 4) + 2; + + if (offset + 1 < rsn_ie_len) { + param->mode_802_11i = 2; + param->rsn_found = true; + memcpy(param->rsn_cap, &rsn_ie[offset], 2); + } + } + } } if (param->rsn_found) { -- Gitee From 5792a190cc724cf770b40e794e3ff24d6a12d320 Mon Sep 17 00:00:00 2001 From: Sungwoo Kim Date: Thu, 8 Dec 2022 21:45:19 +0800 Subject: [PATCH 06/10] Bluetooth: L2CAP: Fix u8 overflow maillist inclusion category: bugfix ISSUE:I63XMP CVE: CVE-2022-45934 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=ae4569813a6e931258db627cdfe50dfb4f917d5d Signed-off-by: gaochao -------------------------------- By keep sending L2CAP_CONF_REQ packets, chan->num_conf_rsp increases multiple times and eventually it will wrap around the maximum number (i.e., 255). This patch prevents this by adding a boundary check with L2CAP_MAX_CONF_RSP Btmon log: Bluetooth monitor ver 5.64 = Note: Linux version 6.1.0-rc2 (x86_64) 0.264594 = Note: Bluetooth subsystem version 2.22 0.264636 @ MGMT Open: btmon (privileged) version 1.22 {0x0001} 0.272191 = New Index: 00:00:00:00:00:00 (Primary,Virtual,hci0) [hci0] 13.877604 @ RAW Open: 9496 (privileged) version 2.22 {0x0002} 13.890741 = Open Index: 00:00:00:00:00:00 [hci0] 13.900426 (...) > ACL Data RX: Handle 200 flags 0x00 dlen 1033 #32 [hci0] 14.273106 invalid packet size (12 != 1033) 08 00 01 00 02 01 04 00 01 10 ff ff ............ > ACL Data RX: Handle 200 flags 0x00 dlen 1547 #33 [hci0] 14.273561 invalid packet size (14 != 1547) 0a 00 01 00 04 01 06 00 40 00 00 00 00 00 ........@..... > ACL Data RX: Handle 200 flags 0x00 dlen 2061 #34 [hci0] 14.274390 invalid packet size (16 != 2061) 0c 00 01 00 04 01 08 00 40 00 00 00 00 00 00 04 ........@....... > ACL Data RX: Handle 200 flags 0x00 dlen 2061 #35 [hci0] 14.274932 invalid packet size (16 != 2061) 0c 00 01 00 04 01 08 00 40 00 00 00 07 00 03 00 ........@....... = bluetoothd: Bluetooth daemon 5.43 14.401828 > ACL Data RX: Handle 200 flags 0x00 dlen 1033 #36 [hci0] 14.275753 invalid packet size (12 != 1033) 08 00 01 00 04 01 04 00 40 00 00 00 ........@... Signed-off-by: Sungwoo Kim Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Baisong Zhong Reviewed-by: Liu Jian Reviewed-by: Yue Haibing Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 46c00ad3f6e4..60da4a550c96 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4414,7 +4414,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, chan->ident = cmd->ident; l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); - chan->num_conf_rsp++; + if (chan->num_conf_rsp < L2CAP_CONF_MAX_CONF_RSP) + chan->num_conf_rsp++; /* Reset config buffer. */ chan->conf_len = 0; -- Gitee From e9abb886d367b5c178e6f4da62898044656a1b46 Mon Sep 17 00:00:00 2001 From: Long Li Date: Fri, 16 Dec 2022 17:40:18 +0800 Subject: [PATCH 07/10] proc: proc_skip_spaces() shouldn't think it is working on C strings stable inclusion from stable-v5.10.157 commit 9ba389863ac63032d4b6ffad2c90a62cd78082ee category: bugfix ISSUE:I66BMO CVE: CVE-2022-4378 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9ba389863ac63032d4b6ffad2c90a62cd78082ee Signed-off-by: gaochao -------------------------------- commit bce9332220bd677d83b19d21502776ad555a0e73 upstream. proc_skip_spaces() seems to think it is working on C strings, and ends up being just a wrapper around skip_spaces() with a really odd calling convention. Instead of basing it on skip_spaces(), it should have looked more like proc_skip_char(), which really is the exact same function (except it skips a particular character, rather than whitespace). So use that as inspiration, odd coding and all. Now the calling convention actually makes sense and works for the intended purpose. Reported-and-tested-by: Kyle Zeng Acked-by: Eric Dumazet Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Long Li Reviewed-by: Zhang Yi Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai --- kernel/sysctl.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8832440a4938..59f37f6e6800 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -391,13 +391,14 @@ int proc_dostring(struct ctl_table *table, int write, ppos); } -static size_t proc_skip_spaces(char **buf) +static void proc_skip_spaces(char **buf, size_t *size) { - size_t ret; - char *tmp = skip_spaces(*buf); - ret = tmp - *buf; - *buf = tmp; - return ret; + while (*size) { + if (!isspace(**buf)) + break; + (*size)--; + (*buf)++; + } } static void proc_skip_char(char **buf, size_t *size, const char v) @@ -630,7 +631,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, bool neg; if (write) { - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (!left) break; @@ -657,7 +658,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, if (!write && !first && left && !err) proc_put_char(&buffer, &left, '\n'); if (write && !err && left) - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (write && first) return err ? : -EINVAL; *lenp -= left; @@ -699,7 +700,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data, if (left > PAGE_SIZE - 1) left = PAGE_SIZE - 1; - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (!left) { err = -EINVAL; goto out_free; @@ -719,7 +720,7 @@ static int do_proc_douintvec_w(unsigned int *tbl_data, } if (!err && left) - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); out_free: if (err) @@ -1177,7 +1178,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, if (write) { bool neg; - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (!left) break; @@ -1205,7 +1206,7 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, if (!write && !first && left && !err) proc_put_char(&buffer, &left, '\n'); if (write && !err) - left -= proc_skip_spaces(&p); + proc_skip_spaces(&p, &left); if (write && first) return err ? : -EINVAL; *lenp -= left; -- Gitee From a59db5807fade792fce8048ede68e57601b12782 Mon Sep 17 00:00:00 2001 From: Long Li Date: Fri, 16 Dec 2022 17:40:17 +0800 Subject: [PATCH 08/10] proc: avoid integer type confusion in get_proc_long stable inclusion from stable-v5.10.157 commit 4aa32aaef6c1b5e39ae2508ec596bd7b67871043 category: bugfix ISSUE:I66BMO CVE: CVE-2022-4378 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4aa32aaef6c1b5e39ae2508ec596bd7b67871043 Signed-off-by: gaochao -------------------------------- commit e6cfaf34be9fcd1a8285a294e18986bfc41a409c upstream. proc_get_long() is passed a size_t, but then assigns it to an 'int' variable for the length. Let's not do that, even if our IO paths are limited to MAX_RW_COUNT (exactly because of these kinds of type errors). So do the proper test in the rigth type. Reported-by: Kyle Zeng Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Signed-off-by: Long Li Reviewed-by: Zhang Yi Reviewed-by: Xiu Jianfeng Signed-off-by: Zheng Zengkai --- kernel/sysctl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 59f37f6e6800..2767aa2eb617 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -467,13 +467,12 @@ static int proc_get_long(char **buf, size_t *size, unsigned long *val, bool *neg, const char *perm_tr, unsigned perm_tr_len, char *tr) { - int len; char *p, tmp[TMPBUFLEN]; + ssize_t len = *size; - if (!*size) + if (len <= 0) return -EINVAL; - len = *size; if (len > TMPBUFLEN - 1) len = TMPBUFLEN - 1; -- Gitee From 2b1a22415a8c0bfb2cf23998860d8009cfd46a8f Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 8 Dec 2022 21:45:21 +0800 Subject: [PATCH 09/10] l2tp: Don't sleep and disable BH under writer-side sk_callback_lock mainline inclusion from mainline-v6.1-rc7 commit af295e854a4e3813ffbdef26dbb6a4d6226c3ea1 category: bugfix ISSUE:I656U4 CVE: CVE-2022-4129 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=af295e854a4e3813ffbdef26dbb6a4d6226c3ea1 Signed-off-by: gaochao -------------------------------- When holding a reader-writer spin lock we cannot sleep. Calling setup_udp_tunnel_sock() with write lock held violates this rule, because we end up calling percpu_down_read(), which might sleep, as syzbot reports [1]: __might_resched.cold+0x222/0x26b kernel/sched/core.c:9890 percpu_down_read include/linux/percpu-rwsem.h:49 [inline] cpus_read_lock+0x1b/0x140 kernel/cpu.c:310 static_key_slow_inc+0x12/0x20 kernel/jump_label.c:158 udp_tunnel_encap_enable include/net/udp_tunnel.h:187 [inline] setup_udp_tunnel_sock+0x43d/0x550 net/ipv4/udp_tunnel_core.c:81 l2tp_tunnel_register+0xc51/0x1210 net/l2tp/l2tp_core.c:1509 pppol2tp_connect+0xcdc/0x1a10 net/l2tp/l2tp_ppp.c:723 Trim the writer-side critical section for sk_callback_lock down to the minimum, so that it covers only operations on sk_user_data. Also, when grabbing the sk_callback_lock, we always need to disable BH, as Eric points out. Failing to do so leads to deadlocks because we acquire sk_callback_lock in softirq context, which can get stuck waiting on us if: 1) it runs on the same CPU, or CPU0 ---- lock(clock-AF_INET6); lock(clock-AF_INET6); 2) lock ordering leads to priority inversion CPU0 CPU1 ---- ---- lock(clock-AF_INET6); local_irq_disable(); lock(&tcp_hashinfo.bhash[i].lock); lock(clock-AF_INET6); lock(&tcp_hashinfo.bhash[i].lock); ... as syzbot reports [2,3]. Use the _bh variants for write_(un)lock. [1] https://lore.kernel.org/netdev/0000000000004e78ec05eda79749@google.com/ [2] https://lore.kernel.org/netdev/000000000000e38b6605eda76f98@google.com/ [3] https://lore.kernel.org/netdev/000000000000dfa31e05eda76f75@google.com/ v2: - Check and set sk_user_data while holding sk_callback_lock for both L2TP encapsulation types (IP and UDP) (Tetsuo) Cc: Tom Parkin Cc: Tetsuo Handa Fixes: b68777d54fac ("l2tp: Serialize access to sk_user_data with sk_callback_lock") Reported-by: Eric Dumazet Reported-by: syzbot+703d9e154b3b58277261@syzkaller.appspotmail.com Reported-by: syzbot+50680ced9e98a61f7698@syzkaller.appspotmail.com Reported-by: syzbot+de987172bb74a381879b@syzkaller.appspotmail.com Signed-off-by: Jakub Sitnicki Signed-off-by: David S. Miller Signed-off-by: Lu Wei Reviewed-by: Yue Haibing Reviewed-by: Wang Weiyang Signed-off-by: Zheng Zengkai --- net/l2tp/l2tp_core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 203890e378cb..cac2202c045b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1469,12 +1469,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, sock = sockfd_lookup(tunnel->fd, &ret); if (!sock) goto err; - - ret = l2tp_validate_socket(sock->sk, net, tunnel->encap); - if (ret < 0) - goto err_sock; } + sk = sock->sk; + write_lock_bh(&sk->sk_callback_lock); + ret = l2tp_validate_socket(sk, net, tunnel->encap); + if (ret < 0) + goto err_inval_sock; + rcu_assign_sk_user_data(sk, tunnel); + write_unlock_bh(&sk->sk_callback_lock); + tunnel->l2tp_net = net; pn = l2tp_pernet(net); @@ -1503,8 +1507,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, }; setup_udp_tunnel_sock(net, sock, &udp_cfg); - } else { - sk->sk_user_data = tunnel; } tunnel->old_sk_destruct = sk->sk_destruct; @@ -1521,6 +1523,11 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, return 0; err_sock: + write_lock_bh(&sk->sk_callback_lock); + rcu_assign_sk_user_data(sk, NULL); +err_inval_sock: + write_unlock_bh(&sk->sk_callback_lock); + if (tunnel->fd < 0) sock_release(sock); else -- Gitee From feb59b9320b409d384519c014026979c8ad1bb1a Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 8 Dec 2022 21:45:20 +0800 Subject: [PATCH 10/10] l2tp: Serialize access to sk_user_data with sk_callback_lock mainline inclusion from mainline-v6.1-rc6 commit b68777d54fac21fc833ec26ea1a2a84f975ab035 category: bugfix ISSUE:I656U4 CVE: CVE-2022-4129 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b68777d54fac21fc833ec26ea1a2a84f975ab035 Signed-off-by: gaochao -------------------------------- sk->sk_user_data has multiple users, which are not compatible with each other. Writers must synchronize by grabbing the sk->sk_callback_lock. l2tp currently fails to grab the lock when modifying the underlying tunnel socket fields. Fix it by adding appropriate locking. We err on the side of safety and grab the sk_callback_lock also inside the sk_destruct callback overridden by l2tp, even though there should be no refs allowing access to the sock at the time when sk_destruct gets called. v4: - serialize write to sk_user_data in l2tp sk_destruct v3: - switch from sock lock to sk_callback_lock - document write-protection for sk_user_data v2: - update Fixes to point to origin of the bug - use real names in Reported/Tested-by tags Cc: Tom Parkin Fixes: 3557baabf280 ("[L2TP]: PPP over L2TP driver core") Reported-by: Haowei Yan Signed-off-by: Jakub Sitnicki Signed-off-by: David S. Miller Signed-off-by: Lu Wei Reviewed-by: Yue Haibing Reviewed-by: Wang Weiyang Signed-off-by: Zheng Zengkai --- include/net/sock.h | 2 +- net/l2tp/l2tp_core.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 6fda43cee5bc..c0875a54cca5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -318,7 +318,7 @@ struct bpf_local_storage; * @sk_tskey: counter to disambiguate concurrent tstamp requests * @sk_zckey: counter to order MSG_ZEROCOPY notifications * @sk_socket: Identd and reporting IO signals - * @sk_user_data: RPC layer private data + * @sk_user_data: RPC layer private data. Write-protected by @sk_callback_lock. * @sk_frag: cached page frag * @sk_peek_off: current peek_offset value * @sk_send_head: front of stuff to transmit diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index cac2202c045b..13944b841125 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1148,8 +1148,10 @@ static void l2tp_tunnel_destruct(struct sock *sk) } /* Remove hooks into tunnel socket */ + write_lock_bh(&sk->sk_callback_lock); sk->sk_destruct = tunnel->old_sk_destruct; sk->sk_user_data = NULL; + write_unlock_bh(&sk->sk_callback_lock); /* Call the original destructor */ if (sk->sk_destruct) @@ -1472,16 +1474,18 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, } sk = sock->sk; - write_lock_bh(&sk->sk_callback_lock); + write_lock(&sk->sk_callback_lock); + ret = l2tp_validate_socket(sk, net, tunnel->encap); if (ret < 0) - goto err_inval_sock; - rcu_assign_sk_user_data(sk, tunnel); - write_unlock_bh(&sk->sk_callback_lock); + goto err_sock; tunnel->l2tp_net = net; pn = l2tp_pernet(net); + sock_hold(sk); + tunnel->sock = sk; + spin_lock_bh(&pn->l2tp_tunnel_list_lock); list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) { if (tunnel_walk->tunnel_id == tunnel->tunnel_id) { @@ -1507,6 +1511,8 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, }; setup_udp_tunnel_sock(net, sock, &udp_cfg); + } else { + rcu_assign_sk_user_data(sk, tunnel); } tunnel->old_sk_destruct = sk->sk_destruct; @@ -1520,6 +1526,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, if (tunnel->fd >= 0) sockfd_put(sock); + write_unlock(&sk->sk_callback_lock); return 0; err_sock: @@ -1532,6 +1539,8 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, sock_release(sock); else sockfd_put(sock); + + write_unlock(&sk->sk_callback_lock); err: return ret; } -- Gitee