Skip to content

Commit e3b9424

Browse files
committed
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_1@28522 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 9450c64 commit e3b9424

File tree

5 files changed

+169
-91
lines changed

5 files changed

+169
-91
lines changed

ChangeLog

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
Fri Jul 2 19:07:09 2010 Yuki Sonoda (Yugui) <yugui@yugui.jp>
2+
3+
* io.c (argf_inplace_mode_set): prohibits an assignment
4+
of a tainted value. Patch by unak.
5+
6+
* util.c, file.c: prevents a buffer over-run on windows.
7+
Patch by unak.
8+
19
Wed May 26 13:27:18 2010 Yuki Sonoda (Yugui) <yugui@yugui.jp>
210

311
* random.c: refactoring.

file.c

Lines changed: 103 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,36 +2982,15 @@ rmext(const char *p, int l1, const char *e)
29822982
return 0;
29832983
}
29842984

2985-
/*
2986-
* call-seq:
2987-
* File.basename(file_name [, suffix] ) -> base_name
2988-
*
2989-
* Returns the last component of the filename given in <i>file_name</i>,
2990-
* which must be formed using forward slashes (``<code>/</code>'')
2991-
* regardless of the separator used on the local file system. If
2992-
* <i>suffix</i> is given and present at the end of <i>file_name</i>,
2993-
* it is removed.
2994-
*
2995-
* File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
2996-
* File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
2997-
*/
2998-
2999-
static VALUE
3000-
rb_file_s_basename(int argc, VALUE *argv)
2985+
const char *
2986+
ruby_find_basename(const char *name, long *len, long *ext)
30012987
{
3002-
VALUE fname, fext, basename;
3003-
const char *name, *p;
2988+
const char *p;
30042989
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
30052990
const char *root;
30062991
#endif
3007-
int f, n;
2992+
long f, n = -1;
30082993

3009-
if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
3010-
StringValue(fext);
3011-
}
3012-
FilePathStringValue(fname);
3013-
if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
3014-
return rb_str_new_shared(fname);
30152994
name = skipprefix(name);
30162995
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
30172996
root = name;
@@ -3050,11 +3029,57 @@ rb_file_s_basename(int argc, VALUE *argv)
30503029
#else
30513030
n = chompdirsep(p) - p;
30523031
#endif
3032+
}
3033+
3034+
if (len)
3035+
*len = f;
3036+
if (ext)
3037+
*ext = n;
3038+
return p;
3039+
}
3040+
3041+
/*
3042+
* call-seq:
3043+
* File.basename(file_name [, suffix] ) -> base_name
3044+
*
3045+
* Returns the last component of the filename given in <i>file_name</i>,
3046+
* which must be formed using forward slashes (``<code>/</code>'')
3047+
* regardless of the separator used on the local file system. If
3048+
* <i>suffix</i> is given and present at the end of <i>file_name</i>,
3049+
* it is removed.
3050+
*
3051+
* File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
3052+
* File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
3053+
*/
3054+
3055+
static VALUE
3056+
rb_file_s_basename(int argc, VALUE *argv)
3057+
{
3058+
VALUE fname, fext, basename;
3059+
const char *name, *p;
3060+
long f, n;
3061+
3062+
if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
3063+
rb_encoding *enc;
3064+
StringValue(fext);
3065+
if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) {
3066+
rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s",
3067+
rb_enc_name(enc));
3068+
}
3069+
}
3070+
FilePathStringValue(fname);
3071+
if (!NIL_P(fext)) rb_enc_check(fname, fext);
3072+
if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
3073+
return rb_str_new_shared(fname);
3074+
3075+
p = ruby_find_basename(name, &f, &n);
3076+
if (n >= 0) {
30533077
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
30543078
f = n;
30553079
}
30563080
if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
30573081
}
3082+
30583083
basename = rb_str_new(p, f);
30593084
rb_enc_copy(basename, fname);
30603085
OBJ_INFECT(basename, fname);
@@ -3114,32 +3139,27 @@ rb_file_s_dirname(VALUE klass, VALUE fname)
31143139
}
31153140

