[前][次][番号順一覧][スレッド一覧]

ruby-changes:43026

From: rhe <ko1@a...>
Date: Sat, 21 May 2016 16:25:06 +0900 (JST)
Subject: [ruby-changes:43026] rhe:r55100 (trunk): openssl: fix possible SEGV on race between SSLSocket#stop and #connect

rhe	2016-05-21 16:25:00 +0900 (Sat, 21 May 2016)

  New Revision: 55100

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55100

  Log:
    openssl: fix possible SEGV on race between SSLSocket#stop and #connect
    
    * ext/openssl/ossl_ssl.c (ossl_ssl_stop): Don't free the SSL struct
      here. Since some methods such as SSLSocket#connect releases GVL,
      there is a chance of use after free if we free the SSL from another
      thread. SSLSocket#stop was documented as "prepares it for another
      connection" so this is a slightly incompatible change. However when
      this sentence was added (r30090, Add toplevel documentation for
      OpenSSL, 2010-12-06), it didn't actually. The current behavior is
      from r40304 (Correct shutdown behavior w.r.t GC., 2013-04-15).
      [ruby-core:74978] [Bug #12292]
    
    * ext/openssl/lib/openssl/ssl.rb (sysclose): Update doc.
    
    * test/openssl/test_ssl.rb: Test this.

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/lib/openssl/ssl.rb
    trunk/ext/openssl/ossl_ssl.c
    trunk/test/openssl/test_ssl.rb
Index: test/openssl/test_ssl.rb
===================================================================
--- test/openssl/test_ssl.rb	(revision 55099)
+++ test/openssl/test_ssl.rb	(revision 55100)
@@ -1169,6 +1169,28 @@ end https://github.com/ruby/ruby/blob/trunk/test/openssl/test_ssl.rb#L1169
     }
   end
 
+  def test_close_and_socket_close_while_connecting
+    # test it doesn't cause a segmentation fault
+    ctx = OpenSSL::SSL::SSLContext.new
+    ctx.ciphers = "aNULL"
+
+    sock1, sock2 = socketpair
+    ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx)
+    ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx)
+
+    t = Thread.new { ssl1.connect }
+    ssl2.accept
+
+    ssl1.close
+    sock1.close
+    t.value rescue nil
+  ensure
+    ssl1.close if ssl1
+    ssl2.close if ssl2
+    sock1.close if sock1
+    sock2.close if sock2
+  end
+
   def test_get_ephemeral_key
     return unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key)
     pkey = OpenSSL::PKey
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55099)
+++ ChangeLog	(revision 55100)
@@ -1,3 +1,19 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat May 21 16:16:03 2016  Kazuki Yamaguchi  <k@r...>
+
+	* ext/openssl/ossl_ssl.c (ossl_ssl_stop): Don't free the SSL struct
+	  here. Since some methods such as SSLSocket#connect releases GVL,
+	  there is a chance of use after free if we free the SSL from another
+	  thread. SSLSocket#stop was documented as "prepares it for another
+	  connection" so this is a slightly incompatible change. However when
+	  this sentence was added (r30090, Add toplevel documentation for
+	  OpenSSL, 2010-12-06), it didn't actually. The current behavior is
+	  from r40304 (Correct shutdown behavior w.r.t GC., 2013-04-15).
+	  [ruby-core:74978] [Bug #12292]
+
+	* ext/openssl/lib/openssl/ssl.rb (sysclose): Update doc.
+
+	* test/openssl/test_ssl.rb: Test this.
+
 Sat May 21 14:41:14 2016  Kazuki Yamaguchi  <k@r...>
 
 	* ext/openssl/ossl.c: [DOC] Fix SSL client example. The variable name
Index: ext/openssl/ossl_ssl.c
===================================================================
--- ext/openssl/ossl_ssl.c	(revision 55099)
+++ ext/openssl/ossl_ssl.c	(revision 55100)
@@ -1601,23 +1601,17 @@ ossl_ssl_write_nonblock(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1601
  * call-seq:
  *    ssl.stop => nil
  *
- * Stops the SSL connection and prepares it for another connection.
+ * Sends "close notify" to the peer and tries to shut down the SSL connection
+ * gracefully.
  */
 static VALUE
 ossl_ssl_stop(VALUE self)
 {
     SSL *ssl;
 
-    /* ossl_ssl_data_get_struct() is not usable here because it may return
-     * from this function; */
+    ossl_ssl_data_get_struct(self, ssl);
 
-    GetSSL(self, ssl);
-
-    if (ssl) {
-	ossl_ssl_shutdown(ssl);
-	SSL_free(ssl);
-    }
-    DATA_PTR(self) = NULL;
+    ossl_ssl_shutdown(ssl);
 
     return Qnil;
 }
Index: ext/openssl/lib/openssl/ssl.rb
===================================================================
--- ext/openssl/lib/openssl/ssl.rb	(revision 55099)
+++ ext/openssl/lib/openssl/ssl.rb	(revision 55100)
@@ -290,7 +290,10 @@ module OpenSSL https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl/ssl.rb#L290
       # call-seq:
       #    ssl.sysclose => nil
       #
-      # Shuts down the SSL connection and prepares it for another connection.
+      # Sends "close notify" to the peer and tries to shut down the SSL
+      # connection gracefully.
+      #
+      # If sync_close is set to +true+, the underlying IO is also closed.
       def sysclose
         return if closed?
         stop

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]