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
--
C. Andy Martin (BSCS, BSEE)
Senior Engineer
Lumenware, LLC
A161A ASTeCC Building
University of Kentucky
Lexington, KY 40506-0286
859/257-2300 x225
859/257-2489 (fax)
[EMAIL PROTECTED]
http://www.lumenware.com/
--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]