- 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>
This commit is contained in:
parent
7ebb5510d7
commit
344acaf18a
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=218354
7 changed files with 512 additions and 1 deletions
|
@ -167,7 +167,7 @@ RUBY?= ${LOCALBASE}/bin/${RUBY_NAME}
|
|||
# Ruby 1.8
|
||||
#
|
||||
RUBY_RELVERSION= 1.8.6
|
||||
RUBY_PORTREVISION= 4
|
||||
RUBY_PORTREVISION= 5
|
||||
RUBY_PORTEPOCH= 1
|
||||
RUBY_PATCHLEVEL= 111
|
||||
|
||||
|
|
36
lang/ruby18/files/patch-lib_cgi.rb
Normal file
36
lang/ruby18/files/patch-lib_cgi.rb
Normal file
|
@ -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)
|
11
lang/ruby18/files/patch-lib_ipaddr.rb
Normal file
11
lang/ruby18/files/patch-lib_ipaddr.rb
Normal file
|
@ -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
|
||||
|
19
lang/ruby18/files/patch-lib_optparse.rb
Normal file
19
lang/ruby18/files/patch-lib_optparse.rb
Normal file
|
@ -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
|
||||
|
12
lang/ruby18/files/patch-lib_resolv-replace.rb
Normal file
12
lang/ruby18/files/patch-lib_resolv-replace.rb
Normal file
|
@ -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
|
401
lang/ruby18/files/patch-lib_resolv.rb
Normal file
401
lang/ruby18/files/patch-lib_resolv.rb
Normal file
|
@ -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
|
||||
|
32
lang/ruby18/files/patch-lib_webrick_httputils.rb
Normal file
32
lang/ruby18/files/patch-lib_webrick_httputils.rb
Normal file
|
@ -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
|
||||
|
Loading…
Reference in a new issue