Skip to content

Commit 3a84f98

Browse files
authored
Fix the xattr read loop bounds (#658)
Fixes the `xattr` read loop bounds. Resolves the failing added tests: > ✘ Test lastXattrNotDroppedAtBufferBoundary() recorded an issue at TestEXT4ExtendedAttributes.swift:72:13: Expectation failed: (attrs.count → 0) == 1 > ✘ Test lastXattrNotDroppedAtBufferBoundary() failed after 0.001 seconds with 1 issue. > Swift/Array.swift:430: Fatal error: Array index is out of range
1 parent b2be8de commit 3a84f98

2 files changed

Lines changed: 33 additions & 2 deletions

File tree

Sources/ContainerizationEXT4/EXT4+Xattrs.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,13 @@ extension EXT4 {
257257
var i = start
258258
var attribs: [ExtendedAttribute] = []
259259
// 16 is the size of 1 XAttrEntry
260-
while i + 16 < buffer.count {
260+
while i + 16 <= buffer.count {
261261
let attributeStart = i
262262
let rawXattrEntry = Array(buffer[i..<i + 16])
263263
let xattrEntry = try EXT4.XAttrEntry(using: rawXattrEntry)
264264
i += 16
265265
var endIndex = i + Int(xattrEntry.nameLength)
266-
guard endIndex < buffer.count else {
266+
guard endIndex <= buffer.count else {
267267
continue
268268
}
269269
let rawName = buffer[i..<endIndex]
@@ -272,6 +272,9 @@ extension EXT4 {
272272
}
273273
let valueStart = Int(xattrEntry.valueOffset) + offset
274274
let valueEnd = Int(xattrEntry.valueOffset) + Int(xattrEntry.valueSize) + offset
275+
guard valueEnd <= buffer.count else {
276+
break
277+
}
275278
let value = [UInt8](buffer[valueStart..<valueEnd])
276279
let xattr = ExtendedAttribute(idx: xattrEntry.nameIndex, compressedName: name, value: value)
277280
attribs.append(xattr)

Tests/ContainerizationEXT4Tests/TestEXT4ExtendedAttributes.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,34 @@ struct TestEXT4ExtendedAttribute {
5151
}
5252
}
5353

54+
@Test func lastXattrNotDroppedAtBufferBoundary() throws {
55+
let buffer: [UInt8] = [
56+
0, // nameLength
57+
8, // nameIndex
58+
0, 0, // valueOffset
59+
0, 0, 0, 0, // valueInum
60+
0, 0, 0, 0, // valueSize
61+
0, 0, 0, 0, // hash
62+
]
63+
let attrs = try EXT4.FileXattrsState.read(buffer: buffer, start: 0, offset: 0)
64+
try #require(attrs.count == 1)
65+
#expect(attrs[0].fullName == "system.richacl")
66+
}
67+
68+
@Test func xattrOutOfBoundsValueDoesNotCrash() throws {
69+
let buffer: [UInt8] = [
70+
1, // nameLength
71+
1, // nameIndex
72+
17, 0, // valueOffset
73+
0, 0, 0, 0, // valueInum
74+
4, 0, 0, 0, // valueSize
75+
0, 0, 0, 0, // hash
76+
UInt8(ascii: "a"), 0, 0, 0, // name
77+
]
78+
let attrs = try EXT4.FileXattrsState.read(buffer: buffer, start: 0, offset: 0)
79+
#expect(attrs.isEmpty)
80+
}
81+
5482
@Test func encodeDecodeAttributes() {
5583
let xattrs: [String: Data] = [
5684
"foo.bar": Data([1, 2, 3]),

0 commit comments

Comments
 (0)