diff mbox series

[kirkstone] libssh2: backport fix for CVE-2023-48795

Message ID 20240419081824.998654-1-padalkards17082001@gmail.com
State Under Review
Delegated to: Steve Sakoman
Headers show
Series [kirkstone] libssh2: backport fix for CVE-2023-48795 | expand

Commit Message

dnyandev April 19, 2024, 8:18 a.m. UTC
Backport the upstream fix for CVE-2023-48795.

(From OE-Core rev: 314fa19c5e07fa632ff0434a6adbb97de1319a02)

Signed-off-by: Ross Burton <ross.burton@arm.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
(cherry picked from commit 3adac25f899054b7d1d8c14458a1a4cd310abbd7)
Signed-off-by: Bhabu Bindu <bhabu.bindu@kpit.com>
---
 .../libssh2/libssh2/CVE-2023-48795.patch      | 469 ++++++++++++++++++
 .../recipes-support/libssh2/libssh2_1.10.0.bb |   1 +
 2 files changed, 470 insertions(+)
 create mode 100644 meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch

Comments

Steve Sakoman April 23, 2024, 12:50 p.m. UTC | #1
There is already a fix for this CVE in kirkstone:

https://git.yoctoproject.org/poky/commit/?h=kirkstone&id=888ea24812c21910e74c864313be56f02fad6c2e

Steve

