ruby-changes:16530
From: yugui <ko1@a...>
Date: Fri, 2 Jul 2010 19:14:30 +0900 (JST)
Subject: [ruby-changes:16530] Ruby:r28522 (ruby_1_9_1, ruby_1_9_2): * io.c (argf_inplace_mode_set): prohibits an assignment
yugui 2010-07-02 19:14:05 +0900 (Fri, 02 Jul 2010) New Revision: 28522 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=28522 Log: * io.c (argf_inplace_mode_set): prohibits an assignment of a tainted value. Patch by unak. * util.c, file.c: prevents a buffer over-run on windows. Patch by unak. Modified files: branches/ruby_1_9_1/ChangeLog branches/ruby_1_9_1/file.c branches/ruby_1_9_1/io.c branches/ruby_1_9_1/util.c branches/ruby_1_9_1/version.h branches/ruby_1_9_2/ChangeLog branches/ruby_1_9_2/file.c branches/ruby_1_9_2/io.c branches/ruby_1_9_2/util.c branches/ruby_1_9_2/version.h Index: ruby_1_9_1/ChangeLog =================================================================== --- ruby_1_9_1/ChangeLog (revision 28521) +++ ruby_1_9_1/ChangeLog (revision 28522) @@ -1,3 +1,11 @@ +Fri Jul 2 19:07:09 2010 Yuki Sonoda (Yugui) <yugui@y...> + + * io.c (argf_inplace_mode_set): prohibits an assignment + of a tainted value. Patch by unak. + + * util.c, file.c: prevents a buffer over-run on windows. + Patch by unak. + Wed May 26 13:27:18 2010 Yuki Sonoda (Yugui) <yugui@y...> * random.c: refactoring. Index: ruby_1_9_1/io.c =================================================================== --- ruby_1_9_1/io.c (revision 28521) +++ ruby_1_9_1/io.c (revision 28522) @@ -8368,6 +8368,9 @@ static VALUE argf_inplace_mode_set(VALUE argf, VALUE val) { + if (rb_safe_level() >= 1 && OBJ_TAINTED(val)) + rb_raise(rb_eSecurityError, "Insecure operation - ARGF.inplace_mode="); + if (!RTEST(val)) { if (ARGF.inplace) free(ARGF.inplace); ARGF.inplace = 0; Index: ruby_1_9_1/util.c =================================================================== --- ruby_1_9_1/util.c (revision 28521) +++ ruby_1_9_1/util.c (revision 28522) @@ -266,71 +266,81 @@ static const char suffix1[] = ".$$$"; static const char suffix2[] = ".~~~"; -#define ext (&buf[1000]) - #define strEQ(s1,s2) (strcmp(s1,s2) == 0) +extern const char *ruby_find_basename(const char *, long *, long *); +extern const char *ruby_find_extname(const char *, long *); + void ruby_add_suffix(VALUE str, const char *suffix) { int baselen; int extlen = strlen(suffix); - char *s, *t, *p; + char *p, *q; long slen; char buf[1024]; + const char *name; + const char *ext; + long len; - if (RSTRING_LEN(str) > 1000) - rb_fatal("Cannot do inplace edit on long filename (%ld characters)", - RSTRING_LEN(str)); + name = StringValueCStr(str); + slen = strlen(name); + if (slen > sizeof(buf) - 1) + rb_fatal("Cannot do inplace edit on long filename (%ld characters)", + slen); -#if defined(__CYGWIN32__) || defined(_WIN32) /* Style 0 */ - slen = RSTRING_LEN(str); rb_str_cat(str, suffix, extlen); if (valid_filename(RSTRING_PTR(str))) return; /* Fooey, style 0 failed. Fix str before continuing. */ rb_str_resize(str, slen); -#endif + name = StringValueCStr(str); + ext = ruby_find_extname(name, &len); - slen = extlen; - t = buf; baselen = 0; s = RSTRING_PTR(str); - while ((*t = *s) && *s != '.') { - baselen++; - if (*s == '\\' || *s == '/') baselen = 0; - s++; t++; - } - p = t; - - t = ext; extlen = 0; - while ((*t++ = *s++) != 0) extlen++; - if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; } - if (*suffix == '.') { /* Style 1 */ - if (strEQ(ext, suffix)) goto fallback; - strcpy(p, suffix); + if (ext) { + if (strEQ(ext, suffix)) goto fallback; + slen = ext - name; + } + rb_str_resize(str, slen); + rb_str_cat(str, suffix, extlen); } - else if (suffix[1] == '\0') { /* Style 2 */ - if (extlen < 4) { - ext[extlen] = *suffix; - ext[++extlen] = '\0'; - } - else if (baselen < 8) { - *p++ = *suffix; + else { + strncpy(buf, name, slen); + if (ext) + p = buf + (ext - name); + else + p = buf + slen; + p[len] = '\0'; + if (suffix[1] == '\0') { /* Style 2 */ + if (len <= 3) { + p[len] = *suffix; + p[++len] = '\0'; + } + else if ((q = (char *)ruby_find_basename(buf, &baselen, 0)) && + baselen < 8) { + q += baselen; + *q++ = *suffix; + if (ext) { + strncpy(q, ext, ext - name); + q[ext - name + 1] = '\0'; + } + else + *q = '\0'; + } + else if (len == 4 && p[3] != *suffix) + p[3] = *suffix; + else if (baselen == 8 && q[7] != *suffix) + q[7] = *suffix; + else + goto fallback; } - else if (ext[3] != *suffix) { - ext[3] = *suffix; + else { /* Style 3: Panic */ + fallback: + (void)memcpy(p, !ext || strEQ(ext, suffix1) ? suffix2 : suffix1, 5); } - else if (buf[7] != *suffix) { - buf[7] = *suffix; - } - else goto fallback; - strcpy(p, ext); } - else { /* Style 3: Panic */ -fallback: - (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); - } rb_str_resize(str, strlen(buf)); memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str)); } Index: ruby_1_9_1/version.h =================================================================== --- ruby_1_9_1/version.h (revision 28521) +++ ruby_1_9_1/version.h (revision 28522) @@ -1,13 +1,13 @@ #define RUBY_VERSION "1.9.1" -#define RUBY_PATCHLEVEL 428 +#define RUBY_PATCHLEVEL 429 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 9 #define RUBY_VERSION_TEENY 1 #define RUBY_RELEASE_YEAR 2010 #define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 1 -#define RUBY_RELEASE_DATE "2010-07-01" +#define RUBY_RELEASE_DAY 2 +#define RUBY_RELEASE_DATE "2010-07-02" #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_9_1/file.c =================================================================== --- ruby_1_9_1/file.c (revision 28521) +++ ruby_1_9_1/file.c (revision 28522) @@ -2982,36 +2982,15 @@ return 0; } -/* - * call-seq: - * File.basename(file_name [, suffix] ) -> base_name - * - * Returns the last component of the filename given in <i>file_name</i>, - * which must be formed using forward slashes (``<code>/</code>'') - * regardless of the separator used on the local file system. If - * <i>suffix</i> is given and present at the end of <i>file_name</i>, - * it is removed. - * - * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" - * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" - */ - -static VALUE -rb_file_s_basename(int argc, VALUE *argv) +const char * +ruby_find_basename(const char *name, long *len, long *ext) { - VALUE fname, fext, basename; - const char *name, *p; + const char *p; #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC const char *root; #endif - int f, n; + long f, n = -1; - if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { - StringValue(fext); - } - FilePathStringValue(fname); - if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) - return rb_str_new_shared(fname); name = skipprefix(name); #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC root = name; @@ -3050,11 +3029,57 @@ #else n = chompdirsep(p) - p; #endif + } + + if (len) + *len = f; + if (ext) + *ext = n; + return p; +} + +/* + * call-seq: + * File.basename(file_name [, suffix] ) -> base_name + * + * Returns the last component of the filename given in <i>file_name</i>, + * which must be formed using forward slashes (``<code>/</code>'') + * regardless of the separator used on the local file system. If + * <i>suffix</i> is given and present at the end of <i>file_name</i>, + * it is removed. + * + * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" + * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" + */ + +static VALUE +rb_file_s_basename(int argc, VALUE *argv) +{ + VALUE fname, fext, basename; + const char *name, *p; + long f, n; + + if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { + rb_encoding *enc; + StringValue(fext); + if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) { + rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s", + rb_enc_name(enc)); + } + } + FilePathStringValue(fname); + if (!NIL_P(fext)) rb_enc_check(fname, fext); + if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) + return rb_str_new_shared(fname); + + p = ruby_find_basename(name, &f, &n); + if (n >= 0) { if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) { f = n; } if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname); } + basename = rb_str_new(p, f); rb_enc_copy(basename, fname); OBJ_INFECT(basename, fname); @@ -3114,32 +3139,27 @@ } /* - * call-seq: - * File.extname(path) -> string - * - * Returns the extension (the portion of file name in <i>path</i> - * after the period). - * - * File.extname("test.rb") #=> ".rb" - * File.extname("a/b/d/test.rb") #=> ".rb" - * File.extname("test") #=> "" - * File.extname(".profile") #=> "" - * + * accept a String, and return the pointer of the extension. + * if len is passed, set the length of extension to it. + * returned pointer is in ``name'' or NULL. + * returns *len + * no dot NULL 0 + * dotfile top 0 + * end with dot dot 1 + * .ext dot len of .ext + * .ext:stream dot len of .ext without :stream (NT only) + * */ - -static VALUE -rb_file_s_extname(VALUE klass, VALUE fname) +const char * +ruby_find_extname(const char *name, long *len) { - const char *name, *p, *e; - VALUE extname; + const char *p, *e; - FilePathStringValue(fname); - name = StringValueCStr(fname); p = strrdirsep(name); /* get the last path component */ if (!p) p = name; else - name = ++p; + do name = ++p; while (isdirsep(*p)); e = 0; while (*p && *p == '.') p++; @@ -3170,9 +3190,46 @@ break; p = CharNext(p); } - if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */ + + if (len) { + /* no dot, or the only dot is first or end? */ + if (!e || e == name) + *len = 0; + else if (e+1 == p) + *len = 1; + else + *len = p - e; + } + return e; +} + +/* + * call-seq: + * File.extname(path) -> string + * + * Returns the extension (the portion of file name in <i>path</i> + * after the period). + * + * File.extname("test.rb") #=> ".rb" + * File.extname("a/b/d/test.rb") #=> ".rb" + * File.extname("test") #=> "" + * File.extname(".profile") #=> "" + * + */ + +static VALUE +rb_file_s_extname(VALUE klass, VALUE fname) +{ + const char *name, *e; + long len; + VALUE extname; + + FilePathStringValue(fname); + name = StringValueCStr(fname); + e = ruby_find_extname(name, &len); + if (len <= 1) return rb_str_new(0, 0); - extname = rb_str_new(e, p - e); /* keep the dot, too! */ + extname = rb_str_new(e, len); /* keep the dot, too! */ rb_enc_copy(extname, fname); OBJ_INFECT(extname, fname); return extname; Index: ruby_1_9_2/ChangeLog =================================================================== --- ruby_1_9_2/ChangeLog (revision 28521) +++ ruby_1_9_2/ChangeLog (revision 28522) @@ -1,3 +1,11 @@ +Fri Jul 2 19:07:09 2010 Yuki Sonoda (Yugui) <yugui@y...> + + * io.c (argf_inplace_mode_set): prohibits an assignment + of a tainted value. Patch by unak. + + * util.c, file.c: prevents a buffer over-run on windows. + Patch by unak. + Tue Jun 29 19:39:59 2010 Masaki Suketa <masaki.suketa@n...> * test/win32ole/test_win32ole_method.rb (is_ruby64): check Index: ruby_1_9_2/io.c =================================================================== --- ruby_1_9_2/io.c (revision 28521) +++ ruby_1_9_2/io.c (revision 28522) @@ -9548,6 +9548,9 @@ static VALUE argf_inplace_mode_set(VALUE argf, VALUE val) { + if (rb_safe_level() >= 1 && OBJ_TAINTED(val)) + rb_insecure_operation(); + if (!RTEST(val)) { if (ARGF.inplace) free(ARGF.inplace); ARGF.inplace = 0; Index: ruby_1_9_2/util.c =================================================================== --- ruby_1_9_2/util.c (revision 28521) +++ ruby_1_9_2/util.c (revision 28522) @@ -258,77 +258,85 @@ static const char suffix1[] = ".$$$"; static const char suffix2[] = ".~~~"; -#define ext (&buf[1000]) - #define strEQ(s1,s2) (strcmp(s1,s2) == 0) +extern const char *ruby_find_basename(const char *, long *, long *); +extern const char *ruby_find_extname(const char *, long *); + void ruby_add_suffix(VALUE str, const char *suffix) { int baselen; int extlen = strlen(suffix); - char *s, *t, *p; + char *p, *q; long slen; char buf[1024]; - char *const bufend = buf + sizeof(buf); + const char *name; + const char *ext; + long len; - if (RSTRING_LEN(str) > 1000) - rb_fatal("Cannot do inplace edit on long filename (%ld characters)", - RSTRING_LEN(str)); + name = StringValueCStr(str); + slen = strlen(name); + if (slen > sizeof(buf) - 1) + rb_fatal("Cannot do inplace edit on long filename (%ld characters)", + slen); -#if defined(__CYGWIN32__) || defined(_WIN32) /* Style 0 */ - slen = RSTRING_LEN(str); rb_str_cat(str, suffix, extlen); if (valid_filename(RSTRING_PTR(str))) return; /* Fooey, style 0 failed. Fix str before continuing. */ rb_str_resize(str, slen); -#endif + name = StringValueCStr(str); + ext = ruby_find_extname(name, &len); - slen = extlen; - t = buf; baselen = 0; s = RSTRING_PTR(str); - while ((*t = *s) && *s != '.') { - baselen++; - if (*s == '\\' || *s == '/') baselen = 0; - s++; t++; - } - p = t; - - t = ext; extlen = 0; - while ((*t++ = *s++) != 0) extlen++; - if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; } - if (*suffix == '.') { /* Style 1 */ - if (strEQ(ext, suffix)) goto fallback; - strlcpy(p, suffix, bufend - p); + if (ext) { + if (strEQ(ext, suffix)) goto fallback; + slen = ext - name; + } + rb_str_resize(str, slen); + rb_str_cat(str, suffix, extlen); } - else if (suffix[1] == '\0') { /* Style 2 */ - if (extlen < 4) { - ext[extlen] = *suffix; - ext[++extlen] = '\0'; - } - else if (baselen < 8) { - *p++ = *suffix; + else { + strncpy(buf, name, slen); + if (ext) + p = buf + (ext - name); + else + p = buf + slen; + p[len] = '\0'; + if (suffix[1] == '\0') { /* Style 2 */ + if (len <= 3) { + p[len] = *suffix; + p[++len] = '\0'; + } + else if ((q = (char *)ruby_find_basename(buf, &baselen, 0)) && + baselen < 8) { + q += baselen; + *q++ = *suffix; + if (ext) { + strncpy(q, ext, ext - name); + q[ext - name + 1] = '\0'; + } + else + *q = '\0'; + } + else if (len == 4 && p[3] != *suffix) + p[3] = *suffix; + else if (baselen == 8 && q[7] != *suffix) + q[7] = *suffix; + else + goto fallback; } - else if (ext[3] != *suffix) { - ext[3] = *suffix; + else { /* Style 3: Panic */ + fallback: + (void)memcpy(p, !ext || strEQ(ext, suffix1) ? suffix2 : suffix1, 5); } - else if (buf[7] != *suffix) { - buf[7] = *suffix; - } - else goto fallback; - strlcpy(p, ext, bufend - p); } - else { /* Style 3: Panic */ -fallback: - (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); - } rb_str_resize(str, strlen(buf)); memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str)); } -#if defined(__CYGWIN32__) || defined(_WIN32) static int valid_filename(const char *s) { @@ -350,7 +358,6 @@ return 0; } #endif -#endif /* mm.c */ Index: ruby_1_9_2/version.h =================================================================== --- ruby_1_9_2/version.h (revision 28521) +++ ruby_1_9_2/version.h (revision 28522) @@ -1,5 +1,5 @@ #define RUBY_VERSION "1.9.2" -#define RUBY_RELEASE_DATE "2010-07-01" +#define RUBY_RELEASE_DATE "2010-07-02" #define RUBY_PATCHLEVEL -1 #define RUBY_VERSION_MAJOR 1 @@ -7,7 +7,7 @@ #define RUBY_VERSION_TEENY 1 #define RUBY_RELEASE_YEAR 2010 #define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 1 +#define RUBY_RELEASE_DAY 2 #include "ruby/version.h" Index: ruby_1_9_2/file.c =================================================================== --- ruby_1_9_2/file.c (revision 28521) +++ ruby_1_9_2/file.c (revision 28522) @@ -3429,42 +3429,15 @@ return 0; } -/* - * call-seq: - * File.basename(file_name [, suffix] ) -> base_name - * - * Returns the last component of the filename given in <i>file_name</i>, - * which must be formed using forward slashes (``<code>/</code>'') - * regardless of the separator used on the local file system. If - * <i>suffix</i> is given and present at the end of <i>file_name</i>, - * it is removed. - * - * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" - * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" - */ - -static VALUE -rb_file_s_basename(int argc, VALUE *argv) +const char * +ruby_find_basename(const char *name, long *len, long *ext) { - VALUE fname, fext, basename; - const char *name, *p; + const char *p; #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC const char *root; #endif - long f, n; + long f, n = -1; - if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { - rb_encoding *enc; - StringValue(fext); - if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) { - rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s", - rb_enc_name(enc)); - } - } - FilePathStringValue(fname); - if (!NIL_P(fext)) rb_enc_check(fname, fext); - if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) - return rb_str_new_shared(fname); name = skipprefix(name); #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC root = name; @@ -3503,11 +3476,57 @@ #else n = chompdirsep(p) - p; #endif + } + + if (len) + *len = f; + if (ext) + *ext = n; + return p; +} + +/* + * call-seq: + * File.basename(file_name [, suffix] ) -> base_name + * + * Returns the last component of the filename given in <i>file_name</i>, + * which must be formed using forward slashes (``<code>/</code>'') + * regardless of the separator used on the local file system. If + * <i>suffix</i> is given and present at the end of <i>file_name</i>, + * it is removed. + * + * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" + * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" + */ + +static VALUE +rb_file_s_basename(int argc, VALUE *argv) +{ + VALUE fname, fext, basename; + const char *name, *p; + long f, n; + + if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { + rb_encoding *enc; + StringValue(fext); + if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) { + rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s", + rb_enc_name(enc)); + } + } + FilePathStringValue(fname); + if (!NIL_P(fext)) rb_enc_check(fname, fext); + if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) + return rb_str_new_shared(fname); + + p = ruby_find_basename(name, &f, &n); + if (n >= 0) { if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) { f = n; } if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname); } + basename = rb_str_new(p, f); rb_enc_copy(basename, fname); OBJ_INFECT(basename, fname); @@ -3573,27 +3592,22 @@ } /* - * call-seq: - * File.extname(path) -> string + * accept a String, and return the pointer of the extension. + * if len is passed, set the length of extension to it. + * returned pointer is in ``name'' or NULL. + * returns *len + * no dot NULL 0 + * dotfile top 0 + * end with dot dot 1 + * .ext dot len of .ext + * .ext:stream dot len of .ext without :stream (NT only) * - * Returns the extension (the portion of file name in <i>path</i> - * after the period). - * - * File.extname("test.rb") #=> ".rb" - * File.extname("a/b/d/test.rb") #=> ".rb" - * File.extname("test") #=> "" - * File.extname(".profile") #=> "" - * */ - -static VALUE -rb_file_s_extname(VALUE klass, VALUE fname) +const char * +ruby_find_extname(const char *name, long *len) { - const char *name, *p, *e; - VALUE extname; + const char *p, *e; - FilePathStringValue(fname); - name = StringValueCStr(fname); p = strrdirsep(name); /* get the last path component */ if (!p) p = name; @@ -3629,9 +3643,46 @@ break; p = CharNext(p); } - if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */ + + if (len) { + /* no dot, or the only dot is first or end? */ + if (!e || e == name) + *len = 0; + else if (e+1 == p) + *len = 1; + else + *len = p - e; + } + return e; +} + +/* + * call-seq: + * File.extname(path) -> string + * + * Returns the extension (the portion of file name in <i>path</i> + * after the period). + * + * File.extname("test.rb") #=> ".rb" + * File.extname("a/b/d/test.rb") #=> ".rb" + * File.extname("test") #=> "" + * File.extname(".profile") #=> "" + * + */ + +static VALUE +rb_file_s_extname(VALUE klass, VALUE fname) +{ + const char *name, *e; + long len; + VALUE extname; + + FilePathStringValue(fname); + name = StringValueCStr(fname); + e = ruby_find_extname(name, &len); + if (len <= 1) return rb_str_new(0, 0); - extname = rb_str_new(e, p - e); /* keep the dot, too! */ + extname = rb_str_new(e, len); /* keep the dot, too! */ rb_enc_copy(extname, fname); OBJ_INFECT(extname, fname); return extname; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/