Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP5:GA
p7zip
CVE-2023-52168.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2023-52168.patch of Package p7zip
Index: b/CPP/7zip/Archive/NtfsHandler.cpp =================================================================== --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -59,6 +59,7 @@ struct CHeader { Byte SectorSizeLog; Byte ClusterSizeLog; + unsigned MftRecordSizeLog; // Byte MediaType; UInt32 NumHiddenSectors; UInt64 NumClusters; @@ -138,11 +139,44 @@ bool CHeader::Parse(const Byte *p) G64(p + 0x30, MftCluster); // G64(p + 0x38, Mft2Cluster); G64(p + 0x48, SerialNumber); - UInt32 numClustersInMftRec; - UInt32 numClustersInIndexBlock; - G32(p + 0x40, numClustersInMftRec); - G32(p + 0x44, numClustersInIndexBlock); - return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256); + + /* + numClusters_per_MftRecord: + numClusters_per_IndexBlock: + only low byte from 4 bytes is used. Another 3 high bytes are zeros. + If the number is positive (number < 0x80), + then it represents the number of clusters. + If the number is negative (number >= 0x80), + then the size of the file record is 2 raised to the absolute value of this number. + example: (0xF6 == -10) means 2^10 = 1024 bytes. + */ + { + UInt32 numClusters_per_MftRecord; + G32(p + 0x40, numClusters_per_MftRecord); + if (numClusters_per_MftRecord >= 0x100 || numClusters_per_MftRecord == 0) + return false; + if (numClusters_per_MftRecord < 0x80) + { + const int t = GetLog(numClusters_per_MftRecord); + if (t < 0) + return false; + MftRecordSizeLog = (unsigned)t + ClusterSizeLog; + } + else + MftRecordSizeLog = 0x100 - numClusters_per_MftRecord; + // what exact MFT record sizes are possible and supported by Windows? + // do we need to change this limit here? + const unsigned k_MftRecordSizeLog_MAX = 12; + if (MftRecordSizeLog > k_MftRecordSizeLog_MAX) + return false; + if (MftRecordSizeLog < SectorSizeLog) + return false; + } + { + UInt32 numClusters_per_IndexBlock; + G32(p + 0x44, numClusters_per_IndexBlock); + return (numClusters_per_IndexBlock < 0x100); + } } struct CMftRef @@ -1266,20 +1300,22 @@ HRESULT CDatabase::Open() SeekToCluster(Header.MftCluster); - CMftRec mftRec; - UInt32 numSectorsInRec; - int recSizeLog; + // we use ByteBuf for records reading. + // so the size of ByteBuf must be >= mftRecordSize + const size_t recSize = (size_t)1 << Header.MftRecordSizeLog; + const size_t kBufSize = MyMax((size_t)(1 << 15), recSize); + ByteBuf.SetCapacity(kBufSize); + RINOK(ReadStream_FALSE(InStream, ByteBuf, recSize)) + { + const UInt32 allocSize = Get32(ByteBuf + 0x1C); + if (allocSize != recSize) + return S_FALSE; + } + // MftRecordSizeLog >= SectorSizeLog + const UInt32 numSectorsInRec = 1u << (Header.MftRecordSizeLog - Header.SectorSizeLog); CMyComPtr<IInStream> mftStream; + CMftRec mftRec; { - UInt32 blockSize = 1 << 12; - ByteBuf.SetCapacity(blockSize); - RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); - - UInt32 allocSize = Get32(ByteBuf + 0x1C); - recSizeLog = GetLog(allocSize); - if (recSizeLog < Header.SectorSizeLog) - return false; - numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog); if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0)) return S_FALSE; if (!mftRec.IsFILE()) @@ -1292,22 +1328,18 @@ HRESULT CDatabase::Open() return S_FALSE; } - UInt64 mftSize = mftRec.DataAttrs[0].Size; + const UInt64 mftSize = mftRec.DataAttrs[0].Size; if ((mftSize >> 4) > Header.GetPhySize()) return S_FALSE; - UInt64 numFiles = mftSize >> recSizeLog; + const UInt64 numFiles = mftSize >> Header.MftRecordSizeLog; if (numFiles > (1 << 30)) return S_FALSE; if (OpenCallback) { RINOK(OpenCallback->SetTotal(&numFiles, &mftSize)); } - const UInt32 kBufSize = (1 << 15); - if (kBufSize < (1 << recSizeLog)) - return S_FALSE; - ByteBuf.SetCapacity((size_t)kBufSize); Recs.Reserve((int)numFiles); for (UInt64 pos64 = 0;;) { @@ -1323,15 +1355,15 @@ HRESULT CDatabase::Open() UInt64 rem = mftSize - pos64; if (readSize > rem) readSize = (UInt32)rem; - if (readSize < ((UInt32)1 << recSizeLog)) + if (readSize < recSize) break; RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize)); pos64 += readSize; - for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++) + for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize) { PRF(printf("\n---------------------")); PRF(printf("\n%5d:", Recs.Size())); - Byte *p = ByteBuf + ((UInt32)i << recSizeLog); + Byte *p = ByteBuf + i; CMftRec rec; if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL))
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor