Bug 7869 - rsync segfault
Summary: rsync segfault
Status: RESOLVED FIXED
Alias: None
Product: rsync
Classification: Unclassified
Component: core (show other bugs)
Version: 3.0.7
Hardware: x64 Linux
: P3 minor (vote)
Target Milestone: ---
Assignee: Wayne Davison
QA Contact: Rsync QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-15 11:36 UTC by Rafael Silva
Modified: 2010-12-17 00:34 UTC (History)
0 users

See Also:


Attachments
core dumped for rsync (444.00 KB, application/octet-stream)
2010-12-15 13:28 UTC, Rafael Silva
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Rafael Silva 2010-12-15 11:36:21 UTC
Hi,
In my analysis (fuzzing) i find a fancy bug in rsync.

Linux bengbeng 2.6.32-26-generic #48-Ubuntu SMP Wed Nov 24 10:14:11 UTC 2010 x86_64 GNU/Linux

The Bug:

$ rsync --backup-dir=`perl -e 'print "A"x22222;'` 
Segmentation fault

$ rsync --backup-dir=`perl -e 'print "1"x22222;'` 
Segmentation fault

Cheers.
Comment 1 Paul Slootman 2010-12-15 13:16:23 UTC
Are you sure that the segmentation violation was in rsync, and not e.g. in the shell used to execute the backticks? Please provide a backtrace of the core dump.

I can't reproduce it on my system, I just get the usage message due to incomplete arguments.
Comment 2 Rafael Silva 2010-12-15 13:28:36 UTC
Created attachment 6132 [details]
core dumped for rsync
Comment 3 Matt McCutchen 2010-12-15 13:32:25 UTC
I see what is happening.  options.c:1496:

backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
if (backup_dir_remainder < 32) {
        snprintf(err_buf, sizeof err_buf,
                "the --backup-dir path is WAY too long.\n");
        return 0;
}

But backup_dir_remainder is unsigned, so the subtraction overflows and the error message does not trip.
Comment 4 Jordan Russell 2010-12-15 14:01:15 UTC
There's also potential for a one-off overflow here:

  } else if (backup_dir_buf[backup_dir_len - 1] != '/') {
          backup_dir_buf[backup_dir_len++] = '/';
          backup_dir_buf[backup_dir_len] = '\0';
  }

backup_dir_len is incremented, but there is no corresponding decrement of backup_dir_remainder.
Comment 5 Paul Slootman 2010-12-15 15:14:08 UTC
(In reply to comment #3)
> I see what is happening.  options.c:1496:
> 
> backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
> if (backup_dir_remainder < 32) {
>         snprintf(err_buf, sizeof err_buf,
>                 "the --backup-dir path is WAY too long.\n");
>         return 0;
> }
> 
> But backup_dir_remainder is unsigned, so the subtraction overflows and the
> error message does not trip.

I would have expected strlcpy() to limit the return value to the bufsize passed as last argument, but at least the lib/compat.c version doesn't, and contradicts the comments there in doing so ("@return index of the terminating byte"). If it had done that, it would have limited the result of the subtraction to >= 0.
Comment 6 Paul Slootman 2010-12-15 15:17:03 UTC
(In reply to comment #2)
> Created an attachment (id=6132) [details]
> core dumped for rsync

A coredump from your system is pretty useless for anyone else. That's why I asked for the backtrace from that coredump. However Matt has spotted the problem already.

Amusingly 'file core' says:

core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from '111111111111111'

Note how apparently argv[0] got overwritten as well.
Comment 7 Wayne Davison 2010-12-17 00:34:44 UTC
Fix committed to git for both the crashing overflow and the off-by-one issue.