Work around Linux libc overflow in mmap64

The mmap64 functions in all Linux libc fail to properly check that the
value fits in the system call parameter. I guess the developers just
said "16 PB are enough for everyone"...

Change-Id: Ic39b2c4fd9c84522a8fafffd14ac91567ce09c09
Reviewed-by: Sami Nurmenniemi <sami.nurmenniemi@qt.io>
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
Thiago Macieira 2017-03-16 21:36:17 -07:00
parent cdaea16964
commit 4ee7425794
1 changed files with 14 additions and 1 deletions

View File

@ -688,6 +688,19 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
#if (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && Q_PROCESSOR_WORDSIZE == 4
// The Linux mmap2 system call on 32-bit takes a page-shifted 32-bit
// integer so the maximum offset is 1 << (32+12) (the shift is always 12,
// regardless of the actual page size). Unfortunately, the mmap64()
// function is known to be broken in all Linux libcs (glibc, uclibc, musl
// and Bionic): all of them do the right shift, but don't confirm that the
// result fits into the 32-bit parameter to the kernel.
static qint64 MaxFileOffset = (Q_INT64_C(1) << (32+12)) - 1;
#else
static qint64 MaxFileOffset = std::numeric_limits<QT_OFF_T>::max();
#endif
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QIODevice::NotOpen) {
@ -695,7 +708,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
return 0;
}
if (offset < 0 || offset != qint64(QT_OFF_T(offset))
if (offset < 0 || offset > MaxFileOffset
|| size < 0 || quint64(size) > quint64(size_t(-1))) {
q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
return 0;