diff --git a/array.c b/array.c index 0b5601d..a6a1e89 100644 --- a/array.c +++ b/array.c @@ -20,6 +20,7 @@ VALUE rb_cArray; static ID id_cmp; #define ARY_DEFAULT_SIZE 16 +#define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE)) void rb_mem_clear(mem, size) @@ -120,7 +121,7 @@ ary_new(klass, len) if (len < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); } - if (len > 0 && len * sizeof(VALUE) <= len) { + if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } if (len == 0) len++; @@ -293,7 +294,7 @@ rb_ary_initialize(argc, argv, ary) if (len < 0) { rb_raise(rb_eArgError, "negative array size"); } - if (len > 0 && len * (long)sizeof(VALUE) <= len) { + if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } if (len > RARRAY(ary)->aux.capa) { @@ -359,6 +360,10 @@ rb_ary_store(ary, idx, val) } } + if (idx >= ARY_MAX_SIZE) { + rb_raise(rb_eIndexError, "index %ld too big", idx); + } + rb_ary_modify(ary); if (idx >= RARRAY(ary)->aux.capa) { long new_capa = RARRAY(ary)->aux.capa / 2; @@ -366,6 +371,9 @@ rb_ary_store(ary, idx, val) if (new_capa < ARY_DEFAULT_SIZE) { new_capa = ARY_DEFAULT_SIZE; } + if (new_capa >= ARY_MAX_SIZE - idx) { + new_capa = (ARY_MAX_SIZE - idx) / 2; + } new_capa += idx; if (new_capa * (long)sizeof(VALUE) <= new_capa) { rb_raise(rb_eArgError, "index too big"); @@ -975,6 +983,9 @@ rb_ary_splice(ary, beg, len, rpl) rb_ary_modify(ary); if (beg >= RARRAY(ary)->len) { + if (beg > ARY_MAX_SIZE - rlen) { + rb_raise(rb_eIndexError, "index %ld too big", beg); + } len = beg + rlen; if (len >= RARRAY(ary)->aux.capa) { REALLOC_N(RARRAY(ary)->ptr, VALUE, len); @@ -2378,7 +2389,7 @@ rb_ary_times(ary, times) if (len < 0) { rb_raise(rb_eArgError, "negative argument"); } - if (LONG_MAX/len < RARRAY(ary)->len) { + if (ARY_MAX_SIZE/len < RARRAY(ary)->len) { rb_raise(rb_eArgError, "argument too big"); } len *= RARRAY(ary)->len; diff --git a/intern.h b/intern.h index 822066c..99c4ade 100644 --- a/intern.h +++ b/intern.h @@ -400,6 +400,7 @@ const char *ruby_signal_name _((int)); void ruby_default_signal _((int)); /* sprintf.c */ VALUE rb_f_sprintf _((int, VALUE*)); +VALUE rb_str_format _((int, VALUE*, VALUE)); /* string.c */ VALUE rb_str_new _((const char*, long)); VALUE rb_str_new2 _((const char*)); diff --git a/io.c b/io.c index 4ffad84..c4cca9d 100644 --- a/io.c +++ b/io.c @@ -4851,8 +4851,9 @@ rb_f_select(argc, argv, obj) #if !defined(MSDOS) && !defined(__human68k__) static int io_cntl(fd, cmd, narg, io_p) - int fd, cmd, io_p; + int fd, io_p; long narg; + unsigned long cmd; { int retval; @@ -4882,7 +4883,7 @@ rb_io_ctl(io, req, arg, io_p) int io_p; { #if !defined(MSDOS) && !defined(__human68k__) - int cmd = NUM2ULONG(req); + unsigned long cmd = NUM2ULONG(req); OpenFile *fptr; long len = 0; long narg = 0; diff --git a/lib/webrick/httpservlet/filehandler.rb b/lib/webrick/httpservlet/filehandler.rb index 410cc6f..c8278b7 100644 --- a/lib/webrick/httpservlet/filehandler.rb +++ b/lib/webrick/httpservlet/filehandler.rb @@ -163,6 +163,7 @@ module WEBrick end end end + prevent_directory_traversal(req, res) super(req, res) end @@ -198,6 +199,22 @@ module WEBrick private + def prevent_directory_traversal(req, res) + # Preventing directory traversal on DOSISH platforms; + # Backslashes (0x5c) in path_info are not interpreted as special + # character in URI notation. So the value of path_info should be + # normalize before accessing to the filesystem. + if File::ALT_SEPARATOR + # File.expand_path removes the trailing path separator. + # Adding a character is a workaround to save it. + # File.expand_path("/aaa/") #=> "/aaa" + # File.expand_path("/aaa/" + "x") #=> "/aaa/x" + expanded = File.expand_path(req.path_info + "x") + expanded[-1, 1] = "" # remove trailing "x" + req.path_info = expanded + end + end + def exec_handler(req, res) raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root if set_filename(req, res) @@ -256,7 +273,7 @@ module WEBrick def check_filename(req, res, name) @options[:NondisclosureName].each{|pattern| - if File.fnmatch("/#{pattern}", name) + if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD) @logger.warn("the request refers nondisclosure name `#{name}'.") raise HTTPStatus::NotFound, "`#{req.path}' not found." end @@ -310,7 +327,7 @@ module WEBrick def nondisclosure_name?(name) @options[:NondisclosureName].each{|pattern| - if File.fnmatch(pattern, name) + if File.fnmatch(pattern, name, File::FNM_CASEFOLD) return true end } diff --git a/sprintf.c b/sprintf.c index 9700c80..662da6c 100644 --- a/sprintf.c +++ b/sprintf.c @@ -247,7 +247,15 @@ rb_f_sprintf(argc, argv) int argc; VALUE *argv; { + return rb_str_format(argc - 1, argv + 1, GETNTHARG(0)); +} + +VALUE +rb_str_format(argc, argv, fmt) + int argc; + VALUE *argv; VALUE fmt; +{ const char *p, *end; char *buf; int blen, bsiz; @@ -276,7 +284,8 @@ rb_f_sprintf(argc, argv) rb_raise(rb_eArgError, "flag after precision"); \ } - fmt = GETNTHARG(0); + ++argc; + --argv; if (OBJ_TAINTED(fmt)) tainted = 1; StringValue(fmt); fmt = rb_str_new4(fmt); diff --git a/string.c b/string.c index 52ec322..623f76f 100644 --- a/string.c +++ b/string.c @@ -452,22 +452,16 @@ rb_str_times(str, times) */ static VALUE -rb_str_format(str, arg) +rb_str_format_m(str, arg) VALUE str, arg; { - VALUE *argv; + VALUE tmp = rb_check_array_type(arg); - if (TYPE(arg) == T_ARRAY) { - argv = ALLOCA_N(VALUE, RARRAY(arg)->len + 1); - argv[0] = str; - MEMCPY(argv+1, RARRAY(arg)->ptr, VALUE, RARRAY(arg)->len); - return rb_f_sprintf(RARRAY(arg)->len+1, argv); + if (!NIL_P(tmp)) { + return rb_str_format(RARRAY_LEN(tmp), RARRAY_PTR(tmp), str); } - argv = ALLOCA_N(VALUE, 2); - argv[0] = str; - argv[1] = arg; - return rb_f_sprintf(2, argv); + return rb_str_format(1, &arg, str); } static int @@ -694,18 +688,14 @@ rb_str_resize(str, len) return str; } -VALUE -rb_str_buf_cat(str, ptr, len) +static VALUE +str_buf_cat(str, ptr, len) VALUE str; const char *ptr; long len; { long capa, total; - if (len == 0) return str; - if (len < 0) { - rb_raise(rb_eArgError, "negative string size (or size too big)"); - } rb_str_modify(str); if (FL_TEST(str, STR_ASSOC)) { FL_UNSET(str, STR_ASSOC); @@ -714,9 +704,16 @@ rb_str_buf_cat(str, ptr, len) else { capa = RSTRING(str)->aux.capa; } + if (RSTRING(str)->len >= LONG_MAX - len) { + rb_raise(rb_eArgError, "string sizes too big"); + } total = RSTRING(str)->len+len; if (capa <= total) { while (total > capa) { + if (capa + 1 >= LONG_MAX / 2) { + capa = total; + break; + } capa = (capa + 1) * 2; } RESIZE_CAPA(str, capa); @@ -729,6 +726,19 @@ rb_str_buf_cat(str, ptr, len) } VALUE +rb_str_buf_cat(str, ptr, len) + VALUE str; + const char *ptr; + long len; +{ + if (len == 0) return str; + if (len < 0) { + rb_raise(rb_eArgError, "negative string size (or size too big)"); + } + return str_buf_cat(str, ptr, len); +} + +VALUE rb_str_buf_cat2(str, ptr) VALUE str; const char *ptr; @@ -747,7 +757,7 @@ rb_str_cat(str, ptr, len) } if (FL_TEST(str, STR_ASSOC)) { rb_str_modify(str); - REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len); + REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1); memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ @@ -769,29 +779,8 @@ VALUE rb_str_buf_append(str, str2) VALUE str, str2; { - long capa, len; - - rb_str_modify(str); - if (FL_TEST(str, STR_ASSOC)) { - FL_UNSET(str, STR_ASSOC); - capa = RSTRING(str)->aux.capa = RSTRING(str)->len; - } - else { - capa = RSTRING(str)->aux.capa; - } - len = RSTRING(str)->len+RSTRING(str2)->len; - if (capa <= len) { - while (len > capa) { - capa = (capa + 1) * 2; - } - RESIZE_CAPA(str, capa); - } - memcpy(RSTRING(str)->ptr + RSTRING(str)->len, - RSTRING(str2)->ptr, RSTRING(str2)->len); - RSTRING(str)->len += RSTRING(str2)->len; - RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ + str_buf_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); OBJ_INFECT(str, str2); - return str; } @@ -4657,7 +4646,7 @@ Init_String() rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1); rb_define_method(rb_cString, "+", rb_str_plus, 1); rb_define_method(rb_cString, "*", rb_str_times, 1); - rb_define_method(rb_cString, "%", rb_str_format, 1); + rb_define_method(rb_cString, "%", rb_str_format_m, 1); rb_define_method(rb_cString, "[]", rb_str_aref_m, -1); rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1); rb_define_method(rb_cString, "insert", rb_str_insert, 2);