From 68293135ead9749f8e27149820d294839d37aff3 Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Mon, 28 Oct 2024 14:06:28 +0100 Subject: [PATCH] Avoid deadlocking the Packet Tunnel after a reboot --- ios/MullvadSettings/MigrationManager.swift | 3 ++ .../PacketTunnelProvider.swift | 48 +++++++++++-------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ios/MullvadSettings/MigrationManager.swift b/ios/MullvadSettings/MigrationManager.swift index 2fb11019c885..c13fd9baa580 100644 --- a/ios/MullvadSettings/MigrationManager.swift +++ b/ios/MullvadSettings/MigrationManager.swift @@ -68,6 +68,9 @@ public struct MigrationManager { ) } catch .itemNotFound as KeychainError { migrationCompleted(.nothing) + } catch let couldNotReadKeychainError as KeychainError + where couldNotReadKeychainError == .interactionNotAllowed { + migrationCompleted(.failure(couldNotReadKeychainError)) } catch { resetStoreHandler(.failure(error)) } diff --git a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift index 92e02e96d547..34530a0b48fa 100644 --- a/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider/PacketTunnelProvider.swift @@ -174,28 +174,36 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } private func performSettingsMigration() { - migrationManager.migrateSettings( - store: SettingsManager.store, - migrationCompleted: { [unowned self] migrationResult in - switch migrationResult { - case .success: - providerLogger.debug("Successful migration from PacketTunnel") - case .nothing: - providerLogger.debug("Attempted migration from PacketTunnel, but found nothing to do") - case let .failure(error): - // `next` returns an Optional value, but this iterator is guaranteed to always have a next value - guard let delay = migrationFailureIterator.next() else { return } - providerLogger - .error( - "Failed migration from PacketTunnel: \(error), retrying in \(delay.timeInterval) seconds" - ) - // Block the launch of the Packet Tunnel for as long as the settings migration fail. - // The process watchdog introduced by iOS 17 will kill this process after 60 seconds. - Thread.sleep(forTimeInterval: delay.timeInterval) - performSettingsMigration() + var hasNotMigrated = true + repeat { + migrationManager.migrateSettings( + store: SettingsManager.store, + migrationCompleted: { [unowned self] migrationResult in + switch migrationResult { + case .success: + providerLogger.debug("Successful migration from PacketTunnel") + hasNotMigrated = false + case .nothing: + hasNotMigrated = false + providerLogger.debug("Attempted migration from PacketTunnel, but found nothing to do") + case let .failure(error): + providerLogger + .error( + "Failed migration from PacketTunnel: \(error)" + ) + } } + ) + if hasNotMigrated { + // `next` returns an Optional value, but this iterator is guaranteed to always have a next value + guard let delay = migrationFailureIterator.next() else { continue } + + providerLogger.error("Retrying migration in \(delay.timeInterval) seconds") + // Block the launch of the Packet Tunnel for as long as the settings migration fail. + // The process watchdog introduced by iOS 17 will kill this process after 60 seconds. + Thread.sleep(forTimeInterval: delay.timeInterval) } - ) + } while hasNotMigrated } private func setUpTransportProvider(