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>
This commit is contained in:
parent
c2d5944e19
commit
a37f372973
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user