summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhongxu <hongxu.jia@eng.windriver.com>2024-11-22 21:46:40 +0800
committerArmin Kuster <akuster808@gmail.com>2024-12-15 13:52:02 -0500
commit00973f130d797fe829fef17b5858c5ae8bca3220 (patch)
tree1d69f2f3bae999506cadf190c9253f2bba9e3b02
parent16482be69910fbd105b0aa63160ddc443032684a (diff)
downloadmeta-openembedded-00973f130d797fe829fef17b5858c5ae8bca3220.tar.gz
p7zip: fix CVE-2023-52169 and CVE-2023-52168
According to [1][2], Igor Pavlov, the author of 7-Zip, refused to provide an advisory or any related change log entries. Have to backport a part of ./CPP/7zip/Archive/NtfsHandler.cpp from upstream big commit https://github.com/ip7z/7zip/commit/fc662341e6f85da78ada0e443f6116b978f79f22 [1] https://dfir.ru/2024/06/19/vulnerabilities-in-7-zip-and-ntfs3/ [2] https://dfir.ru/wp-content/uploads/2024/07/screenshot-2024-07-03-at-02-13-40-7-zip-_-bugs-_-2402-two-vulnerabilities-in-the-ntfs-handler.png Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/recipes-extended/p7zip/files/0001-Fix-two-buffer-overflow-vulnerabilities.patch455
-rw-r--r--meta-oe/recipes-extended/p7zip/p7zip_16.02.bb1
2 files changed, 456 insertions, 0 deletions
diff --git a/meta-oe/recipes-extended/p7zip/files/0001-Fix-two-buffer-overflow-vulnerabilities.patch b/meta-oe/recipes-extended/p7zip/files/0001-Fix-two-buffer-overflow-vulnerabilities.patch
new file mode 100644
index 0000000000..d149c34134
--- /dev/null
+++ b/meta-oe/recipes-extended/p7zip/files/0001-Fix-two-buffer-overflow-vulnerabilities.patch
@@ -0,0 +1,455 @@
1From 1f266347b154ed90b8262126f04e8cc8f59fa617 Mon Sep 17 00:00:00 2001
2From: Hongxu Jia <hongxu.jia@windriver.com>
3Date: Fri, 22 Nov 2024 21:25:21 +0800
4Subject: [PATCH] Fix two buffer overflow vulnerabilities
5
6According to [1][2], Igor Pavlov, the author of 7-Zip, refused to
7provide an advisory or any related change log entries. We have to
8backport a part of ./CPP/7zip/Archive/NtfsHandler.cpp from upstream
9big commit
10
11Upstream-Status: Backport [https://github.com/ip7z/7zip/commit/fc662341e6f85da78ada0e443f6116b978f79f22]
12
13[1] https://dfir.ru/2024/06/19/vulnerabilities-in-7-zip-and-ntfs3/
14[2] https://dfir.ru/wp-content/uploads/2024/07/screenshot-2024-07-03-at-02-13-40-7-zip-_-bugs-_-2402-two-vulnerabilities-in-the-ntfs-handler.png
15
16CVE: CVE-2023-52169
17CVE: CVE-2023-52168
18
19Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
20---
21 CPP/7zip/Archive/NtfsHandler.cpp | 229 ++++++++++++++++++++-----------
22 1 file changed, 151 insertions(+), 78 deletions(-)
23
24diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
25index 93e9f88..2701439 100644
26--- a/CPP/7zip/Archive/NtfsHandler.cpp
27+++ b/CPP/7zip/Archive/NtfsHandler.cpp
28@@ -71,8 +71,9 @@ struct CHeader
29 {
30 unsigned SectorSizeLog;
31 unsigned ClusterSizeLog;
32+ unsigned MftRecordSizeLog;
33 // Byte MediaType;
34- UInt32 NumHiddenSectors;
35+ //UInt32 NumHiddenSectors;
36 UInt64 NumSectors;
37 UInt64 NumClusters;
38 UInt64 MftCluster;
39@@ -111,30 +112,42 @@ bool CHeader::Parse(const Byte *p)
40 if (memcmp(p + 3, "NTFS ", 8) != 0)
41 return false;
42 {
43- int t = GetLog(Get16(p + 11));
44- if (t < 9 || t > 12)
45- return false;
46- SectorSizeLog = t;
47- t = GetLog(p[13]);
48- if (t < 0)
49- return false;
50- sectorsPerClusterLog = t;
51- ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
52- if (ClusterSizeLog > 30)
53- return false;
54+ {
55+ const int t = GetLog(Get16(p + 11));
56+ if (t < 9 || t > 12)
57+ return false;
58+ SectorSizeLog = (unsigned)t;
59+ }
60+ {
61+ const unsigned v = p[13];
62+ if (v <= 0x80)
63+ {
64+ const int t = GetLog(v);
65+ if (t < 0)
66+ return false;
67+ sectorsPerClusterLog = (unsigned)t;
68+ }
69+ else
70+ sectorsPerClusterLog = 0x100 - v;
71+ ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
72+ if (ClusterSizeLog > 30)
73+ return false;
74+ }
75 }
76
77 for (int i = 14; i < 21; i++)
78 if (p[i] != 0)
79 return false;
80
81+ // F8 : a hard disk
82+ // F0 : high-density 3.5-inch floppy disk
83 if (p[21] != 0xF8) // MediaType = Fixed_Disk
84 return false;
85 if (Get16(p + 22) != 0) // NumFatSectors
86 return false;
87- G16(p + 24, SectorsPerTrack); // 63 usually
88- G16(p + 26, NumHeads); // 255
89- G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?)
90+ // G16(p + 24, SectorsPerTrack); // 63 usually
91+ // G16(p + 26, NumHeads); // 255
92+ // G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?)
93 if (Get32(p + 32) != 0) // NumSectors32
94 return false;
95
96@@ -156,14 +169,47 @@ bool CHeader::Parse(const Byte *p)
97
98 NumClusters = NumSectors >> sectorsPerClusterLog;
99
100- G64(p + 0x30, MftCluster);
101+ G64(p + 0x30, MftCluster); // $MFT.
102 // G64(p + 0x38, Mft2Cluster);
103- G64(p + 0x48, SerialNumber);
104- UInt32 numClustersInMftRec;
105- UInt32 numClustersInIndexBlock;
106- G32(p + 0x40, numClustersInMftRec); // -10 means 2 ^10 = 1024 bytes.
107- G32(p + 0x44, numClustersInIndexBlock);
108- return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
109+ G64(p + 0x48, SerialNumber); // $MFTMirr
110+
111+ /*
112+ numClusters_per_MftRecord:
113+ numClusters_per_IndexBlock:
114+ only low byte from 4 bytes is used. Another 3 high bytes are zeros.
115+ If the number is positive (number < 0x80),
116+ then it represents the number of clusters.
117+ If the number is negative (number >= 0x80),
118+ then the size of the file record is 2 raised to the absolute value of this number.
119+ example: (0xF6 == -10) means 2^10 = 1024 bytes.
120+ */
121+ {
122+ UInt32 numClusters_per_MftRecord;
123+ G32(p + 0x40, numClusters_per_MftRecord);
124+ if (numClusters_per_MftRecord >= 0x100 || numClusters_per_MftRecord == 0)
125+ return false;
126+ if (numClusters_per_MftRecord < 0x80)
127+ {
128+ const int t = GetLog(numClusters_per_MftRecord);
129+ if (t < 0)
130+ return false;
131+ MftRecordSizeLog = (unsigned)t + ClusterSizeLog;
132+ }
133+ else
134+ MftRecordSizeLog = 0x100 - numClusters_per_MftRecord;
135+ // what exact MFT record sizes are possible and supported by Windows?
136+ // do we need to change this limit here?
137+ const unsigned k_MftRecordSizeLog_MAX = 12;
138+ if (MftRecordSizeLog > k_MftRecordSizeLog_MAX)
139+ return false;
140+ if (MftRecordSizeLog < SectorSizeLog)
141+ return false;
142+ }
143+ {
144+ UInt32 numClusters_per_IndexBlock;
145+ G32(p + 0x44, numClusters_per_IndexBlock);
146+ return (numClusters_per_IndexBlock < 0x100);
147+ }
148 }
149
150 struct CMftRef
151@@ -235,7 +281,7 @@ struct CFileNameAttr
152 bool Parse(const Byte *p, unsigned size);
153 };
154
155-static void GetString(const Byte *p, unsigned len, UString2 &res)
156+static void GetString(const Byte *p, const unsigned len, UString2 &res)
157 {
158 if (len == 0 && res.IsEmpty())
159 return;
160@@ -266,8 +312,8 @@ bool CFileNameAttr::Parse(const Byte *p, unsigned size)
161 G32(p + 0x38, Attrib);
162 // G16(p + 0x3C, PackedEaSize);
163 NameType = p[0x41];
164- unsigned len = p[0x40];
165- if (0x42 + len > size)
166+ const unsigned len = p[0x40];
167+ if (0x42 + len * 2 > size)
168 return false;
169 if (len != 0)
170 GetString(p + 0x42, len, Name);
171@@ -954,6 +1000,14 @@ struct CDataRef
172 static const UInt32 kMagic_FILE = 0x454C4946;
173 static const UInt32 kMagic_BAAD = 0x44414142;
174
175+// 22.02: we support some rare case magic values:
176+static const UInt32 kMagic_INDX = 0x58444e49;
177+static const UInt32 kMagic_HOLE = 0x454c4f48;
178+static const UInt32 kMagic_RSTR = 0x52545352;
179+static const UInt32 kMagic_RCRD = 0x44524352;
180+static const UInt32 kMagic_CHKD = 0x444b4843;
181+static const UInt32 kMagic_FFFFFFFF = 0xFFFFFFFF;
182+
183 struct CMftRec
184 {
185 UInt32 Magic;
186@@ -1030,6 +1084,26 @@ struct CMftRec
187
188 bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
189
190+ bool Is_Magic_Empty() const
191+ {
192+ // what exact Magic values are possible for empty and unused records?
193+ const UInt32 k_Magic_Unused_MAX = 5; // 22.02
194+ return (Magic <= k_Magic_Unused_MAX);
195+ }
196+ bool Is_Magic_FILE() const { return (Magic == kMagic_FILE); }
197+ // bool Is_Magic_BAAD() const { return (Magic == kMagic_BAAD); }
198+ bool Is_Magic_CanIgnore() const
199+ {
200+ return Is_Magic_Empty()
201+ || Magic == kMagic_BAAD
202+ || Magic == kMagic_INDX
203+ || Magic == kMagic_HOLE
204+ || Magic == kMagic_RSTR
205+ || Magic == kMagic_RCRD
206+ || Magic == kMagic_CHKD
207+ || Magic == kMagic_FFFFFFFF;
208+ }
209+
210 bool IsEmpty() const { return (Magic <= 2); }
211 bool IsFILE() const { return (Magic == kMagic_FILE); }
212 bool IsBAAD() const { return (Magic == kMagic_BAAD); }
213@@ -1141,9 +1215,8 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r
214 CObjectVector<CAttr> *attrs)
215 {
216 G32(p, Magic);
217- if (!IsFILE())
218- return IsEmpty() || IsBAAD();
219-
220+ if (!Is_Magic_FILE())
221+ return Is_Magic_CanIgnore();
222
223 {
224 UInt32 usaOffset;
225@@ -1188,12 +1261,12 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r
226 G16(p + 0x10, SeqNumber);
227 // G16(p + 0x12, LinkCount);
228 // PRF(printf(" L=%d", LinkCount));
229- UInt32 attrOffs = Get16(p + 0x14);
230+ const UInt32 attrOffs = Get16(p + 0x14);
231 G16(p + 0x16, Flags);
232 PRF(printf(" F=%4X", Flags));
233
234- UInt32 bytesInUse = Get32(p + 0x18);
235- UInt32 bytesAlloc = Get32(p + 0x1C);
236+ const UInt32 bytesInUse = Get32(p + 0x18);
237+ const UInt32 bytesAlloc = Get32(p + 0x1C);
238 G64(p + 0x20, BaseMftRef.Val);
239 if (BaseMftRef.Val != 0)
240 {
241@@ -1667,68 +1740,57 @@ HRESULT CDatabase::Open()
242
243 SeekToCluster(Header.MftCluster);
244
245- CMftRec mftRec;
246- UInt32 numSectorsInRec;
247-
248+ // we use ByteBuf for records reading.
249+ // so the size of ByteBuf must be >= mftRecordSize
250+ const size_t recSize = (size_t)1 << Header.MftRecordSizeLog;
251+ const size_t kBufSize = MyMax((size_t)(1 << 15), recSize);
252+ ByteBuf.Alloc(kBufSize);
253+ RINOK(ReadStream_FALSE(InStream, ByteBuf, recSize))
254+ {
255+ const UInt32 allocSize = Get32(ByteBuf + 0x1C);
256+ if (allocSize != recSize)
257+ return S_FALSE;
258+ }
259+ // MftRecordSizeLog >= SectorSizeLog
260+ const UInt32 numSectorsInRec = 1u << (Header.MftRecordSizeLog - Header.SectorSizeLog);
261 CMyComPtr<IInStream> mftStream;
262+ CMftRec mftRec;
263 {
264- UInt32 blockSize = 1 << 12;
265- ByteBuf.Alloc(blockSize);
266- RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
267-
268- {
269- UInt32 allocSize = Get32(ByteBuf + 0x1C);
270- int t = GetLog(allocSize);
271- if (t < (int)Header.SectorSizeLog)
272- return S_FALSE;
273- RecSizeLog = t;
274- if (RecSizeLog > 15)
275- return S_FALSE;
276- }
277-
278- numSectorsInRec = 1 << (RecSizeLog - Header.SectorSizeLog);
279 if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL))
280 return S_FALSE;
281- if (!mftRec.IsFILE())
282+ if (!mftRec.Is_Magic_FILE())
283 return S_FALSE;
284 mftRec.ParseDataNames();
285 if (mftRec.DataRefs.IsEmpty())
286 return S_FALSE;
287- RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream));
288+ RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream))
289 if (!mftStream)
290 return S_FALSE;
291 }
292
293 // CObjectVector<CAttr> SecurityAttrs;
294
295- UInt64 mftSize = mftRec.DataAttrs[0].Size;
296+ const UInt64 mftSize = mftRec.DataAttrs[0].Size;
297 if ((mftSize >> 4) > Header.GetPhySize_Clusters())
298 return S_FALSE;
299
300- const size_t kBufSize = (1 << 15);
301- const size_t recSize = ((size_t)1 << RecSizeLog);
302- if (kBufSize < recSize)
303- return S_FALSE;
304-
305 {
306- const UInt64 numFiles = mftSize >> RecSizeLog;
307+ const UInt64 numFiles = mftSize >> Header.MftRecordSizeLog;
308 if (numFiles > (1 << 30))
309 return S_FALSE;
310 if (OpenCallback)
311 {
312 RINOK(OpenCallback->SetTotal(&numFiles, &mftSize));
313 }
314-
315- ByteBuf.Alloc(kBufSize);
316 Recs.ClearAndReserve((unsigned)numFiles);
317 }
318-
319+
320 for (UInt64 pos64 = 0;;)
321 {
322 if (OpenCallback)
323 {
324 const UInt64 numFiles = Recs.Size();
325- if ((numFiles & 0x3FF) == 0)
326+ if ((numFiles & 0x3FFF) == 0)
327 {
328 RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
329 }
330@@ -1817,12 +1879,18 @@ HRESULT CDatabase::Open()
331 for (i = 0; i < Recs.Size(); i++)
332 {
333 CMftRec &rec = Recs[i];
334+ if (!rec.Is_Magic_FILE())
335+ continue;
336+
337 if (!rec.BaseMftRef.IsBaseItself())
338 {
339- UInt64 refIndex = rec.BaseMftRef.GetIndex();
340- if (refIndex > (UInt32)Recs.Size())
341+ const UInt64 refIndex = rec.BaseMftRef.GetIndex();
342+ if (refIndex >= Recs.Size())
343 return S_FALSE;
344 CMftRec &refRec = Recs[(unsigned)refIndex];
345+ if (!refRec.Is_Magic_FILE())
346+ continue;
347+
348 bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
349 if (rec.InUse() && refRec.InUse())
350 {
351@@ -1837,12 +1905,17 @@ HRESULT CDatabase::Open()
352 }
353
354 for (i = 0; i < Recs.Size(); i++)
355- Recs[i].ParseDataNames();
356+ {
357+ CMftRec &rec = Recs[i];
358+ if (!rec.Is_Magic_FILE())
359+ continue;
360+ rec.ParseDataNames();
361+ }
362
363 for (i = 0; i < Recs.Size(); i++)
364 {
365 CMftRec &rec = Recs[i];
366- if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself())
367+ if (!rec.Is_Magic_FILE() || !rec.BaseMftRef.IsBaseItself())
368 continue;
369 if (i < kNumSysRecs && !_showSystemFiles)
370 continue;
371@@ -1864,7 +1937,7 @@ HRESULT CDatabase::Open()
372 FOR_VECTOR (di, rec.DataRefs)
373 if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty())
374 {
375- indexOfUnnamedStream = di;
376+ indexOfUnnamedStream = (int)di;
377 break;
378 }
379 }
380@@ -1922,14 +1995,14 @@ HRESULT CDatabase::Open()
381 indexOfUnnamedStream);
382
383 if (rec.MyItemIndex < 0)
384- rec.MyItemIndex = Items.Size();
385- item.ParentHost = Items.Add(item);
386+ rec.MyItemIndex = (int)Items.Size();
387+ item.ParentHost = (int)Items.Add(item);
388
389 /* we can use that code to reduce the number of alt streams:
390 it will not show how alt streams for hard links. */
391 // if (!isMainName) continue; isMainName = false;
392
393- unsigned numAltStreams = 0;
394+ // unsigned numAltStreams = 0;
395
396 FOR_VECTOR (di, rec.DataRefs)
397 {
398@@ -1947,9 +2020,9 @@ HRESULT CDatabase::Open()
399 continue;
400 }
401
402- numAltStreams++;
403+ // numAltStreams++;
404 ThereAreAltStreams = true;
405- item.DataIndex = di;
406+ item.DataIndex = (int)di;
407 Items.Add(item);
408 }
409 }
410@@ -1964,10 +2037,10 @@ HRESULT CDatabase::Open()
411 if (attr.Name == L"$SDS")
412 {
413 CMyComPtr<IInStream> sdsStream;
414- RINOK(rec.GetStream(InStream, di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream));
415+ RINOK(rec.GetStream(InStream, (int)di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream));
416 if (sdsStream)
417 {
418- UInt64 size64 = attr.GetSize();
419+ const UInt64 size64 = attr.GetSize();
420 if (size64 < (UInt32)1 << 29)
421 {
422 size_t size = (size_t)size64;
423@@ -1997,7 +2070,7 @@ HRESULT CDatabase::Open()
424 const CMftRec &rec = Recs[item.RecIndex];
425 const CFileNameAttr &fn = rec.FileNames[item.NameIndex];
426 const CMftRef &parentDirRef = fn.ParentDirRef;
427- UInt64 refIndex = parentDirRef.GetIndex();
428+ const UInt64 refIndex = parentDirRef.GetIndex();
429 if (refIndex == kRecIndex_RootDir)
430 item.ParentFolder = -1;
431 else
432@@ -2024,17 +2097,17 @@ HRESULT CDatabase::Open()
433 unsigned virtIndex = Items.Size();
434 if (_showSystemFiles)
435 {
436- _systemFolderIndex = virtIndex++;
437+ _systemFolderIndex = (int)(virtIndex++);
438 VirtFolderNames.Add(kVirtualFolder_System);
439 }
440 if (thereAreUnknownFolders_Normal)
441 {
442- _lostFolderIndex_Normal = virtIndex++;
443+ _lostFolderIndex_Normal = (int)(virtIndex++);
444 VirtFolderNames.Add(kVirtualFolder_Lost_Normal);
445 }
446 if (thereAreUnknownFolders_Deleted)
447 {
448- _lostFolderIndex_Deleted = virtIndex++;
449+ _lostFolderIndex_Deleted = (int)(virtIndex++);
450 VirtFolderNames.Add(kVirtualFolder_Lost_Deleted);
451 }
452
453--
4542.34.1
455
diff --git a/meta-oe/recipes-extended/p7zip/p7zip_16.02.bb b/meta-oe/recipes-extended/p7zip/p7zip_16.02.bb
index e795482eb6..31a12fdb04 100644
--- a/meta-oe/recipes-extended/p7zip/p7zip_16.02.bb
+++ b/meta-oe/recipes-extended/p7zip/p7zip_16.02.bb
@@ -12,6 +12,7 @@ SRC_URI = "http://downloads.sourceforge.net/p7zip/p7zip/${PV}/p7zip_${PV}_src_al
12 file://change_numMethods_from_bool_to_unsigned.patch \ 12 file://change_numMethods_from_bool_to_unsigned.patch \
13 file://CVE-2018-5996.patch \ 13 file://CVE-2018-5996.patch \
14 file://CVE-2016-9296.patch \ 14 file://CVE-2016-9296.patch \
15 file://0001-Fix-two-buffer-overflow-vulnerabilities.patch \
15 " 16 "
16 17
17SRC_URI[md5sum] = "a0128d661cfe7cc8c121e73519c54fbf" 18SRC_URI[md5sum] = "a0128d661cfe7cc8c121e73519c54fbf"