31163141
/*
3117-
* call-seq:
3118-
* File.extname(path) -> string
3119-
*
3120-
* Returns the extension (the portion of file name in <i>path</i>
3121-
* after the period).
3122-
*
3123-
* File.extname("test.rb") #=> ".rb"
3124-
* File.extname("a/b/d/test.rb") #=> ".rb"
3125-
* File.extname("test") #=> ""
3126-
* File.extname(".profile") #=> ""
3127-
*
3142+
* accept a String, and return the pointer of the extension.
3143+
* if len is passed, set the length of extension to it.
3144+
* returned pointer is in ``name'' or NULL.
3145+
* returns *len
3146+
* no dot NULL 0
3147+
* dotfile top 0
3148+
* end with dot dot 1
3149+
* .ext dot len of .ext
3150+
* .ext:stream dot len of .ext without :stream (NT only)
3151+
*
31283152
*/
3129-
3130-
static VALUE
3131-
rb_file_s_extname(VALUE klass, VALUE fname)
3153+
const char *
3154+
ruby_find_extname(const char *name, long *len)
31323155
{
3133-
const char *name, *p, *e;
3134-
VALUE extname;
3156+
const char *p, *e;
31353157

3136-
FilePathStringValue(fname);
3137-
name = StringValueCStr(fname);
31383158
p = strrdirsep(name); /* get the last path component */
31393159
if (!p)
31403160
p = name;
31413161
else
3142-
name = ++p;
3162+
do name = ++p; while (isdirsep(*p));
31433163

31443164
e = 0;
31453165
while (*p && *p == '.') p++;
@@ -3170,9 +3190,46 @@ rb_file_s_extname(VALUE klass, VALUE fname)
31703190
break;
31713191
p = CharNext(p);
31723192
}
3173-
if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */
3193+
3194+
if (len) {
3195+
/* no dot, or the only dot is first or end? */
3196+
if (!e || e == name)
3197+
*len = 0;
3198+
else if (e+1 == p)
3199+
*len = 1;
3200+
else
3201+
*len = p - e;
3202+
}
3203+
return e;
3204+
}
3205+
3206+
/*
3207+
* call-seq:
3208+
* File.extname(path) -> string
3209+
*
3210+
* Returns the extension (the portion of file name in <i>path</i>
3211+
* after the period).
3212+
*
3213+
* File.extname("test.rb") #=> ".rb"
3214+
* File.extname("a/b/d/test.rb") #=> ".rb"
3215+
* File.extname("test") #=> ""
3216+
* File.extname(".profile") #=> ""
3217+
*
3218+
*/
3219+
3220+
static VALUE
3221+
rb_file_s_extname(VALUE klass, VALUE fname)
3222+
{
3223+
const char *name, *e;
3224+
long len;
3225+
VALUE extname;
3226+
3227+
FilePathStringValue(fname);
3228+
name = StringValueCStr(fname);
3229+
e = ruby_find_extname(name, &len);
3230+
if (len <= 1)
31743231
return rb_str_new(0, 0);
3175-
extname = rb_str_new(e, p - e); /* keep the dot, too! */
3232+
extname = rb_str_new(e, len); /* keep the dot, too! */
31763233
rb_enc_copy(extname, fname);
31773234
OBJ_INFECT(extname, fname);
31783235
return extname;

io.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8368,6 +8368,9 @@ opt_i_get(ID id, VALUE *var)
83688368
static VALUE
83698369
argf_inplace_mode_set(VALUE argf, VALUE val)
83708370
{
8371+
if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
8372+
rb_raise(rb_eSecurityError, "Insecure operation - ARGF.inplace_mode=");
8373+
83718374
if (!RTEST(val)) {
83728375
if (ARGF.inplace) free(ARGF.inplace);
83738376
ARGF.inplace = 0;

util.c

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -266,70 +266,80 @@ static int valid_filename(const char *s);
266266
static const char suffix1[] = ".$$$";
267267
static const char suffix2[] = ".~~~";
268268

269-
#define ext (&buf[1000])
270-
271269
#define strEQ(s1,s2) (strcmp(s1,s2) == 0)
272270

271+
extern const char *ruby_find_basename(const char *, long *, long *);
272+
extern const char *ruby_find_extname(const char *, long *);
273+
273274
void
274275
ruby_add_suffix(VALUE str, const char *suffix)
275276
{
276277
int baselen;
277278
int extlen = strlen(suffix);
278-
char *s, *t, *p;
279+
char *p, *q;
279280
long slen;
280281
char buf[1024];
282+
const char *name;
283+
const char *ext;
284+
long len;
281285

282-
if (RSTRING_LEN(str) > 1000)
283-
rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
284-
RSTRING_LEN(str));
286+
name = StringValueCStr(str);
287+
slen = strlen(name);
288+
if (slen > sizeof(buf) - 1)
289+
rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
290+
slen);
285291

286-
#if defined(__CYGWIN32__) || defined(_WIN32)
287292
/* Style 0 */
288-
slen = RSTRING_LEN(str);
289293
rb_str_cat(str, suffix, extlen);
290294
if (valid_filename(RSTRING_PTR(str))) return;
291295

292296
/* Fooey, style 0 failed. Fix str before continuing. */
293297
rb_str_resize(str, slen);
294-
#endif
295-
296-
slen = extlen;
297-
t = buf; baselen = 0; s = RSTRING_PTR(str);
298-
while ((*t = *s) && *s != '.') {
299-
baselen++;
300-
if (*s == '\\' || *s == '/') baselen = 0;
301-
s++; t++;
302-
}
303-
p = t;
304-
305-
t = ext; extlen = 0;
306-
while ((*t++ = *s++) != 0) extlen++;
307-
if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
298+
name = StringValueCStr(str);
299+
ext = ruby_find_extname(name, &len);
308300

309301
if (*suffix == '.') { /* Style 1 */
310-
if (strEQ(ext, suffix)) goto fallback;
311-
strcpy(p, suffix);
312-
}
313-
else if (suffix[1] == '\0') { /* Style 2 */
314-
if (extlen < 4) {
315-
ext[extlen] = *suffix;
316-
ext[++extlen] = '\0';
317-
}
318-
else if (baselen < 8) {
319-
*p++ = *suffix;
302+
if (ext) {
303+
if (strEQ(ext, suffix)) goto fallback;
304+
slen = ext - name;
320305
}
321-
else if (ext[3] != *suffix) {
322-
ext[3] = *suffix;
306+
rb_str_resize(str, slen);
307+
rb_str_cat(str, suffix, extlen);
308+
}
309+
else {
310+
strncpy(buf, name, slen);
311+
if (ext)
312+
p = buf + (ext - name);
313+
else
314+
p = buf + slen;
315+
p[len] = '\0';
316+
if (suffix[1] == '\0') { /* Style 2 */
317+
if (len <= 3) {
318+
p[len] = *suffix;
319+
p[++len] = '\0';
320+
}
321+
else if ((q = (char *)ruby_find_basename(buf, &baselen, 0)) &&
322+
baselen < 8) {
323+
q += baselen;
324+
*q++ = *suffix;
325+
if (ext) {
326+
strncpy(q, ext, ext - name);
327+
q[ext - name + 1] = '\0';
328+
}
329+
else
330+
*q = '\0';
331+
}
332+
else if (len == 4 && p[3] != *suffix)
333+
p[3] = *suffix;
334+
else if (baselen == 8 && q[7] != *suffix)
335+
q[7] = *suffix;
336+
else
337+
goto fallback;
323338
}
324-
else if (buf[7] != *suffix) {
325-
buf[7] = *suffix;
339+
else { /* Style 3: Panic */
340+
fallback:
341+
(void)memcpy(p, !ext || strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
326342
}
327-
else goto fallback;
328-
strcpy(p, ext);
329-
}
330-
else { /* Style 3: Panic */
331-
fallback:
332-
(void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
333343
}
334344
rb_str_resize(str, strlen(buf));
335345
memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str));

version.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#define RUBY_VERSION "1.9.1"
2-
#define RUBY_PATCHLEVEL 428
2+
#define RUBY_PATCHLEVEL 429
33
#define RUBY_VERSION_MAJOR 1
44
#define RUBY_VERSION_MINOR 9
55
#define RUBY_VERSION_TEENY 1
66

77
#define RUBY_RELEASE_YEAR 2010
88
#define RUBY_RELEASE_MONTH 7
9-
#define RUBY_RELEASE_DAY 1
10-
#define RUBY_RELEASE_DATE "2010-07-01"
9+
#define RUBY_RELEASE_DAY 2
10+
#define RUBY_RELEASE_DATE "2010-07-02"
1111

1212
#ifdef RUBY_EXTERN
1313
RUBY_EXTERN const char ruby_version[];

0 commit comments

Comments
 (0)