Under some circumstances, readdir_r() tries to memcpy too much data from the buffer opendir() malloced thus reading beyond the end of the buffer. The problem only seems to occur if "-pthread" is given on the compile command line. Fix: Changing the memcpy() in readdir_r() to only copy d_namlen bytes instead of sizeof(struct dirent) should fix the problem, but this has not been tested. How-To-Repeat: /* * To repeat: * cc .... -pthread * * d="d.$$"; mkdir $d * i=1; while [ $i -lt 245 ]; do touch $d/f.$i; i=`expr $i + 1`; done * * ./a.out $d * * When I run this it outputs.... * file = f.1 * file = f.2 * ... * file = f.240 * Segmentation fault (core dumped) */ #include <stdio.h> #include <dirent.h> int main(int argc, char **argv) { DIR *dir; struct dirent entry; struct dirent *result; char *dirname = "."; if (argc > 2) { fprintf(stderr, "Usage %s [dir]\n", argv[0]); exit(1); } if (argc == 2) dirname = argv[1]; dir = opendir(dirname); if (dir == NULL) { perror("opendir"); exit(1); } while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { printf("file = %s\n", entry.d_name); } }
Correction to suggested fix. memcpy(entry, dp, (unsigned) &dp->d_name - (unsigned)dp + dp->d_namlen + 1); -- Jim Bauer, jfbauer@nfr.com NFR Security, Inc. 240-747-3405
On Mon, Sep 17, 2001 at 11:30:04AM -0700, Jim Bauer wrote: > The following reply was made to PR misc/30631; it has been noted by GNATS. > > From: Jim Bauer <jfbauer@nfr.com> > To: freebsd-gnats-submit@FreeBSD.org, jfbauer@nfr.com > Cc: > Subject: Re: misc/30631: readdir_r() SEGV on large directories > Date: Mon, 17 Sep 2001 14:21:48 -0400 > > Correction to suggested fix. > > memcpy(entry, dp, (unsigned) &dp->d_name - (unsigned)dp + dp->d_namlen > + 1); Please submit an updated patch. Kris
This behavior (bug) still in FreebSD 4.4. It's is dumping core in svtest, part of openoffice. Please someone look at that and fix it. Paniago
I traced the problem . The problem occurs only with -pthread library (not the normal libc). The problem is to memcpy the structure memcpy(entry, dp, sizeof *entry); in the pthread library sometimes dp doen't have the correct size (I don't know why or where this is happening). I know that if we change this to memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); it begins to work (and we cut a lot of unnecessary copy in this ugly struct that is dirent). The patch to solve this is here (someone have to test and apply): in the /usr/src directory: ------------ diff -c lib/libc/gen/readdir.c.old lib/libc/gen/readdir.c *** lib/libc/gen/readdir.c.old Wed Oct 24 10:21:17 2001 --- lib/libc/gen/readdir.c Wed Oct 24 10:23:35 2001 *************** *** 111,117 **** errno = saved_errno; if (dp != NULL) ! memcpy(entry, dp, sizeof *entry); #ifdef _THREAD_SAFE _FD_UNLOCK(dirp->dd_fd, FD_READ); --- 111,117 ---- errno = saved_errno; if (dp != NULL) ! memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); #ifdef _THREAD_SAFE _FD_UNLOCK(dirp->dd_fd, FD_READ); ------------- Thanks for fixing this: Paniago
Hi, could some one fix the patch that I send to this list? Until now in FreeBSD 4.5 RC1 this bug still present If the patch is applied it pass the test of this issue. Paniago -- Nome: Carlos Fernando Assis Paniago Email: pan@panix.ecof.org.br e pan@cnpm.embrapa.br Web: http://www.panix.ecof.org.br/ e http://www.cnpm.embrapa.br/ --
State Changed From-To: open->closed The fix has been comitted to both STABLE and CURRENT. Thanks !