Changeset 3643

Show
Ignore:
Timestamp:
05/06/08 17:35:11
Author:
jdapena
Message:

* libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c:

        • Protect PR_Reads and writes to avoid calls to PR_Close before

one of them. Should avoid some crashes and bad memory
accesses.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • releases/modest/diablo/ChangeLog

    r3638 r3643  
     12008-05-06  Jose Dapena Paz  <jdapena@igalia.com> 
     2 
     3        * libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c: 
     4        Protect PR_Reads and writes to avoid calls to PR_Close before one of 
     5        them. Should avoid some crashes and bad memory accesses. 
     6 
    172008-04-30  Sergio Villar Senin  <svillar@igalia.com> 
    28 
  • releases/modest/diablo/libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c

    r3592 r3643  
    8787static int stream_gettimeout (CamelTcpStream *stream); 
    8888 
     89static gboolean begin_read (CamelTcpStreamSSL *stream); 
     90static void end_read (CamelTcpStreamSSL *stream); 
     91static gint ssl_close (CamelTcpStreamSSL *stream); 
     92 
    8993 
    9094struct _CamelTcpStreamSSLPrivate { 
     
    97101        gboolean accepted; 
    98102        CamelService *service; 
     103        guint reads; 
     104        GMutex *reads_lock; 
     105        gboolean scheduled_close; 
    99106}; 
    100107 
     108/* 
     109 * This method is used for making sure we don't close the ssl socket 
     110 * before all the scheduled reads are finished. It also rejects read 
     111 * if we have a pending close. 
     112 * 
     113 * The return value is FALSE when we didn't accept the request to begin 
     114 * a read operation. In this case we shouldn't call end_read. 
     115 */ 
     116static inline gboolean 
     117begin_read (CamelTcpStreamSSL *stream) 
     118{ 
     119        gboolean retval = TRUE; 
     120 
     121        g_mutex_lock (stream->priv->reads_lock); 
     122        if (stream->priv->scheduled_close) { 
     123                retval = FALSE; 
     124        } else { 
     125                stream->priv->reads ++; 
     126                camel_object_ref (stream); 
     127        } 
     128        g_mutex_unlock (stream->priv->reads_lock); 
     129        return retval; 
     130} 
     131 
     132/* 
     133 * This ends a read request started succesfully in begin_read. Then, if that 
     134 * method returns FALSE, we shouldn't call this. 
     135 * 
     136 * It checks if there's a close call delayed because of reads pending. It it's 
     137 * so, then it closes the socket and sets the sock reference to NULL. 
     138 */ 
     139static inline void 
     140end_read (CamelTcpStreamSSL *stream) 
     141{ 
     142        gboolean close; 
     143        g_mutex_lock (stream->priv->reads_lock); 
     144        stream->priv->reads --; 
     145        close =  ((stream->priv->reads == 0) && (stream->priv->scheduled_close)); 
     146        g_mutex_unlock (stream->priv->reads_lock); 
     147        if (close) { 
     148                PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH); 
     149                PR_Close (stream->priv->sockfd); 
     150                stream->priv->sockfd = NULL; 
     151        } 
     152        camel_object_unref (stream); 
     153} 
     154 
     155 
     156/* 
     157 * Closes the stream ssl socket, in case there are no reads pending, or sets 
     158 * this as requested. 
     159 */ 
     160static gint 
     161ssl_close (CamelTcpStreamSSL *stream) 
     162{ 
     163        gboolean close; 
     164        g_mutex_lock (stream->priv->reads_lock); 
     165        close = ((stream->priv->reads == 0) && (stream->priv->sockfd != NULL)); 
     166        if (stream->priv->sockfd != NULL) 
     167                stream->priv->scheduled_close = TRUE; 
     168        g_mutex_unlock (stream->priv->reads_lock); 
     169        if (close) { 
     170                PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH); 
     171                if (PR_Close (stream->priv->sockfd) == PR_FAILURE) { 
     172                        stream->priv->sockfd = NULL; 
     173                        return -1; 
     174                } 
     175                stream->priv->sockfd = NULL; 
     176        } 
     177        return 0; 
     178} 
    101179 
    102180static void  
     
    145223 
    146224        stream->priv = g_new0 (struct _CamelTcpStreamSSLPrivate, 1); 
     225        stream->priv->reads_lock = g_mutex_new (); 
    147226} 
    148227 
     
    153232 
    154233        if (stream->priv->sockfd != NULL) { 
    155                 PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH); 
    156                 PR_Close (stream->priv->sockfd); 
     234                ssl_close (stream); 
    157235        } 
    158236 
    159237        if (stream->priv->session) 
    160238                camel_object_unref(stream->priv->session); 
     239 
     240        g_mutex_free (stream->priv->reads_lock); 
    161241 
    162242        g_free (stream->priv->expected_host); 
     
    221301                NSS_InitReadWrite (str); 
    222302                has_init = TRUE; 
     303                g_free (str); 
    223304        } 
    224305 
     
    362443                } 
    363444 
     445                g_mutex_lock (ssl->priv->reads_lock); 
    364446                ssl->priv->sockfd = fd; 
     447                ssl->priv->scheduled_close = FALSE; 
     448                ssl->priv->reads = 0; 
     449                g_mutex_unlock (ssl->priv->reads_lock); 
    365450 
    366451                if (SSL_ResetHandshake (fd, FALSE) == SECFailure) { 
     
    425510                         do { 
    426511                                nread = -1; 
    427                                 if (PR_Available (tcp_stream_ssl->priv->sockfd) != 0) 
    428                                         nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
     512                                if (begin_read (tcp_stream_ssl)) { 
     513                                        if (PR_Available (tcp_stream_ssl->priv->sockfd) != 0) 
     514                                                nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
     515                                        end_read (tcp_stream_ssl); 
     516                                } 
    429517                                if (nread == -1) 
    430518                                        set_errno (PR_GetError ()); 
     
    491579                        } else { 
    492580                                do { 
    493                                         nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
    494                                         if (nread == -1) 
    495                                                 set_errno (PR_GetError ()); 
     581                                        nread = -1; 
     582                                        if (begin_read (tcp_stream_ssl)) { 
     583                                                nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
     584                                                if (nread == -1) 
     585                                                        set_errno (PR_GetError ()); 
     586                                                end_read (tcp_stream_ssl); 
     587                                        } 
    496588                                } while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR); 
    497589                        } 
     
    548640                        } else { 
    549641                                do { 
    550                                         nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
    551                                         if (nread == -1) 
    552                                                 set_errno (PR_GetError ()); 
     642                                        nread = -1; 
     643                                        if (begin_read (tcp_stream_ssl)) { 
     644                                                nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n); 
     645                                                if (nread == -1) 
     646                                                        set_errno (PR_GetError ()); 
     647                                                end_read (tcp_stream_ssl); 
     648                                        } 
    553649                                } while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR); 
    554650                        } 
     
    619715                        } else { 
    620716                                do { 
    621                                         w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written); 
    622                                         if (w == -1) 
    623                                                 set_errno (PR_GetError ()); 
     717                                        w = -1; 
     718                                        if (begin_read (tcp_stream_ssl)) { 
     719                                                w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written); 
     720                                                if (w == -1) 
     721                                                        set_errno (PR_GetError ()); 
     722                                                end_read (tcp_stream_ssl); 
     723                                        }  
    624724                                } while (w == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR); 
    625725 
     
    681781                        } else { 
    682782                                do { 
    683                                         w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written); 
    684                                         if (w == -1) 
    685                                                 set_errno (PR_GetError ()); 
     783                                        w = -1; 
     784                                        if (begin_read (tcp_stream_ssl)) { 
     785                                                w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written); 
     786                                                if (w == -1) 
     787                                                        set_errno (PR_GetError ()); 
     788                                                end_read (tcp_stream_ssl); 
     789                                        } 
    686790                                } while (w == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR); 
    687791 
     
    724828        } 
    725829 
    726         PR_Shutdown (((CamelTcpStreamSSL *)stream)->priv->sockfd, PR_SHUTDOWN_BOTH); 
    727         if (PR_Close (((CamelTcpStreamSSL *)stream)->priv->sockfd) == PR_FAILURE) 
    728                 return -1; 
     830        ssl_close ((CamelTcpStreamSSL *) stream); 
    729831 
    730832        ((CamelTcpStreamSSL *)stream)->priv->sockfd = NULL; 
     
    13891491                        PR_Shutdown (fd, PR_SHUTDOWN_BOTH); 
    13901492                        PR_Close (fd); 
    1391                         ssl->priv->sockfd = NULL; 
    13921493                        errno = errnosave; 
    13931494 
     
    13981499        } 
    13991500 
     1501        g_mutex_lock (ssl->priv->reads_lock); 
     1502        ssl->priv->reads = 0; 
     1503        ssl->priv->scheduled_close = FALSE; 
    14001504        ssl->priv->sockfd = fd; 
     1505        g_mutex_unlock (ssl->priv->reads_lock); 
    14011506 
    14021507        return 0;