Bug 30631 - readdir_r() SEGV on large directories
Summary: readdir_r() SEGV on large directories
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: misc (show other bugs)
Version: 4.2-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2001-09-17 16:40 UTC by Jim Bauer
Modified: 2002-02-26 22:59 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jim Bauer 2001-09-17 16:40:00 UTC
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);
  }

}
Comment 1 Jim Bauer 2001-09-17 19:21:48 UTC
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
Comment 2 Kris Kennaway 2001-09-24 00:47:50 UTC
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
Comment 3 Carlos Paniago 2001-10-23 14:48:43 UTC
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
Comment 4 Carlos Paniago 2001-10-24 13:38:20 UTC
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
Comment 5 Carlos Paniago 2002-01-11 21:08:14 UTC
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/
--
Comment 6 Martin Blapp freebsd_committer freebsd_triage 2002-02-26 22:58:28 UTC
State Changed
From-To: open->closed

The fix has been comitted to both STABLE and CURRENT. 

Thanks !