Skip to content

Commit

Permalink
Reduce resource cosumption of Net::FTP::TIME_PARSER
Browse files Browse the repository at this point in the history
Reported by Alexandr Savca as a DoS vulnerability, but Net::FTP is a
client library and the impact of the issue is low, so I have decided
to fix it as a normal issue.
Based on patch by nobu.
  • Loading branch information
shugo committed Apr 21, 2021
1 parent b0e2c34 commit a93af63
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 7 deletions.
20 changes: 15 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
PATH
remote: .
specs:
net-ftp (0.1.0)
net-ftp (0.1.1)
net-protocol
time

GEM
remote: https://rubygems.org/
specs:
power_assert (1.1.5)
rake (13.0.1)
test-unit (3.3.5)
date (3.1.0)
io-wait (0.1.0)
net-protocol (0.1.0)
io-wait
timeout
power_assert (2.0.0)
rake (13.0.3)
test-unit (3.4.1)
power_assert
time (0.1.0)
date
timeout (0.1.1)

PLATFORMS
ruby
Expand All @@ -20,4 +30,4 @@ DEPENDENCIES
test-unit

BUNDLED WITH
2.1.4
2.3.0.dev
5 changes: 3 additions & 2 deletions lib/net/ftp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1054,10 +1054,11 @@ def writable?
TIME_PARSER = ->(value, local = false) {
unless /\A(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})
(?<hour>\d{2})(?<min>\d{2})(?<sec>\d{2})
(?:\.(?<fractions>\d+))?/x =~ value
(?:\.(?<fractions>\d{1,17}))?/x =~ value
value = value[0, 97] + "..." if value.size > 100
raise FTPProtoError, "invalid time-val: #{value}"
end
usec = fractions.to_i * 10 ** (6 - fractions.to_s.size)
usec = ".#{fractions}".to_r * 1_000_000 if fractions
Time.public_send(local ? :local : :utc, year, month, day, hour, min, sec, usec)
}
FACT_PARSERS = Hash.new(CASE_DEPENDENT_PARSER)
Expand Down
11 changes: 11 additions & 0 deletions test/net/ftp/test_ftp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2509,6 +2509,17 @@ def test_puttextfile_command_injection
end
end

def test_time_parser
s = "20371231000000." + "9" * 999999999
assert_equal(Time.utc(2037, 12, 31, 0, 0, 0,
99999999999999999r / 100000000000),
Net::FTP::TIME_PARSER[s])
e = assert_raise(Net::FTPProtoError) {
Net::FTP::TIME_PARSER["x" * 999999999]
}
assert_equal("invalid time-val: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...", e.message)
end

private

def create_ftp_server(sleep_time = nil)
Expand Down

0 comments on commit a93af63

Please sign in to comment.