Skip to content
Browse files

readdir: fix interface to kernel getdents64 function

Issue:
  The kernel will pad the entry->d_reclen in a getdents64 call to a
  long-word boundary.  For very long records, this could exceed the
  size of a struct dirent. The mismatch in the size was causing error
  paranoid checking code in bionic to fail... thus causing an early
  "end" when reading the dirent structures from the kernel buffer.

Test:
 ls
 mkdir abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu
 ls

Change-Id: I75d1f8e45e1655fdd7bac4a08a481d086f28073a
Author: Bruce Beare <bruce.j.beare@intel.com>
  • Loading branch information...
1 parent c2d5944 commit a37f3729730e4e7345977915d67adc3eea93dfe4 Bruce Beare committed with Jean-Baptiste Queru Aug 2, 2011
Showing with 10 additions and 4 deletions.
  1. +10 −4 libc/unistd/opendir.c
View
14 libc/unistd/opendir.c
@@ -92,6 +92,9 @@ static struct dirent*
_readdir_unlocked(DIR* dir)
{
struct dirent* entry;
+#ifndef NDEBUG
+ unsigned reclen;
+#endif
if ( !dir->_DIR_avail )
{
@@ -115,15 +118,18 @@ _readdir_unlocked(DIR* dir)
if (((long)(void*)entry & 3) != 0)
return NULL;
- if ( (unsigned)entry->d_reclen > sizeof(*entry) ||
- entry->d_reclen <= offsetof(struct dirent, d_name) )
+#ifndef NDEBUG
+ // paranoid testing of the interface with the kernel getdents64 system call
+ reclen = offsetof(struct dirent, d_name) + strlen(entry->d_name) + 1;
+ if ( reclen > sizeof(*entry) || reclen <= offsetof(struct dirent, d_name) )
goto Bad;
- if ( (char*)entry + entry->d_reclen > (char*)dir->_DIR_buff + sizeof(dir->_DIR_buff) )
+ if ( (char*)entry + reclen > (char*)dir->_DIR_buff + sizeof(dir->_DIR_buff) )
goto Bad;
- if ( !memchr( entry->d_name, 0, entry->d_reclen - offsetof(struct dirent, d_name)) )
+ if ( !memchr( entry->d_name, 0, reclen - offsetof(struct dirent, d_name)) )
goto Bad;
+#endif
dir->_DIR_next = (struct dirent*)((char*)entry + entry->d_reclen);
dir->_DIR_avail -= entry->d_reclen;

0 comments on commit a37f372

Please sign in to comment.
Something went wrong with that request. Please try again.