From 36bb17f3a6adcbdd4c2ed6b43f42a099afac7c26 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 11 Sep 2023 17:42:50 +0800 Subject: [PATCH 1/5] ksmbd: destroy expired sessions mainline inclusion from mainline-v6.4-rc1 commit ea174a91893956450510945a0c5d1a10b5323656 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I74FHK CVE: CVE-2023-32247 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ea174a91893956450510945a0c5d1a10b5323656 -------------------------------- client can indefinitely send smb2 session setup requests with the SessionId set to 0, thus indefinitely spawning new sessions, and causing indefinite memory usage. This patch limit to the number of sessions using expired timeout and session state. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20478 Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: ZhaoLong Wang (cherry picked from commit 8c79f1ee8e576e4a051a07d2731365c7cc3e8979) --- fs/ksmbd/mgmt/user_session.c | 68 ++++++++++++++++++++---------------- fs/ksmbd/mgmt/user_session.h | 1 + fs/ksmbd/smb2pdu.c | 1 + fs/ksmbd/smb2pdu.h | 2 ++ 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c index dac24affd59c..cf83d8c3689b 100644 --- a/fs/ksmbd/mgmt/user_session.c +++ b/fs/ksmbd/mgmt/user_session.c @@ -172,70 +172,73 @@ static struct ksmbd_session *__session_lookup(unsigned long long id) struct ksmbd_session *sess; hash_for_each_possible(sessions_table, sess, hlist, id) { - if (id == sess->id) + if (id == sess->id) { + sess->last_active = jiffies; return sess; + } } return NULL; } +static void ksmbd_expire_session(struct ksmbd_conn *conn) +{ + unsigned long id; + struct ksmbd_session *sess; + + xa_for_each(&conn->sessions, id, sess) { + if (sess->state != SMB2_SESSION_VALID || + time_after(jiffies, + sess->last_active + SMB2_SESSION_TIMEOUT)) { + xa_erase(&conn->sessions, sess->id); + ksmbd_session_destroy(sess); + continue; + } + } +} + int ksmbd_session_register(struct ksmbd_conn *conn, struct ksmbd_session *sess) { sess->dialect = conn->dialect; memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); + ksmbd_expire_session(conn); return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); } -static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) +static void ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) { struct channel *chann; chann = xa_erase(&sess->ksmbd_chann_list, (long)conn); if (!chann) - return -ENOENT; + return; kfree(chann); - - return 0; } void ksmbd_sessions_deregister(struct ksmbd_conn *conn) { struct ksmbd_session *sess; + unsigned long id; - if (conn->binding) { - int bkt; - - down_write(&sessions_table_lock); - hash_for_each(sessions_table, bkt, sess, hlist) { - if (!ksmbd_chann_del(conn, sess)) { - up_write(&sessions_table_lock); - goto sess_destroy; - } + xa_for_each(&conn->sessions, id, sess) { + ksmbd_chann_del(conn, sess); + if (xa_empty(&sess->ksmbd_chann_list)) { + xa_erase(&conn->sessions, sess->id); + ksmbd_session_destroy(sess); } - up_write(&sessions_table_lock); - } else { - unsigned long id; - - xa_for_each(&conn->sessions, id, sess) { - if (!ksmbd_chann_del(conn, sess)) - goto sess_destroy; - } - } - - return; - -sess_destroy: - if (xa_empty(&sess->ksmbd_chann_list)) { - xa_erase(&conn->sessions, sess->id); - ksmbd_session_destroy(sess); } } struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, unsigned long long id) { - return xa_load(&conn->sessions, id); + struct ksmbd_session *sess; + + sess = xa_load(&conn->sessions, id); + if (sess) + sess->last_active = jiffies; + return sess; } struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) @@ -244,6 +247,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) down_read(&sessions_table_lock); sess = __session_lookup(id); + if (sess) + sess->last_active = jiffies; up_read(&sessions_table_lock); return sess; @@ -322,6 +327,7 @@ static struct ksmbd_session *__session_create(int protocol) if (ksmbd_init_file_table(&sess->file_table)) goto error; + sess->last_active = jiffies; sess->state = SMB2_SESSION_IN_PROGRESS; set_session_flag(sess, protocol); xa_init(&sess->tree_conns); diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h index 44a3c67b2bd9..51f38e5b61ab 100644 --- a/fs/ksmbd/mgmt/user_session.h +++ b/fs/ksmbd/mgmt/user_session.h @@ -59,6 +59,7 @@ struct ksmbd_session { __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; struct ksmbd_file_table file_table; + unsigned long last_active; }; static inline int test_session_flag(struct ksmbd_session *sess, int bit) diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index 842135178bef..51166df64d56 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -1890,6 +1890,7 @@ int smb2_sess_setup(struct ksmbd_work *work) if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) try_delay = true; + sess->last_active = jiffies; sess->state = SMB2_SESSION_EXPIRED; if (try_delay) ssleep(5); diff --git a/fs/ksmbd/smb2pdu.h b/fs/ksmbd/smb2pdu.h index 18fa04984599..ba255fd2f77c 100644 --- a/fs/ksmbd/smb2pdu.h +++ b/fs/ksmbd/smb2pdu.h @@ -367,6 +367,8 @@ struct smb2_negotiate_rsp { #define SMB2_SESSION_IN_PROGRESS BIT(0) #define SMB2_SESSION_VALID BIT(1) +#define SMB2_SESSION_TIMEOUT (10 * HZ) + /* Flags */ #define SMB2_SESSION_REQ_FLAG_BINDING 0x01 #define SMB2_SESSION_REQ_FLAG_ENCRYPT_DATA 0x04 -- Gitee From a0b710cd06428af9850a38acf097e2639a4e6cb7 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 11 Sep 2023 17:42:51 +0800 Subject: [PATCH 2/5] ksmbd: block asynchronous requests when making a delay on session setup mainline inclusion from mainline-v6.4-rc1 commit b096d97f47326b1e2dbdef1c91fab69ffda54d17 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I74FP0 CVE: CVE-2023-32251 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b096d97f47326b1e2dbdef1c91fab69ffda54d17 -------------------------------- ksmbd make a delay of 5 seconds on session setup to avoid dictionary attacks. But the 5 seconds delay can be bypassed by using asynchronous requests. This patch block all requests on current connection when making a delay on sesstion setup failure. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20482 Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: ZhaoLong Wang (cherry picked from commit 166bfc4a627fbc623bf449abe8abcb4bf27420a1) --- fs/ksmbd/smb2pdu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index 51166df64d56..38e5e5909422 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -1892,8 +1892,11 @@ int smb2_sess_setup(struct ksmbd_work *work) sess->last_active = jiffies; sess->state = SMB2_SESSION_EXPIRED; - if (try_delay) + if (try_delay) { + ksmbd_conn_set_need_reconnect(conn); ssleep(5); + ksmbd_conn_set_need_negotiate(conn); + } } } -- Gitee From 82db28cbb18b9a56db55ecc940f75c743e9f44df Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 11 Sep 2023 17:42:52 +0800 Subject: [PATCH 3/5] ksmbd: fix deadlock in ksmbd_find_crypto_ctx() mainline inclusion from mainline-v6.4-rc1 commit 7b4323373d844954bb76e0e9f39c4e5fc785fa7b category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I74FIN CVE: CVE-2023-32253 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7b4323373d844954bb76e0e9f39c4e5fc785fa7b -------------------------------- Deadlock is triggered by sending multiple concurrent session setup requests. It should be reused after releasing when getting ctx for crypto. Multiple consecutive ctx uses cause deadlock while waiting for releasing due to the limited number of ctx. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20591 Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: ZhaoLong Wang (cherry picked from commit 5c18a2edbfe6dbb709c8fdfc1d9d6c4624cacd3b) --- fs/ksmbd/auth.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c index 0ac85a1a63c0..d8dabd19823f 100644 --- a/fs/ksmbd/auth.c +++ b/fs/ksmbd/auth.c @@ -220,22 +220,22 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; - struct ksmbd_crypto_ctx *ctx; + struct ksmbd_crypto_ctx *ctx = NULL; char *construct = NULL; int rc, len; - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); if (rc) { ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); goto out; } + ctx = ksmbd_crypto_ctx_find_hmacmd5(); + if (!ctx) { + ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); + return -ENOMEM; + } + rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); @@ -271,6 +271,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, ksmbd_debug(AUTH, "Could not generate md5 hash\n"); goto out; } + ksmbd_release_crypto_ctx(ctx); + ctx = NULL; rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); if (rc) { @@ -281,7 +283,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0) rc = -EINVAL; out: - ksmbd_release_crypto_ctx(ctx); + if (ctx) + ksmbd_release_crypto_ctx(ctx); kfree(construct); return rc; } -- Gitee From c638b5d4734c9eb46b73b5efa03fabbcff6d8a0e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 11 Sep 2023 17:42:53 +0800 Subject: [PATCH 4/5] ksmbd: not allow guest user on multichannel mainline inclusion from mainline-v6.4-rc1 commit 3353ab2df5f68dab7da8d5ebb427a2d265a1f2b2 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I74FMP CVE: CVE-2023-32249 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3353ab2df5f68dab7da8d5ebb427a2d265a1f2b2 -------------------------------- This patch return STATUS_NOT_SUPPORTED if binding session is guest. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20480 Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: ZhaoLong Wang (cherry picked from commit c77a3939ec7258ac1eb210c87b5d6f9c0ce621d3) --- fs/ksmbd/smb2pdu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index 38e5e5909422..546fed3daa25 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -1481,7 +1481,7 @@ static int ntlm_authenticate(struct ksmbd_work *work, * Reuse session if anonymous try to connect * on reauthetication. */ - if (ksmbd_anonymous_user(user)) { + if (conn->binding == false && ksmbd_anonymous_user(user)) { ksmbd_free_user(user); return 0; } @@ -1495,7 +1495,7 @@ static int ntlm_authenticate(struct ksmbd_work *work, sess->user = user; } - if (user_guest(sess->user)) { + if (conn->binding == false && user_guest(sess->user)) { rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE; } else { struct authenticate_message *authblob; @@ -1739,6 +1739,11 @@ int smb2_sess_setup(struct ksmbd_work *work) goto out_err; } + if (user_guest(sess->user)) { + rc = -EOPNOTSUPP; + goto out_err; + } + conn->binding = true; } else if ((conn->dialect < SMB30_PROT_ID || server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && @@ -1863,6 +1868,8 @@ int smb2_sess_setup(struct ksmbd_work *work) rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED; else if (rc == -ENOMEM) rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; + else if (rc == -EOPNOTSUPP) + rsp->hdr.Status = STATUS_NOT_SUPPORTED; else if (rc) rsp->hdr.Status = STATUS_LOGON_FAILURE; -- Gitee From b98f911dfb0bd27c3f1cb131f9b8cfb54c74db32 Mon Sep 17 00:00:00 2001 From: Szuying Chen Date: Fri, 15 Sep 2023 07:03:57 +0000 Subject: [PATCH 5/5] ata: libahci: clear pending interrupt status driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I81M63 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git/commit/?h=for-6.6-fixes&id=737dd811a3dbfd7edd4ad2ba5152e93d99074f83 ------------------------------------------------------------ When a CRC error occurs, the HBA asserts an interrupt to indicate an interface fatal error (PxIS.IFS). The ISR clears PxIE and PxIS, then does error recovery. If the adapter receives another SDB FIS with an error (PxIS.TFES) from the device before the start of the EH recovery process, the interrupt signaling the new SDB cannot be serviced as PxIE was cleared already. This in turn results in the HBA inability to issue any command during the error recovery process after setting PxCMD.ST to 1 because PxIS.TFES is still set. According to AHCI 1.3.1 specifications section 6.2.2, fatal errors notified by setting PxIS.HBFS, PxIS.HBDS, PxIS.IFS or PxIS.TFES will cause the HBA to enter the ERR:Fatal state. In this state, the HBA shall not issue any new commands. To avoid this situation, introduce the function ahci_port_clear_pending_irq() to clear pending interrupts before executing a COMRESET. This follows the AHCI 1.3.1 - section 6.2.2.2 specification. Signed-off-by: Szuying Chen Fixes: e0bfd149973d ("[PATCH] ahci: stop engine during hard reset") Cc: stable@vger.kernel.org Reviewed-by: Niklas Cassel Signed-off-by: Damien Le Moal Signed-off-by: Xingui Yang (cherry picked from commit 0a835ab132184942830ff7530761c62074abbf0c) --- drivers/ata/libahci.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 4514f3f28b7c..160400a2a998 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1205,6 +1205,26 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) return sprintf(buf, "%d\n", emp->blink_policy); } +static void ahci_port_clear_pending_irq(struct ata_port *ap) +{ + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 tmp; + + /* clear SError */ + tmp = readl(port_mmio + PORT_SCR_ERR); + dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + + /* clear port IRQ */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp); + if (tmp) + writel(tmp, port_mmio + PORT_IRQ_STAT); + + writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT); +} + static void ahci_port_init(struct device *dev, struct ata_port *ap, int port_no, void __iomem *mmio, void __iomem *port_mmio) @@ -1219,18 +1239,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap, if (rc) dev_warn(dev, "%s (%d)\n", emsg, rc); - /* clear SError */ - tmp = readl(port_mmio + PORT_SCR_ERR); - VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* clear port IRQ */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); - - writel(1 << port_no, mmio + HOST_IRQ_STAT); + ahci_port_clear_pending_irq(ap); /* mark esata ports */ tmp = readl(port_mmio + PORT_CMD); @@ -1560,6 +1569,8 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class, tf.command = ATA_BUSY; ata_tf_to_fis(&tf, 0, 0, d2h_fis); + ahci_port_clear_pending_irq(ap); + rc = sata_link_hardreset(link, timing, deadline, online, ahci_check_ready); -- Gitee