LibreSSLÖ®CVE-2023-35784Îó²îÆÊÎö

Ðû²¼Ê±¼ä 2024-06-28

LibreSSLÊÇ2014ÄêÐÄÔàµÎѪÎó²î±¬·¢ºó £¬OpenBSD fork OpenSSL 1.0.1g²¢¾ÙÐÐά»¤µÄÇå¾²SSL¿â¡£


CVE-2023-35784ÊÇLibreSSL 3.6.2µÈ°æ±¾ÖеÄssl3_freeº¯ÊýÔÚÊÍ·Ås->internal->verified_chainºóδÄÜʵʱ¸³ÖµÎªNULL £¬µ¼ÖÂDZÔÚµÄDouble Free»òÕßUse After FreeÎó²î¡£

Ò»¡¢Îó²îÐÅÏ¢


? Îó²îÐÎò


A double free or use after free could occur after SSL_clear in OpenBSD 7.2 before errata 026 and 7.3 before errata 004, and in LibreSSL before 3.6.3 and 3.7.x before 3.7.3. NOTE: OpenSSL is not affected.


²¹¶¡


    Index: lib/libssl/s3_lib.c

    ===================================================================

    RCS file: /cvs/src/lib/libssl/s3_lib.c,v

    diff -u -p -r1.238 s3_lib.c

    --- lib/libssl/s3_lib.c 21 Aug 2022 19:39:44 -0000  1.238

    +++ lib/libssl/s3_lib.c 15 May 2023 05:05:28 -0000

    @@ -1573,6 +1573,7 @@ ssl3_free(SSL *s)    

    sk_X509_NAME_pop_free(s->s3->hs.tls12.ca_names, X509_NAME_free);    

    sk_X509_pop_free(s->internal->verified_chain, X509_free);

    +   s->internal->verified_chain = NULL;    

    tls1_transcript_free(s);    

    tls1_transcript_hash_free(s)


    ÉÏÃæµÄÎó²îÐÎòºÍ²¹¶¡ÊÇÏÖÔÚÄÜÔÚÍøÂçÉÏÕÒµ½µÄËùÓÐÓÐÒâÒåµÄ¹ûÕæÄÚÈÝ¡£


    ¶þ¡¢Îó²îÆÊÎö


    ÕâÀïÆÊÎö3.6.3°æ±¾´ò¹ý²¹¶¡ºóµÄssl3_freeº¯Êý£¨/// ...ÂÔ... ΪʡÂԵIJ¿·ÖÎ޹شúÂë £¬ÏÂÎÄÏàͬ£©£º


      // 3.6.3 s3_lib.c
      void
      ssl3_free(SSL *s)
      {    
      if (s == NULL)        
      return;
      tls1_cleanup_key_block(s);    
      ssl3_release_read_buffer(s);    
      ssl3_release_write_buffer(s);

      /// ...ÂÔ...

      sk_X509_NAME_pop_free(s->s3->hs.tls12.ca_names, X509_NAME_free);
      sk_X509_pop_free(s->internal->verified_chain, X509_free);////// [1]    
      s->internal->verified_chain = NULL;////// [2]
      tls1_transcript_free(s);    

      /// ...ÂÔ...

      freezero(s->s3,sizeof(*s->s3));
      s->s3 = NULL;
      }


      Ïà±È3.6.2°æ±¾µÄssl3_freeº¯Êý £¬¸Ãº¯Êý¶àÁË[2]´¦¸³ÖµÎªNULLµÄÓï¾ä¡£


      2.1 ¼¸¸ö½á¹¹Ìå


      ÕâÀïÉæ¼°µ½¼¸¸öÖ÷ÒªµÄ½á¹¹Ì壨v3.6.2£© £¬Ê×ÏÈÊÇSSL½á¹¹Ìå¡£

      SSL½á¹¹ÌåÊÇLibreSSL£¨°üÀ¨OpenSSL£©¾ÙÐÐÇå¾²Ì×½Ó×Ö±à³Ìʱ×îÖ±½ÓÓë³ÌÐòÔ±´ò½»µÀµÄ½á¹¹Ìå £¬Çå¾²±à³ÌÖ÷ÒªµÄ²Ù×÷¶¼Ö±½Ó»ò¼ä½ÓÓëÆäÓÐ¹Ø £¬Òò´Ë £¬ÆäÖ÷ÒªÐÔ²»ÑÔ¶øÓ÷¡£


      2.1.1 SSL


        typedef struct ssl_st SSL;
        struct ssl_st {
        /* protocol version     
        * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)     
        */

        int version;

        const SSL_METHOD *method;

        /// ...ÂÔ...

        int server;/* are we the server side? - mostly used by SSL_clear*/

        struct ssl3_state_st *s3; /* SSLv3 variables */   ////////// [1]    
        struct dtls1_state_st *d1; /* DTLSv1 variables */
        X509_VERIFY_PARAM *param;       

         /// ...ÂÔ...
         
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */

        #define session_ctx initial_ctx

        struct ssl_internal_st *internal;    /////////// [2]

        };


        ÔڸýṹÌåÖÐ £¬Öصã¹ØעĩβµÄinternal³ÉÔ±±äÁ¿ £¬ÓÉÓÚµ¼ÖÂÎó²î±¬·¢µÄverified_chainλÓڸýṹÌå±äÁ¿ÄÚ £»ÎÒÃÇͬʱעÖØs3³ÉÔ±±äÁ¿ £¬×¢ÖصÄÔµ¹ÊÔ­ÓɼûÏÂÎÄ¡£


        2.1.2 ssl_internal_st


        ssl_internal_st½á¹¹ÌåµÄ½ç˵ÈçÏ£º


          typedef struct ssl_internal_st {    

          struct tls13_ctx *tls13;
          uint16_t min_tls_version;
          uint16_t max_tls_version;
          /*
          * These may be zero to imply minimum or maximum version supported by
          * the method.     
          */    
          uint16_t min_proto_version;
          uint16_t max_proto_version;
              
           /// ...ÂÔ...
              
          int empty_record_count;
          size_t num_tickets; 
          /* Unused, for OpenSSL compatibility */

          STACK_OF(X509) *verified_chain;  /////// [1]
          } SSL_INTERNAL;


          Îó²î±¬·¢µÄ³ÉÔ±±äÁ¿verified_chainλÓÚssl_internal_st½á¹¹ÌåµÄĩβ £¬ÎªÒ»STACK_OF(X509)Ö¸Õë¡£


          2.1.3 BTW


          ÕâÀï˳±ãÌáÒ»ÏÂSSL£¨Ö¸¹ãÒåÉϵÄSSL £¬°üÀ¨ºóÐøµÄTLS£©µÄÖ¤Êéϵͳ £¬ÓÐÀûÓÚÎÒÃÇÃ÷È·Îó²î±¬·¢µÄ»úÀí¡£


          ? SSLÖ¤Êéϵͳ


          £¨1£©Öð¼¶Ç©·¢


          Ò»Ñùƽ³£À´Ëµ £¬·þÎñÆ÷·µ»ØµÄÖ¤Êé°üÀ¨Á˶à¸ö»ú¹¹ £¬ÓɸùÖ¤Êé½ÒÏþ»ú¹¹Öð¼¶ÏòÏÂÇ©·¢¡£Ò԰ٶȵÄÖ¤ÊéΪÀý £¬¸ùÖ¤Êé½ÒÏþ»ú¹¹GlobalSign½ÒÏþ¸ø»ú¹¹GlobalSign BE £¬¶øGlobalSign BEÔÙ½ÒÏþ¸ø°Ù¶È¡£


          £¨2£©Ö¤Êé°üÀ¨½ÒÏþÕß¡¢½ÒÏþ¸øË­¡¢¹«Ô¿¡¢Ð£ÑéµÈÐÅÏ¢


          ·þÎñÆ÷·µ»ØµÄÖ¤ÊéÖÐ £¬°üÀ¨Á˸÷¸ö»ú¹¹µÄ¶àÖÖÐÅÏ¢ £¬ºÃ±È½ÒÏþÕß £¬½ÒÏþ¸øË­ £¬¹«Ô¿ÐÅÏ¢ £¬°æ±¾¡¢ÓÐÓÃÆÚ¡¢ÒÔ¼°ÊðÃûµÈ¡£


          £¨3£©Á´Ê½°üÀ¨


          • Öð¼¶Ç©·¢µÄÖ¤Êé £¬È·¶¨ÁËÔÚÊý¾ÝÐòÁÐÉÏÓÉÏÂÖÁÉϵÄÁ´Ê½°üÀ¨½á¹¹¡£
          • ²Ù×÷ϵͳÖÁÉÙ°üÀ¨¸ùÖ¤Êé¡£
          • Ö¤Êéϵͳȷ±£ÁËÁ´Ê½¿ÉÐÅ £¬´Ó¶øÒªÇó²Ù×÷ϵͳÖÁÉÙÒª°üÀ¨¸ùÖ¤Êé £¬ºÃ±ÈGlobalSignµÄ¸ùÖ¤Êé¡£

          £¨4£©×ÔÊðÃû


          • Ò»¼¶
          • Ö÷Òª¹©²âÊÔÓÃ
          • ȱÏÝ£ºÖÐÐÄÈ˹¥»÷

          ÕâÀïÒ²ÌáÒ»ÏÂ×ÔÊðÃûÖ¤Êé £¬Í¨³£ÓÉOpenSSL³ÌÐòÌìÉú £¬ÓÉ×Ô¼º½ÒÏþ¸ø×Ô¼º £¬Ò²Òò´Ë £¬ÎÞ·¨Í¨¹ý²Ù×÷ϵͳµÄÖ¤ÊéÐÅÍÐÁ´ £¬ÎÞ·¨¶Ô¿¹ÖÐÐÄÈ˹¥»÷ £¬Ò»Ñùƽ³£½öÓÃÓÚ²âÊÔ¡£


          ÏÂͼΪ·þÎñÆ÷·µ»ØµÄ°Ù¶ÈÖ¤ÊéÁ´£º


          ͼƬ1.png


          STACK_OF(X)ºê


          ¸ÃÎó²î±¬·¢ÓÚSTACK_OF(X509)ºêÖ¸ÏòµÄ¶Ñ £¬Òò´Ë £¬ÓÐÐëҪŪÇåÎúverified_chainµÄ¶Ñ½á¹¹¡£


            #typedef STACK_OF(type) struct stack_st_##type

            typedef struct stack_st {    
            int num;    
            char **data;    
            int sorted;    
            int num_alloc;    
            int (*comp)(const void *, const void *);
            } _STACK; /* Use STACK_OF(...) instead */

              STACK_OF(X509) *verified_chain;


              ÕâÀï £¬ÎÒÃÇÖ÷Òª¹Ø×¢num³ÉÔ±±äÁ¿ºÍÖ¸ÏòÊý×éµÄÖ¸Õëdata£¨LibreSSLʹÓÃÁËLinuxÆ«ÔçÆڵıàÂëÆø¸Å £¬Ê¹ÓÃchar **ÌåÏÖ£©¡£


              ¿Í»§¶Ë»ñÈ¡µ½·þÎñÆ÷¶ËµÄÖ¤Êéºó £¬verified_chainÔÚ¶ÑÖеĽṹÈçÏÂͼ£º


              ͼƬ2.png


              ¿ÉÒÔ¿´µ½ £¬numµÄֵΪ3 £¬ÌåÏÖÖ¤ÊéÁ´ÎªÈý¼¶Ö¤ÊéÁ´£¨ÈÔÒ԰ٶȵÄÖ¤ÊéΪÀý £¬Èý¼¶»®·ÖΪGlobalSign¡¢GlobalSign BEºÍ°Ù¶È¸÷×ÔµÄÖ¤Ê飩 £¬Òò´ËdataÊý×éÖ¸Ïò3¸öx509_stÖ¤Êé½á¹¹Ìå £¬ÉÏͼʾÀýÖдòÓ¡³öÁË×îµ×²ãµÄ¸ùÖ¤ÊéµÄ²¿·Ö³ÉÔ±±äÁ¿¡£


              2.2 sk_X509_pop_freeºê


              ÎÒÃÇ¿´Ò»ÏÂ×îÖÕÊÍ·Ås->internal->verified_chainµÄsk_X509_pop_freeºê¡£


                #define sk_X509_pop_free(st, free_func) SKM_sk_pop_free(X509, (st), (free_func))
                #define SKM_sk_pop_free(type, st, free_func) \    
                sk_pop_free(CHECKED_STACK_OF(type, st), CHECKED_SK_FREE_FUNC(type, free_func))
                void
                sk_pop_free(_STACK *st, void (*func)(void *))
                {    
                int i;
                if (st == NULL)  /////// [*]        
                return;    
                for (i = 0; i < st->num; i++)        
                if (st->data[i] != NULL)            
                func(st->data[i]);      /////// [1]    
                sk_free(st);         /////// [2]
                }


                ¿ÉÒÔ¿´µ½ £¬¸Ãºê×îÖÕŲÓÃsk_pop_freeº¯Êý¡£Ôڸú¯ÊýÄÚ £¬ÏÈÅжÏstÊÇ·ñ¼´ÊÇNULL£¨[*]´¦£© £¬Èô¼´ÊÇÔòÖ±½Ó·µ»Ø £¬ËµÃ÷ÒѾ­²»ÔÙÐèÒªÊÍ·ÅÁË £»Èôst²»¼´ÊÇNULL £¬ÔòʹÓÃforÑ­»·¹²Ñ­»·stack_st½á¹¹ÌåÀïµÄnum´Î £¬²¢Ã¿´ÎʹÓú¯ÊýµÄµÚ¶þ¸ö²ÎÊý£¨ÎªÒ»º¯ÊýÖ¸Õ룩Öð¸öÊÍ·ÅÊý×éÄڵĸ÷¸ö³ÉÔ±£¨[1]´¦£© £¬¹ØÓÚsk_X509_pop_free(s->internal->verified_chain, X509_free)¶øÑÔ £¬func¼´ÎªX509_freeº¯Êý £»×îºóÊÍ·Åst¡£


                ¼ò¶øÑÔÖ® £¬¹ØÓÚÎó²î¶øÑÔ £¬sk_pop_freeµÄµÚÒ»¸ö²ÎÊýst(¼´s->internal->verified_chain)ÉÏ´ÎÊͷźóûÓи³ÖµÎªNULL £¬µÚ¶þ´Îsk_pop_freeʱÓÉÓÚst²»¼´ÊÇNULL £¬´Ó¶øµ¼ÖÂÔٴα»sk_freeº¯ÊýÊÍ·Å¡£ 


                Èý¡¢Îó²îÑéÖ¤


                ƾ֤Îó²îÐÎòºÍ²¹¶¡ÐÅÏ¢ £¬ÎÒÃÇÖªµÀÐèÒªÓÐʱ»úÖ´ÐÐsk_X509_pop_free(s->internal->verified_chain, X509_free)Á½´Î¡£


                ÕâÉæ¼°µ½SSL½á¹¹ÌåµÄÖØÓà £¬ÎÒÃÇÏÈ¿´Ò»¸ö×î¼òÆÓµÄʹÓÃSSL½á¹¹ÌåµÄα´úÂë¡£


                3.1 SSL_newºÍSSL_freeµÄÅä¶ÔʹÓÃ


                Ê×ÏÈΪSSL½á¹¹Ìå±äÁ¿ÉêÇë³ö¶Ñ¿Õ¼ä £¬È»ºóʹÓÃSSL_connectº¯ÊýÍê³ÉSSLÅþÁ¬µÄÎÕÊÖ £¬Õâʱ»á»ñµÃ·þÎñÆ÷¶ËÏìÓ¦µÄÖ¤Êé £¬×îºóʹÓÃSSL_freeº¯ÊýÊͷŶѿռä £¬Î±´úÂëÈçÏ£º


                  SSL* ssl = SSL_new(sslCtx);

                  // ...

                  SSL_connect(ssl);

                  // ...

                  SSL_free(ssl);


                  3.2 SSL_clearº¯Êý


                  ƾ֤Îó²îÐÎò £¬Éó²éOpenSSL¹Ù·½¶ÔSSL_clearº¯ÊýµÄÚ¹ÊÍ £¬¿´¿´ÄÜ»ñÈ¡µ½ÄÄЩÐÅÏ¢ÌáÐÑ¡£


                  ͼƬ3.png


                  Ò²¾ÍÊÇ˵ £¬SSL_clearÌṩÖØÖÃSSL¹¤¾ßµÄ¹¦Ð§ £¬ÒÔΪÏ´ÎÐÂÅþÁ¬×ö×¼±¸ £¬ÕâÑù×èÖ¹ÄÚ²¿×ÊÔ´µÄÉêÇëºÍ³õʼ»¯ £¬ÓÐÀûÓÚÌá¸ß×ÊÔ´µÄʹÓÃЧÂÊ¡£²¢ÇÒÌáµ½ÁËSSL_shutdownº¯ÊýµÄʹÓá£ÏÂÃæΪSSL_clearº¯ÊýµÄ´úÂ룺


                    int

                    SSL_clear(SSL *s)

                    {    
                    if (s->method == NULL) {        
                    SSLerror(s, SSL_R_NO_METHOD_SPECIFIED);        
                    return (0);    
                    }
                      
                     /// ...ÂÔ...
                        
                     s->internal->first_packet = 0;
                     
                     /*    
                     * Check to see if we were changed into a different method, if     
                     * so, revert back if we are not doing session-id reuse.     
                     */    
                     if (!s->internal->in_handshake && (s->session == NULL) &&        
                     (s->method != s->ctx->method)) { /////// [1]        
                     s->method->ssl_free(s);       /////// [2]        
                     s->method = s->ctx->method;        
                     if (!s->method->ssl_new(s))    /////// [3]            
                     return (0);    
                     } else        
                     s->method->ssl_clear(s);
                     return (1);
                     }


                    ÔÚÖØÖÃSSL½á¹¹Ì幤¾ßʱ £¬ÈôÊÇÎÒÃÇ´´Á¢Ìõ¼þÖª×ã[1]´¦ £¬Äܹ»Ê¹³ÌÐò´úÂëÔËÐе½[3]´¦ £¬´Ó¶øÓÐʱ»úʹµÃsk_X509_pop_free(s->internal->verified_chain, X509_free)Ö´ÐÐÁ½´Î¡£×¢Öص½ £¬ÔÚ[2]´¦ÒѾ­ÓÐÒ»´Î¶Ôssl_freeÖ¸ÏòµÄº¯ÊýµÄŲÓà £¬ÒÔ¼°[3]´¦µÄssl_newÖ¸ÏòµÄº¯ÊýµÄÒ»´ÎŲÓá£


                    3.3 ssl3_newº¯Êý


                    ÏÈ¿´¿´ssl3_newº¯Êý£º


                      int
                      ssl3_new(SSL *s)
                      {    
                      if ((s->s3 = calloc(1, sizeof(*s->s3))) == NULL)        
                      return (0);
                      s->method->ssl_clear(s);    /////// [1]
                      return (1);
                      }


                      ×¢ÖØ[1]´¦¡£


                      3.4 ssl3_clearº¯Êý


                      ÉÐÓÐ £¬ssl3_clearº¯ÊýµÄÔ´´úÂ룺


                        void
                        ssl3_clear(SSL *s)
                        {    
                        unsigned char *rp, *wp;    
                        size_t rlen, wlen;
                        tls1_cleanup_key_block(s);    
                        sk_X509_NAME_pop_free(s->s3->hs.tls12.ca_names, X509_NAME_free);    
                        sk_X509_pop_free(s->internal->verified_chain, X509_free);   ///////// [1]    
                        s->internal->verified_chain = NULL;
                        freezero(s->s3->hs.sigalgs, s->s3->hs.sigalgs_len);    
                        s->s3->hs.sigalgs = NULL;    
                        s->s3->hs.sigalgs_len = 0;
                         
                         /// ...ÂÔ...
                         
                        memset(s->s3, 0, sizeof(*s->s3));
                        s->s3->rbuf.buf = rp;

                        /// ...ÂÔ...

                        s->s3->hs.state = SSL_ST_BEFORE|((s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT);

                        }


                        ÊÓ²ì[1]´¦µÄ´úÂë¡£


                        3.5 ´¥·¢Àú³Ì


                        ÈôÊÇÎÒÃÇÄÜÏȺ󴥷¢ssl3_freeºÍssl3_new £¬ÄÇôҲ¾ÍÄÜ´¥·¢¸ÃÎó²î¡£


                        • ½¨ÉèSSLÐèÒªµÄÉÏÏÂÎÄÇéÐÎ £»
                        • ŲÓÃSSL_connectº¯Êý £¬Ê¹µÃSSLÅþÁ¬·µ»ØÖ¤ÊéÁ´;
                        • È»ºóʹÓÃSSL_shutdownº¯Êý¹Ø±Õ¸ÃSSLÅþÁ¬;
                        • ½ÓÏÂÀ´Å²ÓÃTLSv1_methodº¯Êý £¬ÒÔ·µ»ØÒ»¸öеÄSSL_METHODÖ¸Õ루ºÍµÚÒ»´ÎʹÓÃSSL_CTX_newº¯Êý½¨ÉèSSL_CTX±äÁ¿Ê±´«ÈëµÄ²ÎÊý²î±ð£©;
                        • ŲÓÃSSL_set_ssl_methodº¯Êý £¬ÆäµÚ¶þ¸ö²ÎÊýΪÉÏÒ»²½·µ»ØµÄÐÂSSL_METHODÖ¸Õë £»
                        • Õý³£ÊÍ·ÅÏà¹Ø×ÊÔ´¡£


                        ʹÓÃTLSv1_methodº¯ÊýµÄÔµ¹ÊÔ­ÓÉ


                        ÎÒÃÇ¿´Ò»ÏÂTLSv1_methodº¯ÊýµÄÏà¹Ø´úÂ룺


                          // ssl_methods.c

                          const SSL_METHOD *

                          TLSv1_method(void){    

                          return (&TLSv1_method_data);

                          }

                          // ...

                          static const SSL_METHOD TLSv1_method_data = {    

                          .dtls = 0,    
                          .server = 1,    
                          .version = TLS1_VERSION,    
                          .min_tls_version = TLS1_VERSION,    
                          .max_tls_version = TLS1_VERSION,    
                          .ssl_new = tls1_new,    
                          .ssl_clear = tls1_clear,    
                          .ssl_free = tls1_free,  /////// [1]    
                          .ssl_accept = ssl3_accept,    
                          .ssl_connect = ssl3_connect,    
                          .ssl_shutdown = ssl3_shutdown,    

                          /// ...ÂÔ...   

                          .enc_flags = TLSV1_ENC_FLAGS,

                          };


                          Äܹ»¿´µ½ £¬´Ëʱ £¬ssl_freeº¯Êý×ÅʵָÏòÁËtls1_freeº¯Êý £¬¶øtls1_freeº¯ÊýÄÚ²¿Å²ÓÃÁËssl3_free¡£


                            // t1_lib.c

                            void

                            tls1_free(SSL *s)
                            {
                            if (s == NULL)        
                            return;

                            free(s->internal->tlsext_session_ticket);    
                            ssl3_free(s);   /////// [1]

                            }


                            ÎÒÃÇÔÙÀ´¿´Ò»ÏÂSSL_set_ssl_methodº¯Êý£º


                              int

                              SSL_set_ssl_method(SSL *s, const SSL_METHOD *method)

                              {    

                              int (*handshake_func)(SSL *) = NULL;    
                              int ret = 1;
                              if (s->method == method)        
                              return (ret);
                              if (s->internal->handshake_func == s->method->ssl_connect)        
                              handshake_func = method->ssl_connect;    
                              else if (s->internal->handshake_func == s->method->ssl_accept)        
                              handshake_func = method->ssl_accept;
                              if (s->method->version == method->version) { //// [1]        
                              s->method = method;    
                              } else {        
                              s->method->ssl_free(s);  //// [2]        
                              s->method = method;   //// [3]        
                              ret = s->method->ssl_new(s);  //// [4]    
                              }    
                              s->internal->handshake_func = handshake_func;
                              return (ret);
                              }


                              ÎÒÃÇʹÓÃTLSv1_methodº¯Êý·µ»ØµÄmethod->version¾ÓÐIJ»¼´ÊÇs->method->version £¬´Ó¶øµ¼ÖÂ[2]µÄÖ´ÐÐ £¬¶ø´ËʱµÄs->method->ssl_freeµÄֵΪtls1_free £¬ÇÒÔËÐе½[4]´¦Ê± £¬s->method->ssl_newµÄֵΪtls1_new£º


                              ͼƬ4.png


                              ƾ֤tls1_freeº¯ÊýµÄ´úÂë £¬Ëü»áŲÓÃssl3_freeÒ»´Î £¬¶øssl3_freeÄÚ²¿»áÖ´ÐÐÒ»´Îsk_X509_pop_free(s->internal->verified_chain, X509_free) £¬µ¼ÖÂs->internal->verified_chain±»ÊÍ·Å¡£


                              µ±³ÌÐòÖ´Ðе½SSL_set_ssl_methodÄÚµÄ[4]´¦Ê± £¬»áŲÓÃtls1_newº¯Êý¡£


                              ÎÒÃÇÔÙÀ´¿´Ò»ÏÂtls1_newµÄ´úÂ룺


                                int
                                tls1_new(SSL *s)
                                {    
                                if (!ssl3_new(s))        ///// [1]        
                                return (0);    
                                s->method->ssl_clear(s);    
                                return (1);
                                }


                                ¿ÉÒÔ¿´µ½ £¬ÎÞÂÛÔõÑù £¬[1]´¦µÄssl3_newº¯Êý¶¼»áÖ´ÐÐ £¬¶øssl3_newÄÚ²¿»áŲÓÃs->method->ssl_clear £¬´ËʱµÄs->method->ssl_clearÖ¸Ïòtls1_clearº¯Êý £¬tls1_clearº¯ÊýµÄʵÏÖÈçÏ£º


                                  void
                                  tls1_clear(SSL *s)
                                  {    
                                  ssl3_clear(s);  /////// [1]    
                                  s->version = s->method->version;
                                  }


                                  ×¢Öص½tls1_clearÄÚ²¿»áŲÓÃssl3_clear £¬¶øssl3_clearÄÚ²¿Ò»¶¨»áÖ´ÐÐsk_X509_pop_free(s->internal->verified_chain, X509_free)Óï¾ä £¬´Ó¶øµ¼ÖÂs->internal->verified_chain±»ÔÙ´ÎÊÍ·Å¡£ÔÚµ÷ÊÔÆ÷ÖеÄÍß½âÈçÏÂͼ£º


                                  ͼƬ5.png



                                  ËÄ¡¢Îó²îÐÞ¸´


                                  4.1 ¹ØÓÚ3.6.3


                                  ¹ØÓÚ3.6.3°æ £¬¹Ù·½Ö±½ÓÔÚssl3_freeº¯ÊýÀï°Ñs->internal->verified_chain¸³ÖµÎªNULL£º


                                    // ssl3_free(SSL *s)    
                                    sk_X509_pop_free(s->internal->verified_chain, X509_free); /////// [1]    
                                    s->internal->verified_chain = NULL;    /////// [2]


                                    4.2 ×îа汾3.9.2


                                    ÔÚÆÊÎö´ò¹ý²¹¶¡ºóµÄ½Ïа汾ʱ £¬»á·¢Ã÷ssl3_freeº¯ÊýûÓÐÁË3.6.3°æʱ°Ñverified_chain¸³ÖµÎªNULLµÄÓï¾ä £¬ºÃ±È×îаæ3.9.2µÄ£º


                                      void
                                      ssl3_free(SSL *s)
                                      {    
                                      if (s == NULL)        
                                      return;
                                      tls1_cleanup_key_block(s);    
                                      ssl3_release_read_buffer(s);    
                                      ssl3_release_write_buffer(s);
                                       
                                       /// ...ÂÔ...
                                       
                                      sk_X509_pop_free(s->s3->hs.peer_certs, X509_free);    
                                      sk_X509_pop_free(s->s3->hs.peer_certs_no_leaf, X509_free);    
                                      sk_X509_pop_free(s->s3->hs.verified_chain, X509_free); /////// [1]   
                                      tls_key_share_free(s->s3->hs.key_share);

                                      /// ...ÂÔ...

                                      freezero(s->s3->peer_quic_transport_params,        
                                      s->s3->peer_quic_transport_params_len);
                                      freezero(s->s3, sizeof(*s->s3));   /////// [2]
                                      s->s3 = NULL;
                                      }


                                      ͬʱ £¬×¢ÖØ[2]´¦µÄfreezeroº¯Êý¡£ 


                                      Ôµ¹ÊÔ­ÓÉÔÚÓڽṹÌå½ç˵µÄת±ä £¬´Ósk_X509_pop_freeºêµÄµÚÒ»²ÎÊý¿ÉÒÔ¿´³öһЩüĿ£º


                                        sk_X509_pop_free(s->s3->hs.verified_chain, X509_free);


                                        ¸Ã°æ±¾¼¸¸öÏà¹Ø½á¹¹ÌåµÄ½ç˵ÈçÏ£º


                                          // 3.9.2
                                          struct ssl_st 
                                          {    
                                          /* protocol version     
                                          * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)     
                                          */ 
                                          int version;
                                          const SSL_METHOD *method; 
                                           
                                           /// ...ÂÔ... 

                                          int server; /* are we the server side? - mostly used by SSL_clear*/

                                          struct ssl3_state_st *s3; /* SSLv3 variables */    /////// [1]    
                                          struct dtls1_state_st *d1; /* DTLSv1 variables */    

                                          /// ...ÂÔ...

                                          };
                                          typedef struct ssl3_state_st 
                                          {   
                                          long flags;
                                          unsigned char server_random[SSL3_RANDOM_SIZE];

                                          /// ...ÂÔ... 

                                          int in_read_app_data;
                                          SSL_HANDSHAKE hs;  /////// [2]    

                                          /// ...ÂÔ...

                                          } SSL3_STATE;


                                          ÒÔ¼°ssl_handshake_st£º


                                            typedef struct ssl_handshake_st 
                                            {    
                                            /*     
                                            * Minimum and maximum versions supported for this handshake. These are     
                                            * initialised at the start of a handshake based on the method in use     
                                            * and the current protocol version configuration.     
                                            */    
                                            uint16_t our_min_tls_version;    

                                            /// ...ÂÔ...

                                            /* Certificate chain resulting from X.509 verification. */    
                                            STACK_OF(X509) *verified_chain;     /////// [1]
                                            SSL_HANDSHAKE_TLS12 tls12;    
                                            SSL_HANDSHAKE_TLS13 tls13;
                                            }SSL_HANDSHAKE;


                                            ¿ÉÒÔ¿´µ½ÔÚ[2]´¦µÄhsÊÇÒ»¸öSSL_HANDSHAKEÀàÐ͵ĽṹÌå³ÉÔ±±äÁ¿¡£ssl3_freeº¯ÊýÀïµÄfreezeroº¯Êý

                                            »á°Ñs->s3µÄ¶Ñ¿Õ¼äµÄÄÚÈÝËùÓÐÉèÖÃΪÁã £¬Éó²éfreezeroº¯Êý¼°ÆäÄÚ²¿µÄexplicit_bzeroµÄ´úÂë¼´¿ÉµÃÖª¡£


                                            ? freezeroº¯ÊýºÍexplicit_bzeroº¯Êý


                                              // freezero.c
                                              void
                                              freezero(void *ptr, size_t sz)
                                              {    
                                              /* This is legal. */    
                                              if (ptr == NULL)        
                                              return;
                                              explicit_bzero(ptr, sz);    
                                              free(ptr);
                                              }

                                              // explicit_bzero.c
                                              void
                                              explicit_bzero(void *buf, size_t len)
                                              {    
                                              memset(buf, 0, len);  /////// [1]    
                                              __explicit_bzero_hook(buf, len);
                                              }


                                              ÕâÑù £¬[1]´¦µÄmemsetº¯Êý»áµ¼ÖÂs->s3->hs.verified_chain±»¸³ÖµÎªNULL £¬´Ó¶øÔÚsk_pop_freeº¯Êý[1]´¦Ê±¼´·µ»Ø £¬½ø¶ø×èÖ¹ÁËÎó²îµÄ±¬·¢¡£



                                              ²Î¿¼Á´½Ó£º

                                              [1]https://ftp.openbsd.org/pub/OpenBSD/patches/7.2/common/026_ssl.patch.sig

                                              [2]https://www.cvedetails.com/cve/CVE-2023-35784/