[Bug 9798] rsync crash with SIGSEGV when read time out happens

samba-bugs at samba.org samba-bugs at samba.org
Mon Apr 22 09:26:41 MDT 2013


https://bugzilla.samba.org/show_bug.cgi?id=9798

--- Comment #2 from Vijay Nag <vijunag at gmail.com> 2013-04-22 15:26:41 UTC ---
(In reply to comment #1)
> Please retry with a current version of rsync. Your 3.0.2 version is 5 years
> old.

Crash is observed in the latest rsync. I checked the diff with the latest one
and
with 3.0.2

I think rsync is not handling EILSEQ error returned by iconv(3). Here are
couple of observations.

1>
 while (icnt) {
    retVal = -1;
    while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1 || retVal == -1)
{
      errno = EILSEQ;
      if (errno == EINTR)
        continue;
      if (errno == EINVAL) {
        if (!(flags & ICB_INCLUDE_INCOMPLETE))
          goto finish;
      } else if (errno == EILSEQ) {
        if (!(flags & ICB_INCLUDE_BAD))
          goto finish;
      } else {
        size_t opos = obuf - out->buf;
        if (!(flags & ICB_EXPAND_OUT)) {
          errno = E2BIG;
          goto finish;
        }
        realloc_xbuf(out, out->size + 1024);
        obuf = out->buf + opos;
        ocnt += 1024;
        continue;
      }
      *obuf++ = *ibuf++;
      ocnt--, icnt--;
    }
  }

The condition checking "while(icnt)" is bad since icnt is size_t and there were
cases where icnt had wrapped causing it to crash.

2>
   while (inbuf.len) {                      
      iconvbufs(ic, &inbuf, &outbuf, 0);                 
      ierrno = errno;
      if (outbuf.len) {  
        filtered_fwrite(f, convbuf, outbuf.len, 0);
        outbuf.len = 0;
      }              
      if (!ierrno || ierrno == E2BIG)
        continue;                          
      fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
      inbuf.len--;        
      save_len = inbuf.len;   
    }                           


Lets assume iconvbufs is returning EILSEQ continuously there are
chances of "inbuf.len"  wrapping again when inbuf.len reaches zero.
so again the "while(inbuf.len)" starts iterating from (size_t)-1 which is
0xffffff. This can lead to a crash again.

Best way to do this check is to save the (size_t)len to an integer and have
the while check "0 < save_len". This will make sure that inbuf.len can never
wrap. Let me know if it is plausible so that i can give you a patch. I have
tested it and it works.

+  int save_len = len;                                                     

    INIT_CONST_XBUF(outbuf, convbuf);                                        
    INIT_XBUF(inbuf, (char*)buf, len, -1);                                 

 -while(inbuf.len)                                                              
+    while (0 < save_len) {                      
      iconvbufs(ic, &inbuf, &outbuf, 0);                 
      ierrno = errno;
      if (outbuf.len) {  
        filtered_fwrite(f, convbuf, outbuf.len, 0);
        outbuf.len = 0;
      }              
      if (!ierrno || ierrno == E2BIG)
        continue;                          
      fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
      inbuf.len--;        
      save_len = inbuf.len;   
    }

-- 
Configure bugmail: https://bugzilla.samba.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.


More information about the rsync mailing list