1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

CVE-2013-4237, BZ #14699: Buffer overflow in readdir_r

* sysdeps/posix/dirstream.h (struct __dirstream): Add errcode
	member.
	* sysdeps/posix/opendir.c (__alloc_dir): Initialize errcode
	member.
	* sysdeps/posix/rewinddir.c (rewinddir): Reset errcode member.
	* sysdeps/posix/readdir_r.c (__READDIR_R): Enforce NAME_MAX limit.
	Return delayed error code.  Remove GETDENTS_64BIT_ALIGNED
	conditional.
	* sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c: Do not define
	GETDENTS_64BIT_ALIGNED.
	* sysdeps/unix/sysv/linux/i386/readdir64_r.c: Likewise.
	* manual/filesys.texi (Reading/Closing Directory): Document
	ENAMETOOLONG return value of readdir_r.  Recommend readdir more
	strongly.
	* manual/conf.texi (Limits for Files): Add portability note to
	NAME_MAX, PATH_MAX.
	(Pathconf): Add portability note for _PC_NAME_MAX, _PC_PATH_MAX.
This commit is contained in:
Florian Weimer
2013-08-16 09:38:52 +02:00
parent ca0a6bc4c5
commit 91ce40854d
10 changed files with 124 additions and 35 deletions

View File

@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
DIRENT_TYPE *dp;
size_t reclen;
const int saved_errno = errno;
int ret;
__libc_lock_lock (dirp->lock);
@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
bytes = 0;
__set_errno (saved_errno);
}
if (bytes < 0)
dirp->errcode = errno;
dp = NULL;
/* Reclen != 0 signals that an error occurred. */
reclen = bytes != 0;
break;
}
dirp->size = (size_t) bytes;
@ -106,29 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
dirp->filepos += reclen;
#endif
/* Skip deleted files. */
#ifdef NAME_MAX
if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
{
/* The record is very long. It could still fit into the
caller-supplied buffer if we can skip padding at the
end. */
size_t namelen = _D_EXACT_NAMLEN (dp);
if (namelen <= NAME_MAX)
reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
else
{
/* The name is too long. Ignore this file. */
dirp->errcode = ENAMETOOLONG;
dp->d_ino = 0;
continue;
}
}
#endif
/* Skip deleted and ignored files. */
}
while (dp->d_ino == 0);
if (dp != NULL)
{
#ifdef GETDENTS_64BIT_ALIGNED
/* The d_reclen value might include padding which is not part of
the DIRENT_TYPE data structure. */
reclen = MIN (reclen,
offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name));
#endif
*result = memcpy (entry, dp, reclen);
#ifdef GETDENTS_64BIT_ALIGNED
#ifdef _DIRENT_HAVE_D_RECLEN
entry->d_reclen = reclen;
#endif
ret = 0;
}
else
*result = NULL;
{
*result = NULL;
ret = dirp->errcode;
}
__libc_lock_unlock (dirp->lock);
return dp != NULL ? 0 : reclen ? errno : 0;
return ret;
}
#ifdef __READDIR_R_ALIAS