Dear Andy

I've done an analysis of #331060 and come the exact same conclusions as
you did.

The string management overhaul is currently being done upstream.

In the meantime I have attached a patch to #331060 which simply
increases the length of MAX_STR_LEN to 512. This is obviously not a
proper fix but reduces the likelihood of the problem appearing.

Cheers
Andree

On Fri, 2005-10-28 at 11:44 -0400, C. Andy Martin wrote:
> I have observed this bug, too, when increasing my exclusion list length 
> from 275 to 299. Because it's so frustrating I spent some time digging 
> through the source. It didn't take long to locate the cause: poor string 
> management (at least for the Debian package source for 2.04-4, I didn't 
> get the source straight from upstream).
> 
> Here are the relevant lines of code (some are reordered for clarity) 
> with a description of the problems and a calculation on the maximum 
> length string that can be safely passed via the -E switch to 
> mondoarchive at the end:
> 
> from mystuff.h:
> #define MAX_STR_LEN 380
> [snip]
> #define malloc_string(x) { x = malloc(MAX_STR_LEN); if (!x) { 
> fatal_error("Unable to malloc"); } x[0] = x[1] = '\0'; }
> 
> from mondo/common/mondostructures.h:
> 
> struct s_bkpinfo
> {
>   [snip]
>   /**
>    * Directories to NOT back up. Ignored if make_filelist == FALSE.
>    * Multiple directories should be separated by spaces. /tmp, /proc,
>    * the scratchdir, and the tempdir are automatically excluded.
>    */
>   char exclude_paths[MAX_STR_LEN];
>   [snip]
> 
> from mondo/mondoarchive/mondo-cli.c:
> 
>   if (flag_set['E'])
>     {
>       if (bkpinfo->exclude_paths[0])
>         { strcat(bkpinfo->exclude_paths," "); }
>       strncpy (bkpinfo->exclude_paths+strlen(bkpinfo->exclude_paths), 
> flag_val['E'], MAX_STR_LEN - strlen(bkpinfo->exclude_paths));
>     }
>    [snip]
>   if (flag_set['N']) // exclude NFS mounts & devices
>     {
> //      strncpy(psz, list_of_NFS_devices_and_mounts(), MAX_STR_LEN);
>       strncpy(psz, list_of_NFS_mounts_only(), MAX_STR_LEN);
>       if (bkpinfo->exclude_paths[0]) { strncat(bkpinfo->exclude_paths, " 
> ", MAX_STR_LEN); }
>       strncat(bkpinfo->exclude_paths, psz, MAX_STR_LEN);
>       log_msg(3, "-N means we're now excluding %s", bkpinfo->exclude_paths);
>     }
>   if (strlen(bkpinfo->exclude_paths) >= MAX_STR_LEN)
>     {
>       fatal_error("Your '-E' parameter is too long. Please use '-J'. 
> (See manual.)");
>     }
> 
> from mondo/common/libmondo-filelist.c:
> 
> int
> prepare_filelist (struct s_bkpinfo *bkpinfo)
> {
>   [snip]
>       res = mondo_makefilelist(
>      MONDO_LOGFILE, bkpinfo->tmpdir, bkpinfo->scratchdir,
>      bkpinfo->include_paths,
>      bkpinfo->exclude_paths,
>      bkpinfo->differential,
>      NULL);
> 
> [snip]
> int mondo_makefilelist(char*logfile, char*tmpdir, char*scratchdir,
>   char*include_paths, char*excp, int differential, char *userdef_filelist)
> {
>   [snip]
>   char *sz_filelist, *exclude_paths, *tmp;
>   [snip]
>   if (!(exclude_paths = malloc(1000))) { fatal_error("Cannot malloc 
> exclude_paths"); }
>   [snip]
>         sprintf(exclude_paths, " %s %s %s %s %s %s . .. \
> "MNT_CDROM" "MNT_FLOPPY" /media/cdrom /media/cdrecorder \
> /proc /sys /tmp /root/images/mondo /root/images/mindi ",
>     excp,
>     call_program_and_get_last_line_of_output("locate /win386.swp 2> 
> /dev/null"),
>     call_program_and_get_last_line_of_output("locate /hiberfil.sys 2> 
> /dev/null"),
>     call_program_and_get_last_line_of_output("locate /pagefile.sys 2> 
> /dev/null"),
>     (tmpdir[0]=='/' && tmpdir[1]=='/')?(tmpdir+1):tmpdir,
>     (scratchdir[0]=='/' && scratchdir[1]=='/')?(scratchdir+1):scratchdir
>             );
>   log_msg(2, "Excluding paths = '%s'", exclude_paths);
> [snip]
> 
> from mondo/common/libmondo-archive.c:
> int
> call_mindi_to_supply_boot_disks (struct s_bkpinfo *bkpinfo)
> {
>   char *tmp;
>   [snip]
>   malloc_string ( tmp );
>   [snip]
>   sprintf (tmp,
>      "echo \"%s\" | tr -s ' ' '\n' | grep -x \"/dev/.*\" | tr -s '\n' ' 
> ' | awk '{print $0\"\\n\";}'",
>      bkpinfo->exclude_paths);
> [snip]
> 
> 
> OK, so from this code you can see many problems already with the way 
> strings are handled in mondo, especially this exclusion path list string 
> which can be lengthy for some systems. (For instance, we have many 
> directories we exclude from backup because they contain downloads, or 
> other cached elements which don't need to be restored and take up tons 
> of space).
> 
> There are several limits on the size of the exclusion string. The first 
> is MAX_STR_LEN, which here is defined as 380 bytes (379 characters to 
> leave space for the NUL). (This limit applies to the command line 
> parameter + the NFS paths discovered, if the NFS option is enabled but 
> no NFS paths are there, a space is appended). The code checks for 
> overflow on the string (which is bad because the string would have 
> _already_ overflowed!) and prints a fatal error on detection of the 
> condition. Also, later on the exclusion string is amplified internally 
> with a list of known exclusion points (such as /proc in Linux) with an 
> internal limit of 1000 characters. This string is not protected from 
> overflow at all, so we must hope the extra appended stuff is less than 
> 1000-380=620 bytes (which proves true on my machine in my configuration, 
> but...). The real kicker is when mindi is run, the 'tmp' string used to 
> construct the command is limited also to 380 bytes, but contains the 
> _entire_ exclusion path as an argument. This causes a buffer overflow 
> here if the command string plus the length of the exclusion path is 
> greater than 379 (which could readily be fixed by using a longer 
> temporary). The extra length of the command is 83 characters, leaving a 
> safe length on the command line of 296 (380-9-1 for the NUL terminator). 
> If the NFS option is specified, this length is reduced by at least 1, 
> more if NFS paths are found. As you can see, when I expanded my 
> exclusion list from 275 to 299 characters I crossed this limit, and that 
> is why the program segfaulted on mindi execution.
> 
> Note: the '-J' switch printed above in the code is not very useful for 
> _excluding_ paths, as it must be a list of all paths and files to 
> _include_ (which means a script of program such as 'find' would need to 
> be used to list all paths that are desired to backup while excluding the 
> ones not desired).
> 
> This should be enough information to forward to upstream to get at least 
> the nasty mindi bug mentioned fixed. Obviously, there are many other 
> potential buffer overflows here. The string management code could use an 
> overhaul.
> 
> -Andy
> 
-- 
Andree Leidenfrost
Sydney - Australia

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to