From aeafb939576b35fb1655687170fe57a775897c69 Mon Sep 17 00:00:00 2001 From: Dmitry Kovba Date: Mon, 6 Apr 2026 19:15:42 -0700 Subject: [PATCH 1/4] Add a test for the last `xattr` dropped at the buffer boundary --- .../TestEXT4ExtendedAttributes.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift b/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift index 21706979..d6e357db 100644 --- a/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift +++ b/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift @@ -51,6 +51,20 @@ struct TestEXT4ExtendedAttribute { } } + @Test func lastXattrNotDroppedAtBufferBoundary() throws { + let buffer: [UInt8] = [ + 0, // nameLength + 8, // nameIndex + 0, 0, // valueOffset + 0, 0, 0, 0, // valueInum + 0, 0, 0, 0, // valueSize + 0, 0, 0, 0, // hash + ] + let attrs = try EXT4.FileXattrsState.read(buffer: buffer, start: 0, offset: 0) + try #require(attrs.count == 1) + #expect(attrs[0].fullName == "system.richacl") + } + @Test func encodeDecodeAttributes() { let xattrs: [String: Data] = [ "foo.bar": Data([1, 2, 3]), From 89cf6f0a3e946250f20d0e050b6a078dfa0999b9 Mon Sep 17 00:00:00 2001 From: Dmitry Kovba Date: Mon, 6 Apr 2026 19:17:06 -0700 Subject: [PATCH 2/4] Fix for the last `xattr` dropped at the buffer boundary --- Sources/ContainerizationEXT4/EXT4+Xattrs.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ContainerizationEXT4/EXT4+Xattrs.swift b/Sources/ContainerizationEXT4/EXT4+Xattrs.swift index 6038ecd1..134824a4 100644 --- a/Sources/ContainerizationEXT4/EXT4+Xattrs.swift +++ b/Sources/ContainerizationEXT4/EXT4+Xattrs.swift @@ -257,13 +257,13 @@ extension EXT4 { var i = start var attribs: [ExtendedAttribute] = [] // 16 is the size of 1 XAttrEntry - while i + 16 < buffer.count { + while i + 16 <= buffer.count { let attributeStart = i let rawXattrEntry = Array(buffer[i.. Date: Mon, 6 Apr 2026 19:17:48 -0700 Subject: [PATCH 3/4] Add a test for the out-of-bounds `xattr` value crash --- .../TestEXT4ExtendedAttributes.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift b/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift index d6e357db..d62c5eb5 100644 --- a/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift +++ b/Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift @@ -65,6 +65,20 @@ struct TestEXT4ExtendedAttribute { #expect(attrs[0].fullName == "system.richacl") } + @Test func xattrOutOfBoundsValueDoesNotCrash() throws { + let buffer: [UInt8] = [ + 1, // nameLength + 1, // nameIndex + 17, 0, // valueOffset + 0, 0, 0, 0, // valueInum + 4, 0, 0, 0, // valueSize + 0, 0, 0, 0, // hash + UInt8(ascii: "a"), 0, 0, 0, // name + ] + let attrs = try EXT4.FileXattrsState.read(buffer: buffer, start: 0, offset: 0) + #expect(attrs.isEmpty) + } + @Test func encodeDecodeAttributes() { let xattrs: [String: Data] = [ "foo.bar": Data([1, 2, 3]), From 04d4efe93512bb538465d33155cae9b4a7e66df1 Mon Sep 17 00:00:00 2001 From: Dmitry Kovba Date: Mon, 6 Apr 2026 19:18:01 -0700 Subject: [PATCH 4/4] Fix for the out-of-bounds `xattr` value crash --- Sources/ContainerizationEXT4/EXT4+Xattrs.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/ContainerizationEXT4/EXT4+Xattrs.swift b/Sources/ContainerizationEXT4/EXT4+Xattrs.swift index 134824a4..e6ee7096 100644 --- a/Sources/ContainerizationEXT4/EXT4+Xattrs.swift +++ b/Sources/ContainerizationEXT4/EXT4+Xattrs.swift @@ -270,6 +270,9 @@ extension EXT4 { let name = String(bytes: rawName, encoding: .ascii)! let valueStart = Int(xattrEntry.valueOffset) + offset let valueEnd = Int(xattrEntry.valueOffset) + Int(xattrEntry.valueSize) + offset + guard valueEnd <= buffer.count else { + break + } let value = [UInt8](buffer[valueStart..