DO NOT REPLY [Bug 5075] New: Syncing with --iconv may yield protocol error

samba-bugs at samba.org samba-bugs at samba.org
Mon Nov 12 06:06:01 GMT 2007


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

           Summary: Syncing with --iconv may yield protocol error
           Product: rsync
           Version: 3.0.0
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P3
         Component: core
        AssignedTo: wayned at samba.org
        ReportedBy: lennart.samba at lovstrand.com
         QAContact: rsync-qa at samba.org


If you use --iconv to sync between two machines and a file with a name that
needs conversion is to be deleted, the rsync protocol may get out of sync and
yield a protocol error if the converted filename differs in length form the
unconverted name.  This is because mplex_write in io.c will record and send the
message length *before* the message has been converted using iconvbuf.  If the
converted message differs in length, the reading rsync process will get
confused and interpret part of the message data as tag & length.

Here is an example:

[21:45:27]lenux:~/Mirror$ rsync -a --progress --del -n --iconv=utf-8,utf-8-mac
Lennart/Auto/ sva:Mirror/Lennart/Auto/
sending incremental file list
Audi Cabrio 92 (CUB931)/D\#303\#244ck/
deleting Audi Cabrio 92 (CUB931)/D\#303\#244ck/www.stro.nu.url.URL\#001
unexpected tag -7 [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(1135)
[sender=3.0.0pre5]

(Note the garbage #\001 at the end of the filename.)

To fix this, mplex_write needs to convert the message data before sending its
length.  Here is a possible rewrite:

/* Write an message to a multiplexed stream. If this fails, rsync exits. */
static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len,
int convert)
{
        char buffer[BIGPATHBUFLEN]; /* Oversized for use by iconv code. */
        size_t n = len;

#ifdef ICONV_OPTION
        if (convert && ic_send == (iconv_t)-1)
#endif
                convert = 0;

#ifdef ICONV_OPTION
        /* We need to convert buf before doing anything else so that we
         * can include the (converted) byte length in the message header.
         */
        if (convert) {
                xbuf outbuf, inbuf;

                INIT_XBUF(outbuf, buffer + 4, 0, sizeof(buffer) - 4);
                INIT_XBUF(inbuf, (char*)buf, len, -1);

                iconvbufs(ic_send, &inbuf, &outbuf,
                                  ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);

                if (inbuf.len > 0) {
                        rprintf(FERROR, "conversion buffer overflow in
mplex_write; "
                                        "either enlarge 'buffer' or rewrite
code to allocate "
                                        "buffer dynamically");
                }

                n = len = outbuf.len;
        } else
#endif
        if (n > sizeof(buffer) - 4)
                n = 0;
        else
                memcpy(buffer + 4, buf, n);

        SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);


        defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
        writefd_unbuffered(fd, buffer, n+4);
        defer_forwarding_keep = 0;

        len -= n;
        buf += n;

        if (len)
                writefd_unbuffered(fd, buf, len);

        if (!--defer_forwarding_messages && !no_flush)
                msg_flush();
}

Context diff based on 3.0.0pre5 follows:

*** io.c~       Sat Nov  3 00:20:05 2007
--- io.c        Sun Nov 11 21:59:57 2007
***************
*** 468,485 ****
        char buffer[BIGPATHBUFLEN]; /* Oversized for use by iconv code. */
        size_t n = len;

-       SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
- 
  #ifdef ICONV_OPTION
        if (convert && ic_send == (iconv_t)-1)
  #endif
                convert = 0;

!       if (convert || n > 1024 - 4) /* BIGPATHBUFLEN can handle 1024 bytes */
                n = 0;
        else
                memcpy(buffer + 4, buf, n);

        defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
        writefd_unbuffered(fd, buffer, n+4);
        defer_forwarding_keep = 0;
--- 468,508 ----
        char buffer[BIGPATHBUFLEN]; /* Oversized for use by iconv code. */
        size_t n = len;

  #ifdef ICONV_OPTION
        if (convert && ic_send == (iconv_t)-1)
  #endif
                convert = 0;

! #ifdef ICONV_OPTION
!       /* We need to convert buf before doing anything else so that we
!        * can include the (converted) byte length in the message header.
!        */
!       if (convert) {
!               xbuf outbuf, inbuf;
! 
!               INIT_XBUF(outbuf, buffer + 4, 0, sizeof(buffer) - 4);
!               INIT_XBUF(inbuf, (char*)buf, len, -1);
! 
!               iconvbufs(ic_send, &inbuf, &outbuf,
!                                 ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
! 
!               if (inbuf.len > 0) {
!                       rprintf(FERROR, "conversion buffer overflow in
mplex_write; "
!                                       "either enlarge 'buffer' or rewrite
code to allocate "
!                                       "buffer dynamically");
!               }
! 
!               n = len = outbuf.len;
!       } else
! #endif
!       if (n > sizeof(buffer) - 4)
                n = 0;
        else
                memcpy(buffer + 4, buf, n);

+       SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
+ 
+ 
        defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
        writefd_unbuffered(fd, buffer, n+4);
        defer_forwarding_keep = 0;
***************
*** 487,506 ****
        len -= n;
        buf += n;

- #ifdef ICONV_OPTION
-       if (convert) {
-               xbuf outbuf, inbuf;
- 
-               INIT_CONST_XBUF(outbuf, buffer);
-               INIT_XBUF(inbuf, (char*)buf, len, -1);
- 
-               do {
-                       iconvbufs(ic_send, &inbuf, &outbuf,
-                                 ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
-                       writefd_unbuffered(fd, outbuf.buf, outbuf.len);
-               } while (inbuf.len);
-       } else
- #endif
        if (len)
                writefd_unbuffered(fd, buf, 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, or are watching the QA contact.


More information about the rsync mailing list