diff options
author | Nobuyoshi Nakada <[email protected]> | 2021-09-03 19:40:22 +0900 |
---|---|---|
committer | git <[email protected]> | 2021-12-12 13:05:15 +0900 |
commit | e4b35b158a16c42d2b91a3e88309875240d0ce27 (patch) | |
tree | c310fbf57098d2141f930d8cdb1720609fd2bac3 | |
parent | fbd733701659eed2d5a652b5890cfa80ccbce864 (diff) |
[ruby/cgi] Check integer overflow in long range
https://hackerone.com/reports/1328463
https://github.com/ruby/cgi/commit/ccaf6027e0
-rw-r--r-- | ext/cgi/escape/escape.c | 13 | ||||
-rw-r--r-- | test/cgi/test_cgi_util.rb | 17 |
2 files changed, 28 insertions, 2 deletions
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c index 809f95ef4c..f88b61478b 100644 --- a/ext/cgi/escape/escape.c +++ b/ext/cgi/escape/escape.c @@ -32,12 +32,21 @@ preserve_original_state(VALUE orig, VALUE dest) rb_enc_associate(dest, rb_enc_get(orig)); } +static inline long +escaped_length(VALUE str) +{ + const long len = RSTRING_LEN(str); + if (len >= LONG_MAX / HTML_ESCAPE_MAX_LEN) { + ruby_malloc_size_overflow(len, HTML_ESCAPE_MAX_LEN); + } + return len * HTML_ESCAPE_MAX_LEN; +} + static VALUE optimized_escape_html(VALUE str) { VALUE vbuf; - typedef char escape_buf[HTML_ESCAPE_MAX_LEN]; - char *buf = *ALLOCV_N(escape_buf, vbuf, RSTRING_LEN(str)); + char *buf = ALLOCV_N(char, vbuf, escaped_length(str)); const char *cstr = RSTRING_PTR(str); const char *end = cstr + RSTRING_LEN(str); diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb index 6ce8b42c20..5a2d07b328 100644 --- a/test/cgi/test_cgi_util.rb +++ b/test/cgi/test_cgi_util.rb @@ -104,6 +104,23 @@ class CGIUtilTest < Test::Unit::TestCase assert_not_predicate CGI.escapeHTML("Ruby".freeze), :frozen? end + def test_cgi_escape_html_large + ulong_max, size_max = RbConfig::LIMITS.values_at("ULONG_MAX", "SIZE_MAX") + return unless ulong_max < size_max # Platforms not concerned + + size = (ulong_max / 6 + 1) + begin + str = '"' * size + escaped = CGI.escapeHTML(str) + rescue NoMemoryError + omit "Not enough memory" + rescue => e + end + assert_raise_with_message(ArgumentError, /overflow/, ->{"length = #{escaped.length}"}) do + raise e if e + end + end + def test_cgi_unescapeHTML assert_equal("'&\"><", CGI.unescapeHTML("'&"><")) end |