bin/112775: libmd(3) bug for some zero-length files

Bruce Evans bde at
Sun May 20 15:40:08 UTC 2007

The following reply was made to PR kern/112775; it has been noted by GNATS.

From: Bruce Evans <bde at>
To: Ighighi <ighighi at>
Cc: freebsd-gnats-submit at, freebsd-bugs at
Subject: Re: bin/112775: libmd(3) bug for some zero-length files
Date: Sat, 19 May 2007 16:52:34 +1000 (EST)

 On Sat, 19 May 2007, Ighighi wrote:
 >> Description:
 > A bug was introduced into version 1.14 of src/lib/libmd/mdXhl.c that prevents any application using the libmd(3) functions {MD4,MD5,SHA_,SHA1_,SHA256_}File() from correctly processing zero-length files on filesystems such as procfs(5).
 Please keep line lengths considerably shorter than 235 characters.
 I've been waiting for many years for the author of the bug to fix this.
 Not just the irregular regular zero-length files in procfs are broken
 -- all files for which stat(2) doesn't report the file size are broken.
 This includes all device files, and pipes.  For pipes, the bug is
 normally not visible, since pipes are normally accessed via stdin and
 then there is no filename on the command line so md5(1) uses its private
 routine MDFilter() which is missing the bug.  The bug affects stdin too
 if stdin is accessed by name (/dev/stdin or /dev/fd/0), at least when
 /dev/stdin is actually a device on devfs.  I'm not sure what happens when
 /dev/stdin is on fdescfs.
 >> How-To-Repeat:
 > $ /sbin/md5 /proc/1/cmdline
 > MD5 (/proc/1/cmdline) = d41d8cd98f00b204e9800998ecf8427e
 > $ /bin/cat /proc/1/cmdline | /sbin/md5
 > 8624f652bec9bf7d9376dca7ea02a6b5
 Piping the file as in the second command here is a workaround for most cases.
 >> Fix:
 > --- lib/libmd/mdXhl.c.orig	Sun Sep  8 11:10:04 2002
 > +++ lib/libmd/mdXhl.c	Sat May 19 00:04:24 2007
 > @@ -43,7 +43,22 @@
 > char *
 > MDXFile(const char *filename, char *buf)
 > {
 > -	return (MDXFileChunk(filename, buf, 0, 0));
 > +	unsigned char buffer[BUFSIZ];
 > +	MDX_CTX ctx;
 > +	int f, i, j;
 > +
 > +	MDXInit(&ctx);
 > +	f = open(filename, O_RDONLY);
 > +	if (f < 0)
 > +		return 0;
 > +	while ((i = read(f, buffer, sizeof(buffer))) > 0)
 > +		MDXUpdate(&ctx, buffer, i);
 > +	j = errno;
 > +	close(f);
 > +	errno = j;
 > +	if (i < 0)
 > +		return 0;
 > +	return MDXEnd(&ctx, buf);
 > }
 > char *
 This gives some duplication and leaves MDXFileChunk() unusuable.  Callers
 of MDFileChunk() would have to either distrust MDXFileChunk() and never
 call it, or call it and actually check for errors and decide which errors
 are actually bugs in MDXFileChunk(), and work around the bugs...
 Error handling is currently almost nonexistent.  MDXFileChunk() and
 the above return NULL (spelled as 0) on error, but md5(1) never checks
 for errors.  These routines at least distinguish between error and EOF.
 The private MDFilter() doesn't even do that.
 There is a minor API problem for handling the non-errors of EAGAIN and
 EINTR.  If the application allows these (via non-blocking reads or
 non-restarted syscalls after a signal), then it probably wants to
 restart checksumming.  MDXFileChunk() provides a way, but only for
 seekable files with a valid non-volatile size.  MDXFile() would have
 to restart from the beginning, so it cannot work for pipes would take
 too long or never complete for large regular files.  The restart needs
 to be in the read loop to handle pipes, but restarting is not always
 the correct handling, so the API would need a flag to control the
 restart.  The stdio API has the same bug.

More information about the freebsd-bugs mailing list