diff --git a/CHANGES-3.2 b/CHANGES-3.2 index 92c9f51f7..fc42033c3 100644 --- a/CHANGES-3.2 +++ b/CHANGES-3.2 @@ -17,6 +17,10 @@ This release contains contributions from (alphabetically by first name): - The translation for Sinhala (`si`) has reached 100%. Thank you to හෙළබස and Sandaruwan, translators for Sinhala, for special effort in completing that translation. + - Logging now supports Redacted names. This reduces the scope for + leaking names or other private information through the logs + (if they are posted to a pastebin). A name is redacted consistently + within one run of Calamares, but differently each time. ## Modules ## - *displaymanager* supports the *greetd* display manager, which is a @@ -31,6 +35,8 @@ This release contains contributions from (alphabetically by first name): option, since the kernel automatically picks the right value, while setting it to the wrong one may prevent the system from booting. (Thanks Evan) + - The *partition* module no longer logs recognizable disk names or + UUIDs. These are redacted in the logs. #1593 # 3.2.46 (2021-11-09) # diff --git a/src/libcalamares/utils/Logger.cpp b/src/libcalamares/utils/Logger.cpp index 79ae873db..d35d6891b 100644 --- a/src/libcalamares/utils/Logger.cpp +++ b/src/libcalamares/utils/Logger.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -229,7 +231,7 @@ toString( const QVariant& v ) } QDebug& -operator<<( QDebug& s, const Redacted& l ) +operator<<( QDebug& s, const RedactedCommand& l ) { // Special case logging: don't log the (encrypted) password. if ( l.list.contains( "usermod" ) ) @@ -252,4 +254,33 @@ operator<<( QDebug& s, const Redacted& l ) return s; } +/** @brief Returns a stable-but-private hash of @p context and @p s + * + * Identical strings with the same context will be hashed the same, + * so that they can be logged and still recognized as the-same. + */ +static uint insertRedactedName( const QString& context, const QString& s ) +{ + static uint salt = QRandomGenerator::global()->generate(); // Just once + + uint val = qHash(context, salt); + return qHash(s, val); +} + +RedactedName::RedactedName( const QString& context, const QString& s ) + : m_id( insertRedactedName(context, s) ), + m_context(context) +{ +} + +RedactedName::RedactedName(const char *context, const QString& s ) + : RedactedName( QString::fromLatin1( context ), s ) +{ +} + +RedactedName::operator QString() const +{ + return QString( m_context + '$' + QString::number( m_id, 16 ) ); +} + } // namespace Logger diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h index bf6b99d00..0d7d5c870 100644 --- a/src/libcalamares/utils/Logger.h +++ b/src/libcalamares/utils/Logger.h @@ -145,8 +145,8 @@ public: { } - const T& first; - const U& second; + const T first; + const U second; }; /** @@ -214,9 +214,9 @@ public: * since the log may get posted to bug reports, or stored in * the target system. */ -struct Redacted +struct RedactedCommand { - Redacted( const QStringList& l ) + RedactedCommand( const QStringList& l ) : list( l ) { } @@ -224,7 +224,30 @@ struct Redacted const QStringList& list; }; -QDebug& operator<<( QDebug& s, const Redacted& l ); +QDebug& operator<<( QDebug& s, const RedactedCommand& l ); + +/** @brief When logging "private" identifiers, keep them consistent but private + * + * Send a string to a logger in such a way that each time it is logged, + * it logs the same way, but without revealing the actual contents. + * This can be applied to user names, UUIDs, etc. + */ +struct RedactedName +{ + RedactedName( const char* context, const QString& s ); + RedactedName( const QString& context, const QString& s ); + + operator QString() const; + +private: + const uint m_id; + const QString m_context; +}; + +inline QDebug& operator<<( QDebug& s, const RedactedName& n ) +{ + return s << NoQuote << QString( n ) << Quote; +} /** * @brief Formatted logging of a pointer diff --git a/src/libcalamares/utils/Runner.cpp b/src/libcalamares/utils/Runner.cpp index e138b1c68..c7146c2d7 100644 --- a/src/libcalamares/utils/Runner.cpp +++ b/src/libcalamares/utils/Runner.cpp @@ -163,7 +163,7 @@ Calamares::Utils::Runner::run() } ); } - cDebug() << Logger::SubEntry << "Running" << Logger::Redacted( m_command ); + cDebug() << Logger::SubEntry << "Running" << Logger::RedactedCommand( m_command ); process.start(); if ( !process.waitForStarted() ) { @@ -225,13 +225,13 @@ Calamares::Utils::Runner::run() { if ( !output.isEmpty() ) { - cDebug() << Logger::SubEntry << "Target cmd:" << Logger::Redacted( m_command ) << "Exit code:" << r + cDebug() << Logger::SubEntry << "Target cmd:" << Logger::RedactedCommand( m_command ) << "Exit code:" << r << "output:\n" << Logger::NoQuote << output; } else { - cDebug() << Logger::SubEntry << "Target cmd:" << Logger::Redacted( m_command ) << "Exit code:" << r + cDebug() << Logger::SubEntry << "Target cmd:" << Logger::RedactedCommand( m_command ) << "Exit code:" << r << "(no output)"; } } diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 69a6db535..16e5a7ea1 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -257,14 +257,16 @@ PartitionCoreModule::doInit() cDebug() << Logger::SubEntry << "node\tcapacity\tname\tprettyName"; for ( auto device : devices ) { - cDebug() << Logger::SubEntry << Logger::Pointer( device ); if ( device ) { // Gives ownership of the Device* to the DeviceInfo object auto deviceInfo = new DeviceInfo( device ); m_deviceInfos << deviceInfo; - cDebug() << Logger::SubEntry << device->deviceNode() << device->capacity() << device->name() - << device->prettyName(); + cDebug() << Logger::SubEntry + << device->deviceNode() + << device->capacity() + << Logger::RedactedName( "DevName", device->name() ) + << Logger::RedactedName( "DevNamePretty", device->prettyName() ); } else { @@ -707,10 +709,10 @@ PartitionCoreModule::dumpQueue() const cDebug() << "# Queue:"; for ( auto info : m_deviceInfos ) { - cDebug() << Logger::SubEntry << "## Device:" << info->device->name(); + cDebug() << Logger::SubEntry << "## Device:" << info->device->deviceNode(); for ( const auto& job : info->jobs() ) { - cDebug() << Logger::SubEntry << "-" << job->prettyName(); + cDebug() << Logger::SubEntry << "-" << job->metaObject()->className(); } } } diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index 40e67d620..5be353113 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -104,14 +104,19 @@ mapForPartition( Partition* partition, const QString& uuid ) // Debugging for inside the loop in createPartitionList(), // so indent a bit Logger::CDebug deb; - using TR = Logger::DebugRow< const char* const, const QString& >; + using TR = Logger::DebugRow< const char* const, const QString >; + // clang-format off deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() - << TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() ) - << TR( "parttype", map[ "parttype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() ) - << TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() ) - << TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid ) + << TR( "partlabel", map[ "partlabel" ].toString() ) + << TR( "partition-uuid (partuuid)", Logger::RedactedName( "PartUUID", map[ "partuuid" ].toString() ) ) + << TR( "parttype", map[ "parttype" ].toString() ) + << TR( "partattrs", map[ "partattrs" ].toString() ) + << TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) + << TR( "fs:", map[ "fs" ].toString() ) + << TR( "fsName", map[ "fsName" ].toString() ) + << TR( "filesystem-uuid (uuid)", Logger::RedactedName( "FSUUID", uuid ) ) << TR( "claimed", map[ "claimed" ].toString() ); - + // clang-format on if ( partition->roles().has( PartitionRole::Luks ) ) { const FileSystem& fsRef = partition->fileSystem();