diff options
author | stas <stas@FreeBSD.org> | 2008-08-11 03:26:33 +0800 |
---|---|---|
committer | stas <stas@FreeBSD.org> | 2008-08-11 03:26:33 +0800 |
commit | 41a05d76652a8757441845c8c00a610c6662edf5 (patch) | |
tree | 60a5d92a45bf95413b8ab4cead6e306411625094 /lang | |
parent | 8479e10aebd2c2640058330c3ce7ca4a40a79ca8 (diff) | |
download | freebsd-ports-gnome-41a05d76652a8757441845c8c00a610c6662edf5.tar.gz freebsd-ports-gnome-41a05d76652a8757441845c8c00a610c6662edf5.tar.zst freebsd-ports-gnome-41a05d76652a8757441845c8c00a610c6662edf5.zip |
- Fix CVE-2008-1447 (DNS spoofing vulnerability).
- Fix Webrick DoS vulnerability.
- Serveral minor bugfixes in cgi.rb, ipaddr.rb and resolver.
- Bump PORTREVISION.
Obtained from: ruby VCS
Tested by: Ilya Bakulin <webmaster@kibab.com>
Diffstat (limited to 'lang')
-rw-r--r-- | lang/ruby18/files/patch-lib_cgi.rb | 36 | ||||
-rw-r--r-- | lang/ruby18/files/patch-lib_ipaddr.rb | 11 | ||||
-rw-r--r-- | lang/ruby18/files/patch-lib_optparse.rb | 19 | ||||
-rw-r--r-- | lang/ruby18/files/patch-lib_resolv-replace.rb | 12 | ||||
-rw-r--r-- | lang/ruby18/files/patch-lib_resolv.rb | 401 | ||||
-rw-r--r-- | lang/ruby18/files/patch-lib_webrick_httputils.rb | 32 |
6 files changed, 511 insertions, 0 deletions
diff --git a/lang/ruby18/files/patch-lib_cgi.rb b/lang/ruby18/files/patch-lib_cgi.rb new file mode 100644 index 000000000000..fdbf1d62f9d9 --- /dev/null +++ b/lang/ruby18/files/patch-lib_cgi.rb @@ -0,0 +1,36 @@ +--- lib/cgi.rb.orig 2008-08-10 14:28:28.000000000 +0400 ++++ lib/cgi.rb 2008-08-10 14:28:44.000000000 +0400 +@@ -1032,13 +1032,13 @@ + if "--" == $2 + content_length = -1 + end +- boundary_end = $2.dup ++ boundary_end = $2.dup + "" + end + + body.rewind + +- /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;]*))/ni.match(head) ++ /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni.match(head) + filename = ($1 or $2 or "") + if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and + /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and +@@ -1046,7 +1046,7 @@ + filename = CGI::unescape(filename) + end + +- /Content-Type: (.*)/ni.match(head) ++ /Content-Type: ([^\s]*)/ni.match(head) + content_type = ($1 or "") + + (class << body; self; end).class_eval do +@@ -1055,7 +1055,7 @@ + define_method(:content_type) {content_type.dup.taint} + end + +- /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head) ++ /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head) + name = $1.dup + + if params.has_key?(name) diff --git a/lang/ruby18/files/patch-lib_ipaddr.rb b/lang/ruby18/files/patch-lib_ipaddr.rb new file mode 100644 index 000000000000..c0288626562b --- /dev/null +++ b/lang/ruby18/files/patch-lib_ipaddr.rb @@ -0,0 +1,11 @@ +--- lib/ipaddr.rb.orig 2008-08-10 14:32:15.000000000 +0400 ++++ lib/ipaddr.rb 2008-08-10 14:32:58.000000000 +0400 +@@ -438,7 +438,7 @@ + if prefixlen + mask!(prefixlen) + else +- @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK ++ @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK + end + end + diff --git a/lang/ruby18/files/patch-lib_optparse.rb b/lang/ruby18/files/patch-lib_optparse.rb new file mode 100644 index 000000000000..5dd888108b31 --- /dev/null +++ b/lang/ruby18/files/patch-lib_optparse.rb @@ -0,0 +1,19 @@ +--- lib/optparse.rb.orig 2008-08-10 14:34:06.000000000 +0400 ++++ lib/optparse.rb 2008-08-10 14:34:32.000000000 +0400 +@@ -379,7 +379,7 @@ + while s = lopts.shift + l = left[-1].length + s.length + l += arg.length if left.size == 1 && arg +- l < max or left << '' ++ l < max or sopts.empty? or left << '' + left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s + end + +@@ -1474,6 +1474,7 @@ + # + def environment(env = File.basename($0, '.*')) + env = ENV[env] || ENV[env.upcase] or return ++ require 'shellwords' + parse(*Shellwords.shellwords(env)) + end + diff --git a/lang/ruby18/files/patch-lib_resolv-replace.rb b/lang/ruby18/files/patch-lib_resolv-replace.rb new file mode 100644 index 000000000000..58e54eb6dcda --- /dev/null +++ b/lang/ruby18/files/patch-lib_resolv-replace.rb @@ -0,0 +1,12 @@ +--- lib/resolv-replace.rb.orig 2008-08-10 14:35:16.000000000 +0400 ++++ lib/resolv-replace.rb 2008-08-10 14:35:40.000000000 +0400 +@@ -23,7 +23,8 @@ + class UDPSocket + alias original_resolv_bind bind + def bind(host, port) +- original_resolv_bind(IPSocket.getaddress(host), port) ++ host = IPSocket.getaddress(host) if host != "" ++ original_resolv_bind(host, port) + end + + alias original_resolv_connect connect diff --git a/lang/ruby18/files/patch-lib_resolv.rb b/lang/ruby18/files/patch-lib_resolv.rb new file mode 100644 index 000000000000..e070af9a98bf --- /dev/null +++ b/lang/ruby18/files/patch-lib_resolv.rb @@ -0,0 +1,401 @@ +--- lib/resolv.rb.orig 2008-08-10 14:36:37.000000000 +0400 ++++ lib/resolv.rb 2008-08-10 14:38:09.000000000 +0400 +@@ -194,6 +194,11 @@ + require 'timeout' + require 'thread' + ++begin ++ require 'securerandom' ++rescue LoadError ++end ++ + class Resolv + def self.getaddress(name) + DefaultResolver.getaddress(name) +@@ -388,13 +393,6 @@ + @mutex.synchronize { + unless @initialized + @config.lazy_initialize +- +- if nameserver = @config.single? +- @requester = Requester::ConnectedUDP.new(nameserver) +- else +- @requester = Requester::UnconnectedUDP.new +- end +- + @initialized = true + end + } +@@ -404,8 +402,6 @@ + def close + @mutex.synchronize { + if @initialized +- @requester.close if @requester +- @requester = nil + @initialized = false + end + } +@@ -464,7 +460,7 @@ + + def each_resource(name, typeclass, &proc) + lazy_initialize +- q = Queue.new ++ requester = make_requester + senders = {} + begin + @config.resolv(name) {|candidate, tout, nameserver| +@@ -473,11 +469,9 @@ + msg.add_question(candidate, typeclass) + unless sender = senders[[candidate, nameserver]] + sender = senders[[candidate, nameserver]] = +- @requester.sender(msg, candidate, q, nameserver) ++ requester.sender(msg, candidate, nameserver) + end +- sender.send +- reply = reply_name = nil +- timeout(tout, ResolvTimeout) { reply, reply_name = q.pop } ++ reply, reply_name = requester.request(sender, tout) + case reply.rcode + when RCode::NoError + extract_resources(reply, reply_name, typeclass, &proc) +@@ -489,7 +483,15 @@ + end + } + ensure +- @requester.delete(q) ++ requester.close ++ end ++ end ++ ++ def make_requester # :nodoc: ++ if nameserver = @config.single? ++ Requester::ConnectedUDP.new(nameserver) ++ else ++ Requester::UnconnectedUDP.new + end + end + +@@ -524,45 +526,105 @@ + } + end + ++ if defined? SecureRandom ++ def self.random(arg) # :nodoc: ++ begin ++ SecureRandom.random_number(arg) ++ rescue NotImplementedError ++ rand(arg) ++ end ++ end ++ else ++ def self.random(arg) # :nodoc: ++ rand(arg) ++ end ++ end ++ ++ def self.rangerand(range) # :nodoc: ++ base = range.begin ++ len = range.end - range.begin ++ if !range.exclude_end? ++ len += 1 ++ end ++ base + random(len) ++ end ++ ++ RequestID = {} ++ RequestIDMutex = Mutex.new ++ ++ def self.allocate_request_id(host, port) # :nodoc: ++ id = nil ++ RequestIDMutex.synchronize { ++ h = (RequestID[[host, port]] ||= {}) ++ begin ++ id = rangerand(0x0000..0xffff) ++ end while h[id] ++ h[id] = true ++ } ++ id ++ end ++ ++ def self.free_request_id(host, port, id) # :nodoc: ++ RequestIDMutex.synchronize { ++ key = [host, port] ++ if h = RequestID[key] ++ h.delete id ++ if h.empty? ++ RequestID.delete key ++ end ++ end ++ } ++ end ++ ++ def self.bind_random_port(udpsock) # :nodoc: ++ begin ++ port = rangerand(1024..65535) ++ udpsock.bind("", port) ++ rescue Errno::EADDRINUSE ++ retry ++ end ++ end ++ + class Requester + def initialize + @senders = {} ++ @sock = nil + end + +- def close +- thread, sock, @thread, @sock = @thread, @sock +- begin +- if thread +- thread.kill +- thread.join ++ def request(sender, tout) ++ timelimit = Time.now + tout ++ sender.send ++ while (now = Time.now) < timelimit ++ timeout = timelimit - now ++ if !IO.select([@sock], nil, nil, timeout) ++ raise ResolvTimeout ++ end ++ reply, from = recv_reply ++ begin ++ msg = Message.decode(reply) ++ rescue DecodeError ++ next # broken DNS message ignored ++ end ++ if s = @senders[[from,msg.id]] ++ break ++ else ++ # unexpected DNS message ignored + end +- ensure +- sock.close if sock + end ++ return msg, s.data + end + +- def delete(arg) +- case arg +- when Sender +- @senders.delete_if {|k, s| s == arg } +- when Queue +- @senders.delete_if {|k, s| s.queue == arg } +- else +- raise ArgumentError.new("neither Sender or Queue: #{arg}") +- end ++ def close ++ sock = @sock ++ @sock = nil ++ sock.close if sock + end + +- class Sender +- def initialize(msg, data, sock, queue) ++ class Sender # :nodoc: ++ def initialize(msg, data, sock) + @msg = msg + @data = data + @sock = sock +- @queue = queue +- end +- attr_reader :queue +- +- def recv(msg) +- @queue.push([msg, @data]) + end + end + +@@ -570,45 +632,38 @@ + def initialize + super() + @sock = UDPSocket.new +- @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD +- @id = {} +- @id.default = -1 +- @thread = Thread.new { +- DNSThreadGroup.add Thread.current +- loop { +- reply, from = @sock.recvfrom(UDPSize) +- msg = begin +- Message.decode(reply) +- rescue DecodeError +- STDERR.print("DNS message decoding error: #{reply.inspect}\n") +- next +- end +- if s = @senders[[[from[3],from[1]],msg.id]] +- s.recv msg +- else +- #STDERR.print("non-handled DNS message: #{msg.inspect} from #{from.inspect}\n") +- end +- } +- } ++ @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD ++ DNS.bind_random_port(@sock) ++ end ++ ++ def recv_reply ++ reply, from = @sock.recvfrom(UDPSize) ++ return reply, [from[3],from[1]] + end + +- def sender(msg, data, queue, host, port=Port) ++ def sender(msg, data, host, port=Port) + service = [host, port] +- id = Thread.exclusive { +- @id[service] = (@id[service] + 1) & 0xffff +- } ++ id = DNS.allocate_request_id(host, port) + request = msg.encode + request[0,2] = [id].pack('n') + return @senders[[service, id]] = +- Sender.new(request, data, @sock, host, port, queue) ++ Sender.new(request, data, @sock, host, port) ++ end ++ ++ def close ++ super ++ @senders.each_key {|service, id| ++ DNS.free_request_id(service[0], service[1], id) ++ } + end + + class Sender < Requester::Sender +- def initialize(msg, data, sock, host, port, queue) +- super(msg, data, sock, queue) ++ def initialize(msg, data, sock, host, port) ++ super(msg, data, sock) + @host = host + @port = port + end ++ attr_reader :data + + def send + @sock.send(@msg, 0, @host, @port) +@@ -622,42 +677,38 @@ + @host = host + @port = port + @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET) ++ DNS.bind_random_port(@sock) + @sock.connect(host, port) +- @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD +- @id = -1 +- @thread = Thread.new { +- DNSThreadGroup.add Thread.current +- loop { +- reply = @sock.recv(UDPSize) +- msg = begin +- Message.decode(reply) +- rescue DecodeError +- STDERR.print("DNS message decoding error: #{reply.inspect}") +- next +- end +- if s = @senders[msg.id] +- s.recv msg +- else +- #STDERR.print("non-handled DNS message: #{msg.inspect}") +- end +- } +- } ++ @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD ++ end ++ ++ def recv_reply ++ reply = @sock.recv(UDPSize) ++ return reply, nil + end + +- def sender(msg, data, queue, host=@host, port=@port) ++ def sender(msg, data, host=@host, port=@port) + unless host == @host && port == @port + raise RequestError.new("host/port don't match: #{host}:#{port}") + end +- id = Thread.exclusive { @id = (@id + 1) & 0xffff } ++ id = DNS.allocate_request_id(@host, @port) + request = msg.encode + request[0,2] = [id].pack('n') +- return @senders[id] = Sender.new(request, data, @sock, queue) ++ return @senders[[nil,id]] = Sender.new(request, data, @sock) ++ end ++ ++ def close ++ super ++ @senders.each_key {|from, id| ++ DNS.free_request_id(@host, @port, id) ++ } + end + + class Sender < Requester::Sender + def send + @sock.send(@msg, 0) + end ++ attr_reader :data + end + end + +@@ -666,39 +717,25 @@ + super() + @host = host + @port = port +- @sock = TCPSocket.new +- @sock.connect(host, port) +- @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD +- @id = -1 ++ @sock = TCPSocket.new(@host, @port) ++ @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD + @senders = {} +- @thread = Thread.new { +- DNSThreadGroup.add Thread.current +- loop { +- len = @sock.read(2).unpack('n') +- reply = @sock.read(len) +- msg = begin +- Message.decode(reply) +- rescue DecodeError +- STDERR.print("DNS message decoding error: #{reply.inspect}") +- next +- end +- if s = @senders[msg.id] +- s.push msg +- else +- #STDERR.print("non-handled DNS message: #{msg.inspect}") +- end +- } +- } + end + +- def sender(msg, data, queue, host=@host, port=@port) ++ def recv_reply ++ len = @sock.read(2).unpack('n')[0] ++ reply = @sock.read(len) ++ return reply, nil ++ end ++ ++ def sender(msg, data, host=@host, port=@port) + unless host == @host && port == @port + raise RequestError.new("host/port don't match: #{host}:#{port}") + end +- id = Thread.exclusive { @id = (@id + 1) & 0xffff } ++ id = DNS.allocate_request_id(@host, @port) + request = msg.encode + request[0,2] = [request.length, id].pack('nn') +- return @senders[id] = Sender.new(request, data, @sock, queue) ++ return @senders[[nil,id]] = Sender.new(request, data, @sock) + end + + class Sender < Requester::Sender +@@ -706,6 +743,14 @@ + @sock.print(@msg) + @sock.flush + end ++ attr_reader :data ++ end ++ ++ def close ++ super ++ @senders.each_key {|from,id| ++ DNS.free_request_id(@host, @port, id) ++ } + end + end + diff --git a/lang/ruby18/files/patch-lib_webrick_httputils.rb b/lang/ruby18/files/patch-lib_webrick_httputils.rb new file mode 100644 index 000000000000..c0c050b7d5ed --- /dev/null +++ b/lang/ruby18/files/patch-lib_webrick_httputils.rb @@ -0,0 +1,32 @@ +--- lib/webrick/httputils.rb.orig 2008-08-10 14:29:50.000000000 +0400 ++++ lib/webrick/httputils.rb 2008-08-10 14:30:34.000000000 +0400 +@@ -23,16 +23,8 @@ + ret = path.dup + + ret.gsub!(%r{/+}o, '/') # // => / +- while ret.sub!(%r{/\.(/|\Z)}o, '/'); end # /. => / +- begin # /foo/.. => /foo +- match = ret.sub!(%r{/([^/]+)/\.\.(/|\Z)}o){ +- if $1 == ".." +- raise "abnormal path `#{path}'" +- else +- "/" +- end +- } +- end while match ++ while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => / ++ while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo + + raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret + ret +@@ -154,8 +146,8 @@ + module_function :parse_header + + def split_header_value(str) +- str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+) +- (?:,\s*|\Z)/xn).collect{|v| v[0] } ++ str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+) ++ (?:,\s*|\Z)'xn).flatten + end + module_function :split_header_value + |