summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-12-07 04:11:26 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-12-07 04:11:26 +0000
commit1c2ef610358af33f9ded3086aa2d70aac03dcac5 (patch)
tree1b3ab2601cbf1d3a75a5bf4b3d2181d905d09704 /string.c
parent753de85e40bf400f4cabeee07ab6923bb6e466b9 (diff)
* string.c (rb_str_justify): CVE-2009-4124.
Fixes a bug reported by Emmanouel Kellinis <Emmanouel.Kellinis AT kpmg.co.uk>, KPMG London; Patch by nobu. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26038 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/string.c b/string.c
index a722ac14b0..804513e4ef 100644
--- a/string.c
+++ b/string.c
@@ -6593,7 +6593,7 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
VALUE res;
char *p;
const char *f = " ";
- long n, llen, rlen;
+ long n, size, llen, rlen, llen2 = 0, rlen2 = 0;
volatile VALUE pad;
int singlebyte = 1, cr;
@@ -6617,44 +6617,49 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2);
rlen = n - llen;
cr = ENC_CODERANGE(str);
- res = rb_str_new5(str, 0, RSTRING_LEN(str)+n*flen/fclen+2);
+ if (flen > 1) {
+ llen2 = str_offset(f, f + flen, llen % fclen, enc, singlebyte);
+ rlen2 = str_offset(f, f + flen, rlen % fclen, enc, singlebyte);
+ }
+ size = RSTRING_LEN(str);
+ if ((len = llen / fclen + rlen / fclen) >= LONG_MAX / flen ||
+ (len *= flen) >= LONG_MAX - llen2 - rlen2 ||
+ (len += llen2 + rlen2) >= LONG_MAX - size) {
+ rb_raise(rb_eArgError, "argument too big");
+ }
+ len += size;
+ res = rb_str_new5(str, 0, len);
p = RSTRING_PTR(res);
- while (llen) {
- if (flen <= 1) {
- *p++ = *f;
- llen--;
- }
- else if (llen > fclen) {
+ if (flen <= 1) {
+ memset(p, *f, llen);
+ p += llen;
+ }
+ else {
+ while (llen > fclen) {
memcpy(p,f,flen);
p += flen;
llen -= fclen;
}
- else {
- char *fp = str_nth(f, f+flen, llen, enc, singlebyte);
- n = fp - f;
- memcpy(p,f,n);
- p+=n;
- break;
+ if (llen > 0) {
+ memcpy(p, f, llen2);
+ p += llen2;
}
}
- memcpy(p, RSTRING_PTR(str), RSTRING_LEN(str));
- p+=RSTRING_LEN(str);
- while (rlen) {
- if (flen <= 1) {
- *p++ = *f;
- rlen--;
- }
- else if (rlen > fclen) {
+ memcpy(p, RSTRING_PTR(str), size);
+ p += size;
+ if (flen <= 1) {
+ memset(p, *f, rlen);
+ p += rlen;
+ }
+ else {
+ while (rlen > fclen) {
memcpy(p,f,flen);
p += flen;
rlen -= fclen;
}
- else {
- char *fp = str_nth(f, f+flen, rlen, enc, singlebyte);
- n = fp - f;
- memcpy(p,f,n);
- p+=n;
- break;
+ if (rlen > 0) {
+ memcpy(p, f, rlen2);
+ p += rlen2;
}
}
*p = '\0';