On Fri, Apr 19, 2024 at 1:19 AM dnyandev via lists.openembedded.org
<padalkards17082001=gmail.com@lists.openembedded.org> wrote:
>
> Backport the upstream fix for CVE-2023-48795.
>
> (From OE-Core rev: 314fa19c5e07fa632ff0434a6adbb97de1319a02)
>
> Signed-off-by: Ross Burton <ross.burton@arm.com>
> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> (cherry picked from commit 3adac25f899054b7d1d8c14458a1a4cd310abbd7)
> Signed-off-by: Bhabu Bindu <bhabu.bindu@kpit.com>
> ---
>  .../libssh2/libssh2/CVE-2023-48795.patch      | 469 ++++++++++++++++++
>  .../recipes-support/libssh2/libssh2_1.10.0.bb |   1 +
>  2 files changed, 470 insertions(+)
>  create mode 100644 meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
>
> diff --git a/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch b/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
> new file mode 100644
> index 0000000000..9aaa92bb1c
> --- /dev/null
> +++ b/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
> @@ -0,0 +1,469 @@
> +From d4634630432594b139b3af6b9f254b890c0f275d Mon Sep 17 00:00:00 2001
> +From: Michael Buckley <michael@buckleyisms.com>
> +Date: Thu, 30 Nov 2023 15:08:02 -0800
> +Subject: [PATCH] src: add 'strict KEX' to fix CVE-2023-48795 "Terrapin Attack"
> +
> +Refs:
> +https://terrapin-attack.com/
> +https://seclists.org/oss-sec/2023/q4/292
> +https://osv.dev/list?ecosystem=&q=CVE-2023-48795
> +https://github.com/advisories/GHSA-45x7-px36-x8w8
> +https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795
> +
> +Fixes #1290
> +Closes #1291
> +
> +CVE: CVE-2023-48795
> +Upstream-Status: Backport
> +Comments: Refreshed Hunks
> +
> +Signed-off-by: Ross Burton <ross.burton@arm.com>
> +Signed-off-by: Bindu Bhabu <bhabu.bindu@kpit.com>
> +---
> + src/kex.c          | 63 +++++++++++++++++++++++------------
> + src/libssh2_priv.h | 18 +++++++---
> + src/packet.c       | 83 +++++++++++++++++++++++++++++++++++++++++++---
> + src/packet.h       |  2 +-
> + src/session.c      |  3 ++
> + src/transport.c    | 12 ++++++-
> + 6 files changed, 149 insertions(+), 32 deletions(-)
> +
> +diff --git a/src/kex.c b/src/kex.c
> +index d4034a0a..b4b748ca 100644
> +--- a/src/kex.c
> ++++ b/src/kex.c
> +@@ -3026,6 +3026,13 @@ kex_method_ssh_curve25519_sha256 = {
> + };
> + #endif
> +
> ++static const LIBSSH2_KEX_METHOD
> ++kex_method_strict_client_extension = {
> ++    "kex-strict-c-v00@openssh.com",
> ++    NULL,
> ++    0,
> ++};
> ++
> + static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
> + #if LIBSSH2_ED25519
> +     &kex_method_ssh_curve25519_sha256,
> +@@ -3043,6 +3050,7 @@ static const LIBSSH2_KEX_METHOD *libssh2
> +     &kex_method_diffie_helman_group14_sha1,
> +     &kex_method_diffie_helman_group1_sha1,
> +     &kex_method_diffie_helman_group_exchange_sha1,
> ++    &kex_method_strict_client_extension,
> +   NULL
> + };
> +
> +@@ -3281,13 +3289,13 @@ static int kexinit(LIBSSH2_SESSION * ses
> +     return 0;
> + }
> +
> +-/* kex_agree_instr
> ++/* _libssh2_kex_agree_instr
> +  * Kex specific variant of strstr()
> +  * Needle must be precede by BOL or ',', and followed by ',' or EOL
> +  */
> +-static unsigned char *
> +-kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
> +-                const unsigned char *needle, unsigned long needle_len)
> ++unsigned char *
> ++_libssh2_kex_agree_instr(unsigned char *haystack, size_t haystack_len,
> ++                         const unsigned char *needle, size_t needle_len)
> + {
> +     unsigned char *s;
> +     unsigned char *end_haystack;
> +@@ -3398,7 +3406,7 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
> +         while(s && *s) {
> +             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
> +             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
> +-            if(kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
> ++            if(_libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
> +                 const LIBSSH2_HOSTKEY_METHOD *method =
> +                     (const LIBSSH2_HOSTKEY_METHOD *)
> +                     kex_get_method_by_name((char *) s, method_len,
> +@@ -3432,9 +3440,9 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
> +     }
> +
> +     while(hostkeyp && (*hostkeyp) && (*hostkeyp)->name) {
> +-        s = kex_agree_instr(hostkey, hostkey_len,
> +-                            (unsigned char *) (*hostkeyp)->name,
> +-                            strlen((*hostkeyp)->name));
> ++        s = _libssh2_kex_agree_instr(hostkey, hostkey_len,
> ++                                     (unsigned char *) (*hostkeyp)->name,
> ++                                     strlen((*hostkeyp)->name));
> +         if(s) {
> +             /* So far so good, but does it suit our purposes? (Encrypting vs
> +                Signing) */
> +@@ -3468,6 +3476,12 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
> + {
> +     const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
> +     unsigned char *s;
> ++    const unsigned char *strict =
> ++        (unsigned char *)"kex-strict-s-v00@openssh.com";
> ++
> ++    if(_libssh2_kex_agree_instr(kex, kex_len, strict, 28)) {
> ++        session->kex_strict = 1;
> ++    }
> +
> +     if(session->kex_prefs) {
> +         s = (unsigned char *) session->kex_prefs;
> +@@ -3475,7 +3489,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
> +         while(s && *s) {
> +             unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
> +             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
> +-            q = kex_agree_instr(kex, kex_len, s, method_len);
> ++            q = _libssh2_kex_agree_instr(kex, kex_len, s, method_len);
> +             if(q) {
> +                 const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
> +                     kex_get_method_by_name((char *) s, method_len,
> +@@ -3509,9 +3523,9 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
> +     }
> +
> +     while(*kexp && (*kexp)->name) {
> +-        s = kex_agree_instr(kex, kex_len,
> +-                            (unsigned char *) (*kexp)->name,
> +-                            strlen((*kexp)->name));
> ++        s = _libssh2_kex_agree_instr(kex, kex_len,
> ++                                     (unsigned char *) (*kexp)->name,
> ++                                     strlen((*kexp)->name));
> +         if(s) {
> +             /* We've agreed on a key exchange method,
> +              * Can we agree on a hostkey that works with this kex?
> +@@ -3555,7 +3569,7 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
> +             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
> +             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
> +
> +-            if(kex_agree_instr(crypt, crypt_len, s, method_len)) {
> ++            if(_libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
> +                 const LIBSSH2_CRYPT_METHOD *method =
> +                     (const LIBSSH2_CRYPT_METHOD *)
> +                     kex_get_method_by_name((char *) s, method_len,
> +@@ -3577,9 +3591,9 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
> +     }
> +
> +     while(*cryptp && (*cryptp)->name) {
> +-        s = kex_agree_instr(crypt, crypt_len,
> +-                            (unsigned char *) (*cryptp)->name,
> +-                            strlen((*cryptp)->name));
> ++        s = _libssh2_kex_agree_instr(crypt, crypt_len,
> ++                                     (unsigned char *) (*cryptp)->name,
> ++                                     strlen((*cryptp)->name));
> +         if(s) {
> +             endpoint->crypt = *cryptp;
> +             return 0;
> +@@ -3619,7 +3633,7 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
> +             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
> +             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
> +
> +-            if(kex_agree_instr(mac, mac_len, s, method_len)) {
> ++            if(_libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
> +                 const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
> +                     kex_get_method_by_name((char *) s, method_len,
> +                                            (const LIBSSH2_COMMON_METHOD **)
> +@@ -3640,8 +3654,9 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
> +     }
> +
> +     while(*macp && (*macp)->name) {
> +-        s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name,
> +-                            strlen((*macp)->name));
> ++        s = _libssh2_kex_agree_instr(mac, mac_len,
> ++                                     (unsigned char *) (*macp)->name,
> ++                                     strlen((*macp)->name));
> +         if(s) {
> +             endpoint->mac = *macp;
> +             return 0;
> +@@ -3672,7 +3687,7 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
> +             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
> +             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
> +
> +-            if(kex_agree_instr(comp, comp_len, s, method_len)) {
> ++            if(_libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
> +                 const LIBSSH2_COMP_METHOD *method =
> +                     (const LIBSSH2_COMP_METHOD *)
> +                     kex_get_method_by_name((char *) s, method_len,
> +@@ -3694,8 +3709,9 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
> +     }
> +
> +     while(*compp && (*compp)->name) {
> +-        s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name,
> +-                            strlen((*compp)->name));
> ++        s = _libssh2_kex_agree_instr(comp, comp_len,
> ++                                     (unsigned char *) (*compp)->name,
> ++                                     strlen((*compp)->name));
> +         if(s) {
> +             endpoint->comp = *compp;
> +             return 0;
> +@@ -3876,6 +3892,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
> +                 session->local.kexinit = key_state->oldlocal;
> +                 session->local.kexinit_len = key_state->oldlocal_len;
> +                 key_state->state = libssh2_NB_state_idle;
> ++                session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
> +                 session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
> +                 session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
> +                 return -1;
> +@@ -3901,6 +3918,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
> +                 session->local.kexinit = key_state->oldlocal;
> +                 session->local.kexinit_len = key_state->oldlocal_len;
> +                 key_state->state = libssh2_NB_state_idle;
> ++                session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
> +                 session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
> +                 session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
> +                 return -1;
> +@@ -3949,6 +3967,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
> +         session->remote.kexinit = NULL;
> +     }
> +
> ++    session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
> +     session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
> +     session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
> +
> +diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
> +index 82c3afe2..ee1d8b5c 100644
> +--- a/src/libssh2_priv.h
> ++++ b/src/libssh2_priv.h
> +@@ -640,6 +640,9 @@ struct _LIBSSH2_SESSION
> +     unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH];
> +     int server_hostkey_sha256_valid;
> +
> ++    /* Whether to use the OpenSSH Strict KEX extension */
> ++    int kex_strict;
> ++
> +     /* (remote as source of data -- packet_read ) */
> +     libssh2_endpoint_data remote;
> +
> +@@ -870,6 +873,7 @@ struct _LIBSSH2_SESSION
> +     int fullpacket_macstate;
> +     size_t fullpacket_payload_len;
> +     int fullpacket_packet_type;
> ++    uint32_t fullpacket_required_type;
> +
> +     /* State variables used in libssh2_sftp_init() */
> +     libssh2_nonblocking_states sftpInit_state;
> +@@ -910,10 +914,11 @@ struct _LIBSSH2_SESSION
> + };
> +
> + /* session.state bits */
> +-#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000001
> +-#define LIBSSH2_STATE_NEWKEYS           0x00000002
> +-#define LIBSSH2_STATE_AUTHENTICATED     0x00000004
> +-#define LIBSSH2_STATE_KEX_ACTIVE        0x00000008
> ++#define LIBSSH2_STATE_INITIAL_KEX       0x00000001
> ++#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000002
> ++#define LIBSSH2_STATE_NEWKEYS           0x00000004
> ++#define LIBSSH2_STATE_AUTHENTICATED     0x00000008
> ++#define LIBSSH2_STATE_KEX_ACTIVE        0x00000010
> +
> + /* session.flag helpers */
> + #ifdef MSG_NOSIGNAL
> +@@ -1144,6 +1149,11 @@ ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer,
> + int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
> +                           key_exchange_state_t * state);
> +
> ++unsigned char *_libssh2_kex_agree_instr(unsigned char *haystack,
> ++                                        size_t haystack_len,
> ++                                        const unsigned char *needle,
> ++                                        size_t needle_len);
> ++
> + /* Let crypt.c/hostkey.c expose their method structs */
> + const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
> + const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
> +diff --git a/src/packet.c b/src/packet.c
> +index b5b41981..35d4d39e 100644
> +--- a/src/packet.c
> ++++ b/src/packet.c
> +@@ -605,14 +605,13 @@ authagent_exit:
> +  * layer when it has received a packet.
> +  *
> +  * The input pointer 'data' is pointing to allocated data that this function
> +- * is asked to deal with so on failure OR success, it must be freed fine.
> +- * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
> ++ * will be freed unless return the code is LIBSSH2_ERROR_EAGAIN.
> +  *
> +  * This function will always be called with 'datalen' greater than zero.
> +  */
> + int
> + _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
> +-                    size_t datalen, int macstate)
> ++                    size_t datalen, int macstate, uint32_t seq)
> + {
> +     int rc = 0;
> +     unsigned char *message = NULL;
> +@@ -657,6 +656,70 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
> +         break;
> +     }
> +
> ++    if(session->state & LIBSSH2_STATE_INITIAL_KEX) {
> ++        if(msg == SSH_MSG_KEXINIT) {
> ++            if(!session->kex_strict) {
> ++                if(datalen < 17) {
> ++                    LIBSSH2_FREE(session, data);
> ++                    session->packAdd_state = libssh2_NB_state_idle;
> ++                    return _libssh2_error(session,
> ++                                          LIBSSH2_ERROR_BUFFER_TOO_SMALL,
> ++                                          "Data too short extracting kex");
> ++                }
> ++                else {
> ++                    const unsigned char *strict =
> ++                    (unsigned char *)"kex-strict-s-v00@openssh.com";
> ++                    struct string_buf buf;
> ++                    unsigned char *algs = NULL;
> ++                    size_t algs_len = 0;
> ++
> ++                    buf.data = (unsigned char *)data;
> ++                    buf.dataptr = buf.data;
> ++                    buf.len = datalen;
> ++                    buf.dataptr += 17; /* advance past type and cookie */
> ++
> ++                    if(_libssh2_get_string(&buf, &algs, &algs_len)) {
> ++                        LIBSSH2_FREE(session, data);
> ++                        session->packAdd_state = libssh2_NB_state_idle;
> ++                        return _libssh2_error(session,
> ++                                              LIBSSH2_ERROR_BUFFER_TOO_SMALL,
> ++                                              "Algs too short");
> ++                    }
> ++
> ++                    if(algs_len == 0 ||
> ++                       _libssh2_kex_agree_instr(algs, algs_len, strict, 28)) {
> ++                        session->kex_strict = 1;
> ++                    }
> ++                }
> ++            }
> ++
> ++            if(session->kex_strict && seq) {
> ++                LIBSSH2_FREE(session, data);
> ++                session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
> ++                session->packAdd_state = libssh2_NB_state_idle;
> ++                libssh2_session_disconnect(session, "strict KEX violation: "
> ++                                           "KEXINIT was not the first packet");
> ++
> ++                return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
> ++                                      "strict KEX violation: "
> ++                                      "KEXINIT was not the first packet");
> ++            }
> ++        }
> ++
> ++        if(session->kex_strict && session->fullpacket_required_type &&
> ++            session->fullpacket_required_type != msg) {
> ++            LIBSSH2_FREE(session, data);
> ++            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
> ++            session->packAdd_state = libssh2_NB_state_idle;
> ++            libssh2_session_disconnect(session, "strict KEX violation: "
> ++                                       "unexpected packet type");
> ++
> ++            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
> ++                                  "strict KEX violation: "
> ++                                  "unexpected packet type");
> ++        }
> ++    }
> ++
> +     if(session->packAdd_state == libssh2_NB_state_allocated) {
> +         /* A couple exceptions to the packet adding rule: */
> +         switch(msg) {
> +@@ -1341,6 +1404,15 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
> +
> +             return 0;
> +         }
> ++        else if(session->kex_strict &&
> ++                (session->state & LIBSSH2_STATE_INITIAL_KEX)) {
> ++            libssh2_session_disconnect(session, "strict KEX violation: "
> ++                                       "unexpected packet type");
> ++
> ++            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
> ++                                  "strict KEX violation: "
> ++                                  "unexpected packet type");
> ++        }
> +         packet = _libssh2_list_next(&packet->node);
> +     }
> +     return -1;
> +@@ -1402,7 +1474,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
> +     }
> +
> +     while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
> +-        int ret = _libssh2_transport_read(session);
> ++        int ret;
> ++        session->fullpacket_required_type = packet_type;
> ++        ret = _libssh2_transport_read(session);
> ++        session->fullpacket_required_type = 0;
> +         if(ret == LIBSSH2_ERROR_EAGAIN)
> +             return ret;
> +         else if(ret < 0) {
> +diff --git a/src/packet.h b/src/packet.h
> +index 79018bcf..6ea100a5 100644
> +--- a/src/packet.h
> ++++ b/src/packet.h
> +@@ -71,6 +71,6 @@ int _libssh2_packet_burn(LIBSSH2_SESSION * session,
> + int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
> +                           unsigned long data_len);
> + int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
> +-                        size_t datalen, int macstate);
> ++                        size_t datalen, int macstate, uint32_t seq);
> +
> + #endif /* __LIBSSH2_PACKET_H */
> +diff --git a/src/session.c b/src/session.c
> +index a4d602ba..f4bafb57 100644
> +--- a/src/session.c
> ++++ b/src/session.c
> +@@ -500,6 +500,8 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FU
> +         session->abstract = abstract;
> +         session->api_timeout = 0; /* timeout-free API by default */
> +         session->api_block_mode = 1; /* blocking API by default */
> ++        session->state = LIBSSH2_STATE_INITIAL_KEX;
> ++        session->fullpacket_required_type = 0;
> +         _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
> +                        "New session resource allocated");
> +         _libssh2_init_if_needed();
> +@@ -1186,6 +1188,7 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason,
> +                               const char *desc, const char *lang)
> + {
> +     int rc;
> ++    session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
> +     session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
> +     BLOCK_ADJUST(rc, session,
> +                  session_disconnect(session, reason, desc, lang));
> +diff --git a/src/transport.c b/src/transport.c
> +index 6d902d33..3b30ff84 100644
> +--- a/src/transport.c
> ++++ b/src/transport.c
> +@@ -187,6 +187,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
> +     struct transportpacket *p = &session->packet;
> +     int rc;
> +     int compressed;
> ++    uint32_t seq = session->remote.seqno;
> +
> +     if(session->fullpacket_state == libssh2_NB_state_idle) {
> +         session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
> +@@ -318,7 +319,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
> +     if(session->fullpacket_state == libssh2_NB_state_created) {
> +         rc = _libssh2_packet_add(session, p->payload,
> +                                  session->fullpacket_payload_len,
> +-                                 session->fullpacket_macstate);
> ++                                 session->fullpacket_macstate, seq);
> +         if(rc == LIBSSH2_ERROR_EAGAIN)
> +             return rc;
> +         if(rc) {
> +@@ -329,6 +330,11 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
> +
> +     session->fullpacket_state = libssh2_NB_state_idle;
> +
> ++    if(session->kex_strict &&
> ++        session->fullpacket_packet_type == SSH_MSG_NEWKEYS) {
> ++        session->remote.seqno = 0;
> ++    }
> ++
> +     return session->fullpacket_packet_type;
> + }
> +
> +@@ -892,6 +892,10 @@ int _libssh2_transport_send(LIBSSH2_SESS
> +
> +     session->local.seqno++;
> +
> ++    if(session->kex_strict && data[0] == SSH_MSG_NEWKEYS) {
> ++        session->local.seqno = 0;
> ++    }
> ++
> +     ret = LIBSSH2_SEND(session, p->outbuf, total_length,
> +                         LIBSSH2_SOCKET_SEND_FLAGS(session));
> +     if(ret < 0)
> +--
> +2.34.1
> +
> diff --git a/meta/recipes-support/libssh2/libssh2_1.10.0.bb b/meta/recipes-support/libssh2/libssh2_1.10.0.bb
> index 8483a292c2..9ade9f335c 100644
> --- a/meta/recipes-support/libssh2/libssh2_1.10.0.bb
> +++ b/meta/recipes-support/libssh2/libssh2_1.10.0.bb
> @@ -11,6 +11,7 @@ SRC_URI = "http://www.libssh2.org/download/${BP}.tar.gz \
>             file://fix-ssh2-test.patch \
>             file://run-ptest \
>             file://CVE-2020-22218.patch \
> +           file://CVE-2023-48795.patch \
>             "
>
>  SRC_URI[sha256sum] = "2d64e90f3ded394b91d3a2e774ca203a4179f69aebee03003e5a6fa621e41d51"
> --
> 2.25.1
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#198528): https://lists.openembedded.org/g/openembedded-core/message/198528
> Mute This Topic: https://lists.openembedded.org/mt/105614205/3620601
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [steve@sakoman.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
diff mbox series

Patch

diff --git a/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch b/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
new file mode 100644
index 0000000000..9aaa92bb1c
--- /dev/null
+++ b/meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
@@ -0,0 +1,469 @@ 
+From d4634630432594b139b3af6b9f254b890c0f275d Mon Sep 17 00:00:00 2001
+From: Michael Buckley <michael@buckleyisms.com>
+Date: Thu, 30 Nov 2023 15:08:02 -0800
+Subject: [PATCH] src: add 'strict KEX' to fix CVE-2023-48795 "Terrapin Attack"
+
+Refs:
+https://terrapin-attack.com/
+https://seclists.org/oss-sec/2023/q4/292
+https://osv.dev/list?ecosystem=&q=CVE-2023-48795
+https://github.com/advisories/GHSA-45x7-px36-x8w8
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795
+
+Fixes #1290
+Closes #1291
+
+CVE: CVE-2023-48795
+Upstream-Status: Backport
+Comments: Refreshed Hunks
+
+Signed-off-by: Ross Burton <ross.burton@arm.com>
+Signed-off-by: Bindu Bhabu <bhabu.bindu@kpit.com>
+---
+ src/kex.c          | 63 +++++++++++++++++++++++------------
+ src/libssh2_priv.h | 18 +++++++---
+ src/packet.c       | 83 +++++++++++++++++++++++++++++++++++++++++++---
+ src/packet.h       |  2 +-
+ src/session.c      |  3 ++
+ src/transport.c    | 12 ++++++-
+ 6 files changed, 149 insertions(+), 32 deletions(-)
+
+diff --git a/src/kex.c b/src/kex.c
+index d4034a0a..b4b748ca 100644
+--- a/src/kex.c
++++ b/src/kex.c
+@@ -3026,6 +3026,13 @@ kex_method_ssh_curve25519_sha256 = {
+ };
+ #endif
+ 
++static const LIBSSH2_KEX_METHOD
++kex_method_strict_client_extension = {
++    "kex-strict-c-v00@openssh.com",
++    NULL,
++    0,
++};
++
+ static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
+ #if LIBSSH2_ED25519
+     &kex_method_ssh_curve25519_sha256,
+@@ -3043,6 +3050,7 @@ static const LIBSSH2_KEX_METHOD *libssh2
+     &kex_method_diffie_helman_group14_sha1,
+     &kex_method_diffie_helman_group1_sha1,
+     &kex_method_diffie_helman_group_exchange_sha1,
++    &kex_method_strict_client_extension,
+   NULL
+ };
+
+@@ -3281,13 +3289,13 @@ static int kexinit(LIBSSH2_SESSION * ses
+     return 0;
+ }
+ 
+-/* kex_agree_instr
++/* _libssh2_kex_agree_instr
+  * Kex specific variant of strstr()
+  * Needle must be precede by BOL or ',', and followed by ',' or EOL
+  */
+-static unsigned char *
+-kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
+-                const unsigned char *needle, unsigned long needle_len)
++unsigned char *
++_libssh2_kex_agree_instr(unsigned char *haystack, size_t haystack_len,
++                         const unsigned char *needle, size_t needle_len)
+ {
+     unsigned char *s;
+     unsigned char *end_haystack;
+@@ -3398,7 +3406,7 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
+         while(s && *s) {
+             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
+-            if(kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
++            if(_libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
+                 const LIBSSH2_HOSTKEY_METHOD *method =
+                     (const LIBSSH2_HOSTKEY_METHOD *)
+                     kex_get_method_by_name((char *) s, method_len,
+@@ -3432,9 +3440,9 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
+     }
+ 
+     while(hostkeyp && (*hostkeyp) && (*hostkeyp)->name) {
+-        s = kex_agree_instr(hostkey, hostkey_len,
+-                            (unsigned char *) (*hostkeyp)->name,
+-                            strlen((*hostkeyp)->name));
++        s = _libssh2_kex_agree_instr(hostkey, hostkey_len,
++                                     (unsigned char *) (*hostkeyp)->name,
++                                     strlen((*hostkeyp)->name));
+         if(s) {
+             /* So far so good, but does it suit our purposes? (Encrypting vs
+                Signing) */
+@@ -3468,6 +3476,12 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
+ {
+     const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
+     unsigned char *s;
++    const unsigned char *strict =
++        (unsigned char *)"kex-strict-s-v00@openssh.com";
++
++    if(_libssh2_kex_agree_instr(kex, kex_len, strict, 28)) {
++        session->kex_strict = 1;
++    }
+ 
+     if(session->kex_prefs) {
+         s = (unsigned char *) session->kex_prefs;
+@@ -3475,7 +3489,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
+         while(s && *s) {
+             unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
+             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
+-            q = kex_agree_instr(kex, kex_len, s, method_len);
++            q = _libssh2_kex_agree_instr(kex, kex_len, s, method_len);
+             if(q) {
+                 const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
+                     kex_get_method_by_name((char *) s, method_len,
+@@ -3509,9 +3523,9 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
+     }
+ 
+     while(*kexp && (*kexp)->name) {
+-        s = kex_agree_instr(kex, kex_len,
+-                            (unsigned char *) (*kexp)->name,
+-                            strlen((*kexp)->name));
++        s = _libssh2_kex_agree_instr(kex, kex_len,
++                                     (unsigned char *) (*kexp)->name,
++                                     strlen((*kexp)->name));
+         if(s) {
+             /* We've agreed on a key exchange method,
+              * Can we agree on a hostkey that works with this kex?
+@@ -3555,7 +3569,7 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
+             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
+ 
+-            if(kex_agree_instr(crypt, crypt_len, s, method_len)) {
++            if(_libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
+                 const LIBSSH2_CRYPT_METHOD *method =
+                     (const LIBSSH2_CRYPT_METHOD *)
+                     kex_get_method_by_name((char *) s, method_len,
+@@ -3577,9 +3591,9 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
+     }
+ 
+     while(*cryptp && (*cryptp)->name) {
+-        s = kex_agree_instr(crypt, crypt_len,
+-                            (unsigned char *) (*cryptp)->name,
+-                            strlen((*cryptp)->name));
++        s = _libssh2_kex_agree_instr(crypt, crypt_len,
++                                     (unsigned char *) (*cryptp)->name,
++                                     strlen((*cryptp)->name));
+         if(s) {
+             endpoint->crypt = *cryptp;
+             return 0;
+@@ -3619,7 +3633,7 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
+             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
+ 
+-            if(kex_agree_instr(mac, mac_len, s, method_len)) {
++            if(_libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
+                 const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
+                     kex_get_method_by_name((char *) s, method_len,
+                                            (const LIBSSH2_COMMON_METHOD **)
+@@ -3640,8 +3654,9 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
+     }
+ 
+     while(*macp && (*macp)->name) {
+-        s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name,
+-                            strlen((*macp)->name));
++        s = _libssh2_kex_agree_instr(mac, mac_len,
++                                     (unsigned char *) (*macp)->name,
++                                     strlen((*macp)->name));
+         if(s) {
+             endpoint->mac = *macp;
+             return 0;
+@@ -3672,7 +3687,7 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
+             unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+             size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
+ 
+-            if(kex_agree_instr(comp, comp_len, s, method_len)) {
++            if(_libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
+                 const LIBSSH2_COMP_METHOD *method =
+                     (const LIBSSH2_COMP_METHOD *)
+                     kex_get_method_by_name((char *) s, method_len,
+@@ -3694,8 +3709,9 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
+     }
+ 
+     while(*compp && (*compp)->name) {
+-        s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name,
+-                            strlen((*compp)->name));
++        s = _libssh2_kex_agree_instr(comp, comp_len,
++                                     (unsigned char *) (*compp)->name,
++                                     strlen((*compp)->name));
+         if(s) {
+             endpoint->comp = *compp;
+             return 0;
+@@ -3876,6 +3892,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
+                 session->local.kexinit = key_state->oldlocal;
+                 session->local.kexinit_len = key_state->oldlocal_len;
+                 key_state->state = libssh2_NB_state_idle;
++                session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
+                 session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
+                 session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
+                 return -1;
+@@ -3901,6 +3918,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
+                 session->local.kexinit = key_state->oldlocal;
+                 session->local.kexinit_len = key_state->oldlocal_len;
+                 key_state->state = libssh2_NB_state_idle;
++                session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
+                 session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
+                 session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
+                 return -1;
+@@ -3949,6 +3967,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
+         session->remote.kexinit = NULL;
+     }
+ 
++    session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
+     session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
+     session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
+ 
+diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
+index 82c3afe2..ee1d8b5c 100644
+--- a/src/libssh2_priv.h
++++ b/src/libssh2_priv.h
+@@ -640,6 +640,9 @@ struct _LIBSSH2_SESSION
+     unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH];
+     int server_hostkey_sha256_valid;
+ 
++    /* Whether to use the OpenSSH Strict KEX extension */
++    int kex_strict;
++
+     /* (remote as source of data -- packet_read ) */
+     libssh2_endpoint_data remote;
+ 
+@@ -870,6 +873,7 @@ struct _LIBSSH2_SESSION
+     int fullpacket_macstate;
+     size_t fullpacket_payload_len;
+     int fullpacket_packet_type;
++    uint32_t fullpacket_required_type;
+ 
+     /* State variables used in libssh2_sftp_init() */
+     libssh2_nonblocking_states sftpInit_state;
+@@ -910,10 +914,11 @@ struct _LIBSSH2_SESSION
+ };
+ 
+ /* session.state bits */
+-#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000001
+-#define LIBSSH2_STATE_NEWKEYS           0x00000002
+-#define LIBSSH2_STATE_AUTHENTICATED     0x00000004
+-#define LIBSSH2_STATE_KEX_ACTIVE        0x00000008
++#define LIBSSH2_STATE_INITIAL_KEX       0x00000001
++#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000002
++#define LIBSSH2_STATE_NEWKEYS           0x00000004
++#define LIBSSH2_STATE_AUTHENTICATED     0x00000008
++#define LIBSSH2_STATE_KEX_ACTIVE        0x00000010
+ 
+ /* session.flag helpers */
+ #ifdef MSG_NOSIGNAL
+@@ -1144,6 +1149,11 @@ ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer,
+ int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
+                           key_exchange_state_t * state);
+ 
++unsigned char *_libssh2_kex_agree_instr(unsigned char *haystack,
++                                        size_t haystack_len,
++                                        const unsigned char *needle,
++                                        size_t needle_len);
++
+ /* Let crypt.c/hostkey.c expose their method structs */
+ const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
+ const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
+diff --git a/src/packet.c b/src/packet.c
+index b5b41981..35d4d39e 100644
+--- a/src/packet.c
++++ b/src/packet.c
+@@ -605,14 +605,13 @@ authagent_exit:
+  * layer when it has received a packet.
+  *
+  * The input pointer 'data' is pointing to allocated data that this function
+- * is asked to deal with so on failure OR success, it must be freed fine.
+- * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
++ * will be freed unless return the code is LIBSSH2_ERROR_EAGAIN.
+  *
+  * This function will always be called with 'datalen' greater than zero.
+  */
+ int
+ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
+-                    size_t datalen, int macstate)
++                    size_t datalen, int macstate, uint32_t seq)
+ {
+     int rc = 0;
+     unsigned char *message = NULL;
+@@ -657,6 +656,70 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
+         break;
+     }
+ 
++    if(session->state & LIBSSH2_STATE_INITIAL_KEX) {
++        if(msg == SSH_MSG_KEXINIT) {
++            if(!session->kex_strict) {
++                if(datalen < 17) {
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return _libssh2_error(session,
++                                          LIBSSH2_ERROR_BUFFER_TOO_SMALL,
++                                          "Data too short extracting kex");
++                }
++                else {
++                    const unsigned char *strict =
++                    (unsigned char *)"kex-strict-s-v00@openssh.com";
++                    struct string_buf buf;
++                    unsigned char *algs = NULL;
++                    size_t algs_len = 0;
++
++                    buf.data = (unsigned char *)data;
++                    buf.dataptr = buf.data;
++                    buf.len = datalen;
++                    buf.dataptr += 17; /* advance past type and cookie */
++
++                    if(_libssh2_get_string(&buf, &algs, &algs_len)) {
++                        LIBSSH2_FREE(session, data);
++                        session->packAdd_state = libssh2_NB_state_idle;
++                        return _libssh2_error(session,
++                                              LIBSSH2_ERROR_BUFFER_TOO_SMALL,
++                                              "Algs too short");
++                    }
++
++                    if(algs_len == 0 ||
++                       _libssh2_kex_agree_instr(algs, algs_len, strict, 28)) {
++                        session->kex_strict = 1;
++                    }
++                }
++            }
++
++            if(session->kex_strict && seq) {
++                LIBSSH2_FREE(session, data);
++                session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
++                session->packAdd_state = libssh2_NB_state_idle;
++                libssh2_session_disconnect(session, "strict KEX violation: "
++                                           "KEXINIT was not the first packet");
++
++                return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
++                                      "strict KEX violation: "
++                                      "KEXINIT was not the first packet");
++            }
++        }
++
++        if(session->kex_strict && session->fullpacket_required_type &&
++            session->fullpacket_required_type != msg) {
++            LIBSSH2_FREE(session, data);
++            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
++            session->packAdd_state = libssh2_NB_state_idle;
++            libssh2_session_disconnect(session, "strict KEX violation: "
++                                       "unexpected packet type");
++
++            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
++                                  "strict KEX violation: "
++                                  "unexpected packet type");
++        }
++    }
++
+     if(session->packAdd_state == libssh2_NB_state_allocated) {
+         /* A couple exceptions to the packet adding rule: */
+         switch(msg) {
+@@ -1341,6 +1404,15 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
+ 
+             return 0;
+         }
++        else if(session->kex_strict &&
++                (session->state & LIBSSH2_STATE_INITIAL_KEX)) {
++            libssh2_session_disconnect(session, "strict KEX violation: "
++                                       "unexpected packet type");
++
++            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
++                                  "strict KEX violation: "
++                                  "unexpected packet type");
++        }
+         packet = _libssh2_list_next(&packet->node);
+     }
+     return -1;
+@@ -1402,7 +1474,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
+     }
+ 
+     while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+-        int ret = _libssh2_transport_read(session);
++        int ret;
++        session->fullpacket_required_type = packet_type;
++        ret = _libssh2_transport_read(session);
++        session->fullpacket_required_type = 0;
+         if(ret == LIBSSH2_ERROR_EAGAIN)
+             return ret;
+         else if(ret < 0) {
+diff --git a/src/packet.h b/src/packet.h
+index 79018bcf..6ea100a5 100644
+--- a/src/packet.h
++++ b/src/packet.h
+@@ -71,6 +71,6 @@ int _libssh2_packet_burn(LIBSSH2_SESSION * session,
+ int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
+                           unsigned long data_len);
+ int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
+-                        size_t datalen, int macstate);
++                        size_t datalen, int macstate, uint32_t seq);
+ 
+ #endif /* __LIBSSH2_PACKET_H */
+diff --git a/src/session.c b/src/session.c
+index a4d602ba..f4bafb57 100644
+--- a/src/session.c
++++ b/src/session.c
+@@ -500,6 +500,8 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FU
+         session->abstract = abstract;
+         session->api_timeout = 0; /* timeout-free API by default */
+         session->api_block_mode = 1; /* blocking API by default */
++        session->state = LIBSSH2_STATE_INITIAL_KEX;
++        session->fullpacket_required_type = 0;
+         _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
+                        "New session resource allocated");
+         _libssh2_init_if_needed();
+@@ -1186,6 +1188,7 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason,
+                               const char *desc, const char *lang)
+ {
+     int rc;
++    session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
+     session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
+     BLOCK_ADJUST(rc, session,
+                  session_disconnect(session, reason, desc, lang));
+diff --git a/src/transport.c b/src/transport.c
+index 6d902d33..3b30ff84 100644
+--- a/src/transport.c
++++ b/src/transport.c
+@@ -187,6 +187,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
+     struct transportpacket *p = &session->packet;
+     int rc;
+     int compressed;
++    uint32_t seq = session->remote.seqno;
+ 
+     if(session->fullpacket_state == libssh2_NB_state_idle) {
+         session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
+@@ -318,7 +319,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
+     if(session->fullpacket_state == libssh2_NB_state_created) {
+         rc = _libssh2_packet_add(session, p->payload,
+                                  session->fullpacket_payload_len,
+-                                 session->fullpacket_macstate);
++                                 session->fullpacket_macstate, seq);
+         if(rc == LIBSSH2_ERROR_EAGAIN)
+             return rc;
+         if(rc) {
+@@ -329,6 +330,11 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
+ 
+     session->fullpacket_state = libssh2_NB_state_idle;
+ 
++    if(session->kex_strict &&
++        session->fullpacket_packet_type == SSH_MSG_NEWKEYS) {
++        session->remote.seqno = 0;
++    }
++
+     return session->fullpacket_packet_type;
+ }
+ 
+@@ -892,6 +892,10 @@ int _libssh2_transport_send(LIBSSH2_SESS
+ 
+     session->local.seqno++;
+ 
++    if(session->kex_strict && data[0] == SSH_MSG_NEWKEYS) {
++        session->local.seqno = 0;
++    }
++
+     ret = LIBSSH2_SEND(session, p->outbuf, total_length,
+                         LIBSSH2_SOCKET_SEND_FLAGS(session));
+     if(ret < 0)
+-- 
+2.34.1
+
diff --git a/meta/recipes-support/libssh2/libssh2_1.10.0.bb b/meta/recipes-support/libssh2/libssh2_1.10.0.bb
index 8483a292c2..9ade9f335c 100644
--- a/meta/recipes-support/libssh2/libssh2_1.10.0.bb
+++ b/meta/recipes-support/libssh2/libssh2_1.10.0.bb
@@ -11,6 +11,7 @@  SRC_URI = "http://www.libssh2.org/download/${BP}.tar.gz \
            file://fix-ssh2-test.patch \
            file://run-ptest \
            file://CVE-2020-22218.patch \
+           file://CVE-2023-48795.patch \
            "
 
 SRC_URI[sha256sum] = "2d64e90f3ded394b91d3a2e774ca203a4179f69aebee03003e5a6fa621e41d51"