From 9ca763127dab3ef68cd005d89c4575f1ff514abd Mon Sep 17 00:00:00 2001 From: abalfoort Date: Tue, 7 Jun 2022 17:20:56 +0200 Subject: [PATCH] Fix issue 1963: label encrypted partitions --- src/modules/partition/core/KPMHelpers.cpp | 145 +++++++++++++++--- src/modules/partition/core/KPMHelpers.h | 21 +++ .../jobs/ChangeFilesystemLabelJob.cpp | 13 ++ 3 files changed, 159 insertions(+), 20 deletions(-) diff --git a/src/modules/partition/core/KPMHelpers.cpp b/src/modules/partition/core/KPMHelpers.cpp index d53b441d9..e3985bc40 100644 --- a/src/modules/partition/core/KPMHelpers.cpp +++ b/src/modules/partition/core/KPMHelpers.cpp @@ -25,6 +25,8 @@ #include #include +#include + using CalamaresUtils::Partition::PartitionIterator; namespace KPMHelpers @@ -133,7 +135,6 @@ clonePartition( Device* device, Partition* partition ) partition->activeFlags() ); } -// Adapted from src/fs/luks.cpp cryptOpen which always opens a dialog to ask for a passphrase SavePassphraseValue savePassphrase( Partition* partition, const QString& passphrase ) { @@ -143,57 +144,161 @@ savePassphrase( Partition* partition, const QString& passphrase ) return SavePassphraseValue::EmptyPassphrase; } - if ( partition->fileSystem().type() != FileSystem::Luks ) + FS::luks* luksFs = dynamic_cast< FS::luks* >( &partition->fileSystem() ); + if ( luksFs == nullptr ) { + // No luks device return SavePassphraseValue::NotLuksPartition; } - FS::luks* luksFs = dynamic_cast< FS::luks* >( &partition->fileSystem() ); - const QString deviceNode = partition->partitionPath(); - // Test the given passphrase - if ( !luksFs->testPassphrase( deviceNode, passphrase ) ) + if ( !luksFs->testPassphrase( partition->partitionPath(), passphrase ) ) + { + // Save the existing passphrase + luksFs->setPassphrase( passphrase ); + } + else { return SavePassphraseValue::IncorrectPassphrase; } + return SavePassphraseValue::NoError; +} + +// Adapted from src/fs/luks.cpp cryptOpen which always opens a dialog to ask for a passphrase +QString +cryptOpen( Partition* partition ) +{ + FS::luks* luksFs = dynamic_cast< FS::luks* >( &partition->fileSystem() ); + if ( luksFs == nullptr ) + { + // No luks device + return QString(); + } if ( luksFs->isCryptOpen() ) { if ( !luksFs->mapperName().isEmpty() ) { - return SavePassphraseValue::NoError; + // Already decrypted + return luksFs->mapperName(); } else { - cDebug() << Logger::SubEntry << "No mapper node found"; + cDebug() << Logger::SubEntry << "No mapper node found - reset cryptOpen"; luksFs->setCryptOpen( false ); } } + if ( luksFs->passphrase().isEmpty() ) + { + // No passphrase for decryption + return QString(); + } + + // Decrypt the partition + const QString deviceNode = partition->partitionPath(); ExternalCommand openCmd( QStringLiteral( "cryptsetup" ), { QStringLiteral( "open" ), deviceNode, luksFs->suggestedMapperName( deviceNode ) } ); - if ( !( openCmd.write( passphrase.toLocal8Bit() + '\n' ) && openCmd.start( -1 ) && openCmd.exitCode() == 0 ) ) + if ( ( openCmd.write( luksFs->passphrase().toLocal8Bit() + '\n' ) && openCmd.start( -1 ) && openCmd.exitCode() == 0 ) ) { - cWarning() << Logger::SubEntry << openCmd.exitCode() << ": cryptsetup command failed"; - return SavePassphraseValue::CryptsetupError; + luksFs->scan( deviceNode ); + if ( luksFs->mapperName().isEmpty() ) + { + return QString(); + } + luksFs->loadInnerFileSystem( luksFs->mapperName() ); + luksFs->setCryptOpen( luksFs->innerFS() != nullptr ); + if ( !luksFs->isCryptOpen() ) + { + return QString(); + } + return luksFs->mapperName(); + } + return QString(); +} + +void +cryptClose( Partition* partition ) +{ + FS::luks* luksFs = dynamic_cast< FS::luks* >( &partition->fileSystem() ); + if ( luksFs == nullptr ) + { + // No luks device + return; } - // Save the existing passphrase - luksFs->setPassphrase( passphrase ); - luksFs->scan( deviceNode ); if ( luksFs->mapperName().isEmpty() ) { - return SavePassphraseValue::NoMapperNode; + // Not opened + return; } - luksFs->loadInnerFileSystem( luksFs->mapperName() ); - luksFs->setCryptOpen( luksFs->innerFS() != nullptr ); - if ( !luksFs->isCryptOpen() ) + // Close the partition + luksFs->cryptClose( partition->partitionPath() ); +} + +bool +cryptLabel( Partition* partition, const QString& label ) +{ + int version = cryptVersion( partition ); + if ( version == 0 || label.isEmpty() ) { - return SavePassphraseValue::DeviceNotDecrypted; + return false; } - return SavePassphraseValue::NoError; + if ( version == 1 ) + { + QString mappedDevice = cryptOpen( partition ); + if ( !mappedDevice.isEmpty() ) + { + // Label mapped device + ExternalCommand openCmd( QStringLiteral( "e2label" ), + { mappedDevice, + label } ); + openCmd.start( -1 ); + cryptClose( partition ); + return true; + } + } + else + { + ExternalCommand openCmd( QStringLiteral( "cryptsetup" ), + { QStringLiteral( "config" ), + partition->partitionPath(), + QStringLiteral( "--label" ), + label } ); + if ( openCmd.start( -1 ) && openCmd.exitCode() == 0 ) + { + return true; + } + } + return false; +} + +int +cryptVersion( Partition* partition ) +{ + if ( partition->fileSystem().type() != FileSystem::Luks ) + { + return 0; + } + + // Get luks version from header information + int luksVersion = 1; + ExternalCommand openCmd( QStringLiteral( "cryptsetup" ), + { QStringLiteral( "luksDump" ), + partition->partitionPath() } ); + if ( openCmd.start( -1 ) && openCmd.exitCode() == 0 ) + { + QRegularExpression re( QStringLiteral( R"(version:\s+(\d))" ), + QRegularExpression::CaseInsensitiveOption ); + QRegularExpressionMatch rem = re.match( openCmd.output() ); + if ( rem.hasMatch() ) + { + luksVersion = rem.captured( 1 ).toInt(); + } + } + return luksVersion; } Calamares::JobResult diff --git a/src/modules/partition/core/KPMHelpers.h b/src/modules/partition/core/KPMHelpers.h index 4933caa32..2b2da6b14 100644 --- a/src/modules/partition/core/KPMHelpers.h +++ b/src/modules/partition/core/KPMHelpers.h @@ -98,6 +98,27 @@ Partition* clonePartition( Device* device, Partition* partition ); */ SavePassphraseValue savePassphrase( Partition* partition, const QString& passphrase ); +/** @brief Decrypt an encrypted partition. + * + * Uses @p partition to decrypt the partition. + * The passphrase saved in @p partition is used. + * Returns the mapped device path or an empty string if it fails. + */ +QString cryptOpen( Partition* partition ); +void cryptClose( Partition* partition ); + +/** @brief Set label of luks encrypted partition. + * + * Returns true on success or false if it fails. + */ +bool cryptLabel( Partition* partition, const QString& label ); + +/** @brief Returns the luks version used to encrypt the partition. + * + * Used by cryptLabel + */ +int cryptVersion( Partition* partition ); + /** @brief Return a result for an @p operation * * Executes the operation, and if successful, returns a success result. diff --git a/src/modules/partition/jobs/ChangeFilesystemLabelJob.cpp b/src/modules/partition/jobs/ChangeFilesystemLabelJob.cpp index 9541c000a..4cdb2532e 100644 --- a/src/modules/partition/jobs/ChangeFilesystemLabelJob.cpp +++ b/src/modules/partition/jobs/ChangeFilesystemLabelJob.cpp @@ -9,6 +9,8 @@ #include "ChangeFilesystemLabelJob.h" +#include "core/KPMHelpers.h" + #include "utils/Logger.h" #include @@ -58,6 +60,17 @@ ChangeFilesystemLabelJob::exec() return Calamares::JobResult::ok(); } + // Check for luks device + if ( partition()->fileSystem().type() == FileSystem::Luks ) + { + if ( KPMHelpers::cryptLabel( partition(), m_label ) ) + { + return Calamares::JobResult::ok(); + } + return Calamares::JobResult::error( + tr( "The installer failed to update partition table on disk '%1'." ).arg( m_device->name() ) ); + } + Report report( nullptr ); SetFileSystemLabelOperation op( *partition(), m_label ); op.setStatus( Operation::StatusRunning );