ruby-changes:43338
From: nobu <ko1@a...>
Date: Tue, 14 Jun 2016 22:22:12 +0900 (JST)
Subject: [ruby-changes:43338] nobu:r55412 (trunk): strftime.c: limit result size
nobu 2016-06-14 22:22:09 +0900 (Tue, 14 Jun 2016) New Revision: 55412 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55412 Log: strftime.c: limit result size * strftime.c (rb_strftime_with_timespec): limit the result string size by the format length, to get rid of unlimited memory use. Modified files: trunk/ChangeLog trunk/strftime.c Index: ChangeLog =================================================================== --- ChangeLog (revision 55411) +++ ChangeLog (revision 55412) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue Jun 14 22:22:07 2016 Nobuyoshi Nakada <nobu@r...> + + * strftime.c (rb_strftime_with_timespec): limit the result string + size by the format length, to get rid of unlimited memory use. + Tue Jun 14 22:11:11 2016 Kazuki Yamaguchi <k@r...> * ext/openssl/ossl_ocsp.c (ossl_ocspcid_get_issuer_name_hash, Index: strftime.c =================================================================== --- strftime.c (revision 55411) +++ strftime.c (revision 55412) @@ -162,10 +162,14 @@ enum {LEFT, CHCASE, LOWER, UPPER}; https://github.com/ruby/ruby/blob/trunk/strftime.c#L162 static char * resize_buffer(VALUE ftime, char *s, const char **start, const char **endp, - ptrdiff_t n) + ptrdiff_t n, size_t maxsize) { size_t len = s - *start; size_t nlen = len + n * 2; + + if (nlen < len || nlen > maxsize) { + return 0; + } rb_str_set_len(ftime, len); rb_str_modify_expand(ftime, nlen-len); s = RSTRING_PTR(ftime); @@ -174,6 +178,18 @@ resize_buffer(VALUE ftime, char *s, cons https://github.com/ruby/ruby/blob/trunk/strftime.c#L178 return s += len; } +static void +buffer_size_check(const char *s, + const char *format_end, size_t format_len, + rb_encoding *enc) +{ + if (!s) { + const char *format = format_end-format_len; + VALUE fmt = rb_enc_str_new(format, format_len, enc); + rb_syserr_fail_str(ERANGE, fmt); + } +} + static char * case_conv(char *s, ptrdiff_t i, int flags) { @@ -211,7 +227,7 @@ format_value(VALUE val, int base) https://github.com/ruby/ruby/blob/trunk/strftime.c#L227 static VALUE rb_strftime_with_timespec(VALUE ftime, const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, VALUE timev, - struct timespec *ts, int gmt) + struct timespec *ts, int gmt, size_t maxsize) { size_t len = RSTRING_LEN(ftime); char *s = RSTRING_PTR(ftime); @@ -262,8 +278,10 @@ rb_strftime_with_timespec(VALUE ftime, c https://github.com/ruby/ruby/blob/trunk/strftime.c#L278 goto unknown; \ } while (0) #define NEEDS(n) do { \ - if (s >= endp || (n) >= endp - s - 1) \ - s = resize_buffer(ftime, s, &start, &endp, (n)); \ + if (s >= endp || (n) >= endp - s - 1) { \ + s = resize_buffer(ftime, s, &start, &endp, (n), maxsize); \ + buffer_size_check(s, format_end, format_len, enc); \ + } \ } while (0) #define FILL_PADDING(i) do { \ if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \ @@ -298,7 +316,8 @@ rb_strftime_with_timespec(VALUE ftime, c https://github.com/ruby/ruby/blob/trunk/strftime.c#L316 do { \ len = s - start; \ rb_str_set_len(ftime, len); \ - if (!rb_strftime_with_timespec(ftime, (fmt), rb_strlen_lit(fmt), enc, vtm, timev, ts, gmt)) \ + if (!rb_strftime_with_timespec(ftime, (fmt), rb_strlen_lit(fmt), \ + enc, vtm, timev, ts, gmt, maxsize)) \ return 0; \ s = RSTRING_PTR(ftime); \ i = RSTRING_LEN(ftime) - len; \ @@ -881,13 +900,23 @@ rb_strftime_with_timespec(VALUE ftime, c https://github.com/ruby/ruby/blob/trunk/strftime.c#L900 return ftime; } +static size_t +strftime_size_limit(size_t format_len) +{ + size_t limit = format_len * (1*1024*1024); + if (limit < format_len) limit = format_len; + else if (limit < 1024) limit = 1024; + return limit; +} + VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt) { VALUE result = rb_enc_str_new(0, 0, enc); return rb_strftime_with_timespec(result, format, format_len, enc, - vtm, timev, NULL, gmt); + vtm, timev, NULL, gmt, + strftime_size_limit(format_len)); } VALUE @@ -896,9 +925,22 @@ rb_strftime_timespec(const char *format, https://github.com/ruby/ruby/blob/trunk/strftime.c#L925 { VALUE result = rb_enc_str_new(0, 0, enc); return rb_strftime_with_timespec(result, format, format_len, enc, - vtm, Qnil, ts, gmt); + vtm, Qnil, ts, gmt, + strftime_size_limit(format_len)); } +#if 0 +VALUE +rb_strftime_limit(const char *format, size_t format_len, + rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, + int gmt, size_t maxsize) +{ + VALUE result = rb_enc_str_new(0, 0, enc); + return rb_strftime_with_timespec(result, format, format_len, enc, + vtm, Qnil, ts, gmt, maxsize); +} +#endif + /* isleap --- is a year a leap year? */ static int -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/