[DRE-commits] [ruby-eventmachine] 01/05: Fix remotely triggerable crash due to FD handling

Balint Reczey rbalint at moszumanska.debian.org
Mon Jun 27 22:03:44 UTC 2016


This is an automated email from the git hooks/post-receive script.

rbalint pushed a commit to branch wheezy-security
in repository ruby-eventmachine.

commit d14d3fb6570b0089c5bcfaabcbc3ee1ceeec2e05
Author: Balint Reczey <balint at balintreczey.hu>
Date:   Mon Jun 27 20:34:08 2016 +0200

    Fix remotely triggerable crash due to FD handling
---
 ...e-ruby-select-api-with-expandable-fd-sets.patch | 168 ++++++++++++++++++++
 ...d-stubs-with-warnings-for-1.8.7-and-1.9.0.patch |  45 ++++++
 ...-comment-about-where-the-macros-came-from.patch |  26 ++++
 ...rt-em_test_helper.rb-for-test_many_fds.rb.patch | 173 +++++++++++++++++++++
 debian/patches/series                              |   4 +
 5 files changed, 416 insertions(+)

diff --git a/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch b/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch
new file mode 100644
index 0000000..9a94a64
--- /dev/null
+++ b/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch
@@ -0,0 +1,168 @@
+From bd881bb291b30bf9de71d6ab45caa69f25707577 Mon Sep 17 00:00:00 2001
+From: Patrick Reynolds <patrick.reynolds at github.com>
+Date: Tue, 11 Mar 2014 16:01:25 -0500
+Subject: [PATCH 2/4] use ruby select api with expandable fd sets
+
+Conflicts:
+	ext/em.cpp
+	ext/em.h
+---
+ ext/em.cpp             | 30 +++++++++++++++---------------
+ ext/em.h               | 10 +++++-----
+ tests/test_many_fds.rb | 22 ++++++++++++++++++++++
+ 3 files changed, 42 insertions(+), 20 deletions(-)
+ create mode 100644 tests/test_many_fds.rb
+
+diff --git a/ext/em.cpp b/ext/em.cpp
+index a53699b..d51e716 100644
+--- a/ext/em.cpp
++++ b/ext/em.cpp
+@@ -707,9 +707,9 @@ SelectData_t::SelectData_t
+ SelectData_t::SelectData_t()
+ {
+ 	maxsocket = 0;
+-	FD_ZERO (&fdreads);
+-	FD_ZERO (&fdwrites);
+-	FD_ZERO (&fderrors);
++	rb_fd_init (&fdreads);
++	rb_fd_init (&fdwrites);
++	rb_fd_init (&fderrors);
+ }
+ 
+ 
+@@ -722,7 +722,7 @@ _SelectDataSelect
+ static VALUE _SelectDataSelect (void *v)
+ {
+ 	SelectData_t *sd = (SelectData_t*)v;
+-	sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
++	sd->nSockets = rb_fd_select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
+ 	return Qnil;
+ }
+ #endif
+@@ -783,9 +783,9 @@ bool EventMachine_t::_RunSelectOnce()
+ 
+ 	SelectData_t SelectData;
+ 	/*
+-	fd_set fdreads, fdwrites;
+-	FD_ZERO (&fdreads);
+-	FD_ZERO (&fdwrites);
++	rb_fdset_t fdreads, fdwrites;
++	rb_fd_init (&fdreads);
++	rb_fd_init (&fdwrites);
+ 
+ 	int maxsocket = 0;
+ 	*/
+@@ -795,7 +795,7 @@ bool EventMachine_t::_RunSelectOnce()
+ 	// running on localhost with a randomly-chosen port. (*Puke*)
+ 	// Windows has a version of the Unix pipe() library function, but it doesn't
+ 	// give you back descriptors that are selectable.
+-	FD_SET (LoopBreakerReader, &(SelectData.fdreads));
++	rb_fd_set (LoopBreakerReader, &(SelectData.fdreads));
+ 	if (SelectData.maxsocket < LoopBreakerReader)
+ 		SelectData.maxsocket = LoopBreakerReader;
+ 
+@@ -810,15 +810,15 @@ bool EventMachine_t::_RunSelectOnce()
+ 		assert (sd != INVALID_SOCKET);
+ 
+ 		if (ed->SelectForRead())
+-			FD_SET (sd, &(SelectData.fdreads));
++			rb_fd_set (sd, &(SelectData.fdreads));
+ 		if (ed->SelectForWrite())
+-			FD_SET (sd, &(SelectData.fdwrites));
++			rb_fd_set (sd, &(SelectData.fdwrites));
+ 
+ 		#ifdef OS_WIN32
+ 		/* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable.
+ 		   Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html
+ 		*/
+-		FD_SET (sd, &(SelectData.fderrors));
++		rb_fd_set (sd, &(SelectData.fderrors));
+ 		#endif
+ 
+ 		if (SelectData.maxsocket < sd)
+@@ -853,15 +853,15 @@ bool EventMachine_t::_RunSelectOnce()
+ 					continue;
+ 				assert (sd != INVALID_SOCKET);
+ 
+-				if (FD_ISSET (sd, &(SelectData.fdwrites)))
++				if (rb_fd_isset (sd, &(SelectData.fdwrites)))
+ 					ed->Write();
+-				if (FD_ISSET (sd, &(SelectData.fdreads)))
++				if (rb_fd_isset (sd, &(SelectData.fdreads)))
+ 					ed->Read();
+-				if (FD_ISSET (sd, &(SelectData.fderrors)))
++				if (rb_fd_isset (sd, &(SelectData.fderrors)))
+ 					ed->HandleError();
+ 			}
+ 
+-			if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads)))
++			if (rb_fd_isset (LoopBreakerReader, &(SelectData.fdreads)))
+ 				_ReadLoopBreaker();
+ 		}
+ 		else if (s < 0) {
+diff --git a/ext/em.h b/ext/em.h
+index c5d409a..845071c 100644
+--- a/ext/em.h
++++ b/ext/em.h
+@@ -32,7 +32,7 @@ See the file COPYING for complete licensing information.
+ 
+ #ifdef BUILD_FOR_RUBY
+   #include <ruby.h>
+-  #define EmSelect rb_thread_select
++  #define EmSelect rb_thread_fd_select
+ 
+   #if defined(HAVE_RBTRAP)
+     #include <rubysig.h>
+@@ -54,7 +54,7 @@ See the file COPYING for complete licensing information.
+     #define RUBY_UBF_IO RB_UBF_DFL
+   #endif
+ #else
+-  #define EmSelect select
++  #define EmSelect rb_fd_select
+ #endif
+ 
+ 
+@@ -218,9 +218,9 @@ struct SelectData_t
+ 	int _Select();
+ 
+ 	int maxsocket;
+-	fd_set fdreads;
+-	fd_set fdwrites;
+-	fd_set fderrors;
++	rb_fdset_t fdreads;
++	rb_fdset_t fdwrites;
++	rb_fdset_t fderrors;
+ 	timeval tv;
+ 	int nSockets;
+ };
+diff --git a/tests/test_many_fds.rb b/tests/test_many_fds.rb
+new file mode 100644
+index 0000000..74dc926
+--- /dev/null
++++ b/tests/test_many_fds.rb
+@@ -0,0 +1,22 @@
++require 'em_test_helper'
++require 'socket'
++
++class TestManyFDs < Test::Unit::TestCase
++  def setup
++    @port = next_port
++  end
++
++  def test_connection_class_cache
++    mod = Module.new
++    a = nil
++    Process.setrlimit(Process::RLIMIT_NOFILE,4096);
++    EM.run {
++      EM.start_server '127.0.0.1', @port, mod
++      1100.times do
++        a = EM.connect '127.0.0.1', @port, mod
++        assert_kind_of EM::Connection, a
++      end
++      EM.stop
++    }
++  end
++end
+-- 
+2.1.4
+
diff --git a/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch b/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch
new file mode 100644
index 0000000..9f4b20b
--- /dev/null
+++ b/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch
@@ -0,0 +1,45 @@
+From 0313f9e909f8c307563826e0e363cfdbf5ff3372 Mon Sep 17 00:00:00 2001
+From: Patrick Reynolds <patrick.reynolds at github.com>
+Date: Wed, 12 Mar 2014 00:15:41 -0500
+Subject: [PATCH 3/4] add stubs with warnings for 1.8.7 and 1.9.0
+
+Conflicts:
+	ext/em.h
+---
+ ext/em.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/ext/em.h b/ext/em.h
+index 845071c..7909d55 100644
+--- a/ext/em.h
++++ b/ext/em.h
+@@ -57,6 +57,26 @@ See the file COPYING for complete licensing information.
+   #define EmSelect rb_fd_select
+ #endif
+ 
++#ifndef rb_fd_max
++#define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n)))
++typedef fd_set rb_fdset_t;
++#define rb_fd_zero(f) FD_ZERO(f)
++#define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0)
++#define rb_fd_clr(n, f) do { if (fd_check(n)) FD_CLR((n), (f)); } while(0)
++#define rb_fd_isset(n, f) (fd_check(n) ? FD_ISSET((n), (f)) : 0)
++#define rb_fd_copy(d, s, n) (*(d) = *(s))
++#define rb_fd_dup(d, s) (*(d) = *(s))
++#define rb_fd_resize(n, f)  ((void)(f))
++#define rb_fd_ptr(f)  (f)
++#define rb_fd_init(f) FD_ZERO(f)
++#define rb_fd_init_copy(d, s) (*(d) = *(s))
++#define rb_fd_term(f) ((void)(f))
++#define rb_fd_max(f)  FD_SETSIZE
++#define rb_fd_select(n, rfds, wfds, efds, timeout)  \
++  select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
++#define rb_thread_fd_select(n, rfds, wfds, efds, timeout)  \
++  rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
++#endif
+ 
+ #ifdef OS_UNIX
+ typedef long long Int64;
+-- 
+2.1.4
+
diff --git a/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch b/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch
new file mode 100644
index 0000000..12f0209
--- /dev/null
+++ b/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch
@@ -0,0 +1,26 @@
+From 05b66f11c27e2df9e9e2d7ff75f0f42d258856d7 Mon Sep 17 00:00:00 2001
+From: Patrick Reynolds <patrick.reynolds at github.com>
+Date: Wed, 21 Jan 2015 22:34:43 -0600
+Subject: [PATCH 4/4] add comment about where the macros came from
+
+---
+ ext/em.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/ext/em.h b/ext/em.h
+index 7909d55..b80779c 100644
+--- a/ext/em.h
++++ b/ext/em.h
+@@ -59,6 +59,9 @@ See the file COPYING for complete licensing information.
+ 
+ #ifndef rb_fd_max
+ #define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n)))
++// These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3,
++// with this change: any macros that read or write the nth element of an
++// fdset first call fd_check to make sure n is in bounds.
+ typedef fd_set rb_fdset_t;
+ #define rb_fd_zero(f) FD_ZERO(f)
+ #define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0)
+-- 
+2.1.4
+
diff --git a/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch b/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch
new file mode 100644
index 0000000..fc4fad4
--- /dev/null
+++ b/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch
@@ -0,0 +1,173 @@
+From d5eec7b64c42edce688ef1d60e9900d66848b35f Mon Sep 17 00:00:00 2001
+From: Balint Reczey <balint at balintreczey.hu>
+Date: Mon, 27 Jun 2016 22:48:38 +0200
+Subject: [PATCH 5/5] Back-port em_test_helper.rb for test_many_fds.rb
+
+---
+ tests/em_test_helper.rb | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 154 insertions(+)
+ create mode 100644 tests/em_test_helper.rb
+
+diff --git a/tests/em_test_helper.rb b/tests/em_test_helper.rb
+new file mode 100644
+index 0000000..20a3e59
+--- /dev/null
++++ b/tests/em_test_helper.rb
+@@ -0,0 +1,154 @@
++require 'em/pure_ruby' if ENV['EM_PURE_RUBY']
++require 'eventmachine'
++require 'test/unit'
++require 'rbconfig'
++require 'socket'
++
++puts "EM Library Type: #{EM.library_type}"
++
++class Test::Unit::TestCase
++  class EMTestTimeout < StandardError ; end
++
++  def setup_timeout(timeout = TIMEOUT_INTERVAL)
++    EM.schedule {
++      EM.add_timer(timeout) {
++        raise EMTestTimeout, "Test was cancelled after #{timeout} seconds."
++      }
++    }
++  end
++
++  def port_in_use?(port, host="127.0.0.1")
++    s = TCPSocket.new(host, port)
++    s.close
++    s
++  rescue Errno::ECONNREFUSED
++    false
++  end
++
++  def next_port
++    @@port ||= 9000
++    begin
++      @@port += 1
++    end while port_in_use?(@@port)
++
++    @@port
++  end
++
++  # Returns true if the host have a localhost 127.0.0.1 IPv4.
++  def self.local_ipv4?
++    return @@has_local_ipv4 if defined?(@@has_local_ipv4)
++    begin
++      get_my_ipv4_address "127.0.0.1"
++      @@has_local_ipv4 = true
++    rescue
++      @@has_local_ipv4 = false
++    end
++  end
++
++  # Returns true if the host have a public IPv4 and stores it in
++  # @@public_ipv4.
++  def self.public_ipv4?
++    return @@has_public_ipv4 if defined?(@@has_public_ipv4)
++    begin
++      @@public_ipv4 = get_my_ipv4_address "1.2.3.4"
++      @@has_public_ipv4 = true
++    rescue
++      @@has_public_ipv4 = false
++    end
++  end
++
++  # Returns true if the host have a localhost ::1 IPv6.
++  def self.local_ipv6?
++    return @@has_local_ipv6 if defined?(@@has_local_ipv6)
++    begin
++      get_my_ipv6_address "::1"
++      @@has_local_ipv6 = true
++    rescue
++      @@has_local_ipv6 = false
++    end
++  end
++
++  # Returns true if the host have a public IPv6 and stores it in
++  # @@public_ipv6.
++  def self.public_ipv6?
++    return @@has_public_ipv6 if defined?(@@has_public_ipv6)
++    begin
++      @@public_ipv6 = get_my_ipv6_address "2001::1"
++      @@has_public_ipv6 = true
++    rescue
++      @@has_public_ipv6 = false
++    end
++  end
++
++  # Returns an array with the localhost addresses (IPv4 and/or IPv6).
++  def local_ips
++    return @@local_ips if defined?(@@local_ips)
++    @@local_ips = []
++    @@local_ips << "127.0.0.1" if self.class.local_ipv4?
++    @@local_ips << "::1" if self.class.local_ipv6?
++    @@local_ips
++  end
++
++  def exception_class
++    jruby? ? NativeException : RuntimeError
++  end
++
++  module PlatformHelper
++    # http://blog.emptyway.com/2009/11/03/proper-way-to-detect-windows-platform-in-ruby/
++    def windows?
++      RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
++    end
++
++    def solaris?
++      RUBY_PLATFORM =~ /solaris/
++    end
++
++    # http://stackoverflow.com/questions/1342535/how-can-i-tell-if-im-running-from-jruby-vs-ruby/1685970#1685970
++    def jruby?
++      defined? JRUBY_VERSION
++    end
++
++    def rbx?
++      defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
++    end
++  end
++
++  include PlatformHelper
++  extend PlatformHelper
++
++  # Tests run significantly slower on windows. YMMV
++  TIMEOUT_INTERVAL = windows? ? 1 : 0.25
++
++  def silent
++    backup, $VERBOSE = $VERBOSE, nil
++    begin
++      yield
++    ensure
++      $VERBOSE = backup
++    end
++  end
++
++
++  private
++
++  def self.get_my_ipv4_address ip
++    orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily
++    UDPSocket.open(Socket::AF_INET) do |s|
++      s.connect ip, 1
++      s.addr.last
++    end
++  ensure
++    Socket.do_not_reverse_lookup = orig
++  end
++
++  def self.get_my_ipv6_address ip
++    orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true  # turn off reverse DNS resolution temporarily
++    UDPSocket.open(Socket::AF_INET6) do |s|
++      s.connect ip, 1
++      s.addr.last
++    end
++  ensure
++    Socket.do_not_reverse_lookup = orig
++  end
++
++end
+-- 
+2.1.4
+
diff --git a/debian/patches/series b/debian/patches/series
index 235c4c1..b867e29 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,5 @@
 0001-Format-error-strings-safely.patch
+0002-use-ruby-select-api-with-expandable-fd-sets.patch
+0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch
+0004-add-comment-about-where-the-macros-came-from.patch
+0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-eventmachine.git



More information about the Pkg-ruby-extras-commits mailing list