From ad158d2240e1589565caddb9ae800fb966a614e5 Mon Sep 17 00:00:00 2001 From: Miguel Otero <55704237+MiguelOteroIFD@users.noreply.github.com> Date: Thu, 2 Sep 2021 11:09:53 +0100 Subject: [PATCH] Prevent heap overflow / fix null-terminated name handling / better approach to path creation (#2) --- Light-Swift-Untar.swift | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Light-Swift-Untar.swift b/Light-Swift-Untar.swift index e2c23fd..fb54d5e 100644 --- a/Light-Swift-Untar.swift +++ b/Light-Swift-Untar.swift @@ -35,7 +35,7 @@ public extension FileManager { switch type { case "0": // File let name = self.name(object: tarObject, offset: location) - let filePath = path + name + let filePath = URL(string: path)!.appendingPathComponent(name).path let size = self.size(object: tarObject, offset: location) if size == 0 { try "".write(toFile: filePath, atomically: true, encoding: .utf8) } else { @@ -45,7 +45,7 @@ public extension FileManager { } case "5": // Directory let name = self.name(object: tarObject, offset: location) - let directoryPath = path + name + let directoryPath = URL(string: path)!.appendingPathComponent(name).path try createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) case "\0": break // Null block @@ -72,9 +72,15 @@ public extension FileManager { } private func name(object: Any, offset: UInt64) -> String { - let nameData = data(object: object, location: offset + FileManager.tarNamePosition, - length: FileManager.tarNameSize)! - return String(data: nameData, encoding: .ascii)! + var name = "" + for i in 0...FileManager.tarNameSize { + let char = String(data: data(object: object, location: offset + FileManager.tarNamePosition + i, length: 1)!, encoding: .ascii)! + if (char == "\0") { + return name + } + name += char + } + return name } private func size(object: Any, offset: UInt64) -> UInt64 { @@ -97,11 +103,15 @@ public extension FileManager { let maxSize = FileManager.tarMaxBlockLoadInMemory * FileManager.tarBlockSize var length = _len, location = _loc while length > maxSize { - destinationFile.write(fileHandle.readData(ofLength: Int(maxSize))) + autoreleasepool { // Needed to prevent heap overflow when reading large files + destinationFile.write(fileHandle.readData(ofLength: Int(maxSize))) + } location += maxSize length -= maxSize } - destinationFile.write(fileHandle.readData(ofLength: Int(length))) + autoreleasepool { // Needed to prevent heap overflow when reading large files + destinationFile.write(fileHandle.readData(ofLength: Int(length))) + } destinationFile.closeFile() } } @@ -112,7 +122,9 @@ public extension FileManager { return data.subdata(in: Int(location) ..< Int(location + length)) } else if let fileHandle = object as? FileHandle { fileHandle.seek(toFileOffset: location) - return fileHandle.readData(ofLength: Int(length)) + return autoreleasepool { // Needed to prevent heap overflow when reading large files + fileHandle.readData(ofLength: Int(length)) + } } return nil }