From 31e78ff0c2d15b650564d6027b2c2296b56a227f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 2 Jul 2019 22:08:36 +0200 Subject: [PATCH 01/37] [libcalamares] Add umask helper functions --- src/libcalamares/CMakeLists.txt | 1 + src/libcalamares/utils/UMask.cpp | 44 +++++++++++++++++++++++++ src/libcalamares/utils/UMask.h | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 src/libcalamares/utils/UMask.cpp create mode 100644 src/libcalamares/utils/UMask.h diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index f74c11b0c..032d933f4 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -46,6 +46,7 @@ set( libSources utils/PluginFactory.cpp utils/Retranslator.cpp utils/String.cpp + utils/UMask.cpp utils/Variant.cpp utils/Yaml.cpp ) diff --git a/src/libcalamares/utils/UMask.cpp b/src/libcalamares/utils/UMask.cpp new file mode 100644 index 000000000..358a52887 --- /dev/null +++ b/src/libcalamares/utils/UMask.cpp @@ -0,0 +1,44 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "UMask.h" + +#include +#include + +namespace CalamaresUtils +{ +mode_t +setUMask( mode_t u ) +{ + return umask( u ); +} + +UMask::UMask( mode_t u ) + : m_mode( setUMask( u ) ) +{ +} + +UMask::~UMask() +{ + setUMask( m_mode ); +} + +static_assert( UMask::Safe == ( S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ), "Bad permissions." ); + +} // namespace CalamaresUtils diff --git a/src/libcalamares/utils/UMask.h b/src/libcalamares/utils/UMask.h new file mode 100644 index 000000000..58b1a56ad --- /dev/null +++ b/src/libcalamares/utils/UMask.h @@ -0,0 +1,55 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef UTILS_UMASK_H +#define UTILS_UMASK_H + +#include "DllMacro.h" + +#include + +namespace CalamaresUtils +{ +/// @brief Wrapper for umask(2) +DLLEXPORT mode_t setUMask( mode_t u ); + +/** @brief RAII for setting and re-setting umask. + * + * Create an object of this class to set the umask, + * and the umask is reset to its original value when + * the object goes out of scope. + */ +class DLLEXPORT UMask +{ +public: + UMask( mode_t u ); + ~UMask(); + + /** @brief a "safe" umask + * + * This umask will switch off group- and other- permissions for + * files, so that the file cannot be read, written, or executed + * except by the owner. + */ + static constexpr mode_t Safe = 077; // octal! +private: + mode_t m_mode; +}; +} // namespace CalamaresUtils + +#endif From 0685e3a96c4f444228f4d9a7705524f222fb7853 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 2 Jul 2019 22:12:04 +0200 Subject: [PATCH 02/37] [libcalamares] Move tests of the utils classes into utils/ - while here, adjust include paths (to changed dir) - while here, apply new code formatting --- src/libcalamares/CMakeLists.txt | 2 +- src/libcalamares/{ => utils}/Tests.cpp | 45 ++++++++------------------ src/libcalamares/{ => utils}/Tests.h | 0 3 files changed, 15 insertions(+), 32 deletions(-) rename src/libcalamares/{ => utils}/Tests.cpp (81%) rename src/libcalamares/{ => utils}/Tests.h (100%) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 032d933f4..19bcc921d 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -147,7 +147,7 @@ install( FILES ${utilsHeaders} DESTINATION include/libcalam # if ( ECM_FOUND AND BUILD_TESTING ) ecm_add_test( - Tests.cpp + utils/Tests.cpp TEST_NAME libcalamarestest LINK_LIBRARIES diff --git a/src/libcalamares/Tests.cpp b/src/libcalamares/utils/Tests.cpp similarity index 81% rename from src/libcalamares/Tests.cpp rename to src/libcalamares/utils/Tests.cpp index 3b7624537..60e1b08bd 100644 --- a/src/libcalamares/Tests.cpp +++ b/src/libcalamares/utils/Tests.cpp @@ -18,9 +18,9 @@ #include "Tests.h" -#include "utils/CalamaresUtilsSystem.h" -#include "utils/Logger.h" -#include "utils/Yaml.h" +#include "CalamaresUtilsSystem.h" +#include "Logger.h" +#include "Yaml.h" #include @@ -28,13 +28,9 @@ QTEST_GUILESS_MAIN( LibCalamaresTests ) -LibCalamaresTests::LibCalamaresTests() -{ -} +LibCalamaresTests::LibCalamaresTests() {} -LibCalamaresTests::~LibCalamaresTests() -{ -} +LibCalamaresTests::~LibCalamaresTests() {} void LibCalamaresTests::initTestCase() @@ -46,9 +42,9 @@ LibCalamaresTests::testDebugLevels() { Logger::setupLogLevel( Logger::LOG_DISABLE ); - QCOMPARE( Logger::logLevel(), static_cast( Logger::LOG_DISABLE ) ); + QCOMPARE( Logger::logLevel(), static_cast< unsigned int >( Logger::LOG_DISABLE ) ); - for ( unsigned int level = 0; level <= Logger::LOGVERBOSE ; ++level ) + for ( unsigned int level = 0; level <= Logger::LOGVERBOSE; ++level ) { Logger::setupLogLevel( level ); QCOMPARE( Logger::logLevel(), level ); @@ -67,7 +63,9 @@ LibCalamaresTests::testLoadSaveYaml() QFile f( "settings.conf" ); // Find the nearest settings.conf to read for ( unsigned int up = 0; !f.exists() && ( up < 4 ); ++up ) + { f.setFileName( QString( "../" ) + f.fileName() ); + } cDebug() << QDir().absolutePath() << f.fileName() << f.exists(); QVERIFY( f.exists() ); @@ -75,7 +73,7 @@ LibCalamaresTests::testLoadSaveYaml() CalamaresUtils::saveYaml( "out.yaml", map ); auto other_map = CalamaresUtils::loadYaml( "out.yaml" ); - CalamaresUtils::saveYaml(" out2.yaml", other_map ); + CalamaresUtils::saveYaml( " out2.yaml", other_map ); QCOMPARE( map, other_map ); QFile::remove( "out.yaml" ); @@ -121,10 +119,7 @@ void LibCalamaresTests::testCommands() { using CalamaresUtils::System; - auto r = System::runCommand( - System::RunLocation::RunInHost, - { "/bin/ls", "/tmp" } - ); + auto r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls", "/tmp" } ); QVERIFY( r.getExitCode() == 0 ); @@ -136,25 +131,13 @@ LibCalamaresTests::testCommands() QVERIFY( !r.getOutput().contains( tfn.fileName() ) ); // Run ls again, now that the file exists - r = System::runCommand( - System::RunLocation::RunInHost, - { "/bin/ls", "/tmp" } - ); + r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls", "/tmp" } ); QVERIFY( r.getOutput().contains( tfn.fileName() ) ); // .. and without a working directory set, assume builddir != /tmp - r = System::runCommand( - System::RunLocation::RunInHost, - { "/bin/ls" } - ); + r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls" } ); QVERIFY( !r.getOutput().contains( tfn.fileName() ) ); - r = System::runCommand( - System::RunLocation::RunInHost, - { "/bin/ls" }, - "/tmp" - ); + r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls" }, "/tmp" ); QVERIFY( r.getOutput().contains( tfn.fileName() ) ); - - } diff --git a/src/libcalamares/Tests.h b/src/libcalamares/utils/Tests.h similarity index 100% rename from src/libcalamares/Tests.h rename to src/libcalamares/utils/Tests.h From aa3f909be7d2e99ffca387bf4fdbfcc2250549b6 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 2 Jul 2019 22:46:49 +0200 Subject: [PATCH 03/37] [libcalamares] Tests for UMask handling --- src/libcalamares/utils/Tests.cpp | 33 ++++++++++++++++++++++++++++++++ src/libcalamares/utils/Tests.h | 3 +++ 2 files changed, 36 insertions(+) diff --git a/src/libcalamares/utils/Tests.cpp b/src/libcalamares/utils/Tests.cpp index 60e1b08bd..2f2b7ff4b 100644 --- a/src/libcalamares/utils/Tests.cpp +++ b/src/libcalamares/utils/Tests.cpp @@ -20,12 +20,17 @@ #include "CalamaresUtilsSystem.h" #include "Logger.h" +#include "UMask.h" #include "Yaml.h" #include #include +#include +#include +#include + QTEST_GUILESS_MAIN( LibCalamaresTests ) LibCalamaresTests::LibCalamaresTests() {} @@ -141,3 +146,31 @@ LibCalamaresTests::testCommands() r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls" }, "/tmp" ); QVERIFY( r.getOutput().contains( tfn.fileName() ) ); } + +void +LibCalamaresTests::testUmask() +{ + struct stat mystat; + + QTemporaryFile ft; + QVERIFY( ft.open() ); + + mode_t m = CalamaresUtils::setUMask( 022 ); + QCOMPARE( CalamaresUtils::setUMask( m ), m ); + + for ( int i = 0; i <= 0777 /* octal! */; ++i ) + { + QByteArray name = ( ft.fileName() + QChar( '.' ) + QString::number( i, 8 ) ).toLatin1(); + CalamaresUtils::UMask um( i ); + int fd = creat( name, 0777 ); + QVERIFY( fd >= 0 ); + close( fd ); + QFileInfo fi( name ); + QVERIFY( fi.exists() ); + QCOMPARE( stat( name, &mystat ), 0 ); + QCOMPARE( mystat.st_mode & 0777, 0777 & ~i ); + QCOMPARE( unlink( name ), 0 ); + } + QCOMPARE( CalamaresUtils::setUMask( 022 ), m ); + QCOMPARE( CalamaresUtils::setUMask( m ), 022 ); +} diff --git a/src/libcalamares/utils/Tests.h b/src/libcalamares/utils/Tests.h index 5cdb3912b..d9140e0d0 100644 --- a/src/libcalamares/utils/Tests.h +++ b/src/libcalamares/utils/Tests.h @@ -36,6 +36,9 @@ private Q_SLOTS: void testLoadSaveYamlExtended(); // Do a find() in the src dir void testCommands(); + + /** @brief Test that all the UMask objects work correctly. */ + void testUmask(); }; #endif From 003096698627a527b589c0c929dda4d58f23fd93 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 3 Jul 2019 00:43:40 +0200 Subject: [PATCH 04/37] [initramfs] Set umask before update-initramfs SEE #1191 --- src/modules/initramfs/InitramfsJob.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index db9f8038a..b5cdc4f58 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -20,6 +20,7 @@ #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" +#include "utils/UMask.h" #include "utils/Variant.h" InitramfsJob::InitramfsJob( QObject* parent ) @@ -40,6 +41,8 @@ InitramfsJob::prettyName() const Calamares::JobResult InitramfsJob::exec() { + CalamaresUtils::UMask( CalamaresUtils::UMask::Safe ); + cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 10 ); From 1be81ec3b0cd421bd8e003e8a66a7cfb431a8dae Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 3 Jul 2019 21:20:08 +0200 Subject: [PATCH 05/37] [initramfs] Bump the timeout much higher - Use 120 seconds for update-initramfs, instead of 10. Previous Python code had no timeout at all, which wasn't so hot either. 10 seconds, though, is too short for slow CPU & slow disk. --- src/modules/initramfs/InitramfsJob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index b5cdc4f58..c04174837 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -45,7 +45,7 @@ InitramfsJob::exec() cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( - { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 10 ); + { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 120 ); return r.explainProcess( "update-initramfs", 10 ); } From e2aa4e59e20074906b1f49958bc3b2a1a1d582e6 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 11:36:37 +0200 Subject: [PATCH 06/37] CI: massage the coding style a little --- .clang-format | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 1eb0867e1..997ad379b 100644 --- a/.clang-format +++ b/.clang-format @@ -6,7 +6,7 @@ AllowAllParametersOfDeclarationOnNextLine: 'false' AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: 'false' AllowShortLoopsOnASingleLine: 'false' -AlwaysBreakAfterDefinitionReturnType: All +AlwaysBreakAfterReturnType: TopLevelDefinitions AlwaysBreakTemplateDeclarations: Yes BinPackArguments: 'false' BinPackParameters: 'false' @@ -19,7 +19,7 @@ FixNamespaceComments: 'true' IncludeBlocks: Preserve IndentWidth: '4' MaxEmptyLinesToKeep: '2' -NamespaceIndentation: Inner +NamespaceIndentation: None PointerAlignment: Left ReflowComments: 'false' SortIncludes: 'true' From 4825916f092d3c4b816107807ba7733e9dc5c78d Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 13:24:40 +0200 Subject: [PATCH 07/37] [branding] Improve log message when slideshow starts - Having just "component activated" is confusing in the whole mess of log messages around job activation. --- src/branding/default/show.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/branding/default/show.qml b/src/branding/default/show.qml index 43b407283..c989676dd 100644 --- a/src/branding/default/show.qml +++ b/src/branding/default/show.qml @@ -71,6 +71,6 @@ Presentation function onActivate() { presentation.currentSlide = 0; advanceTimer.running = true - console.log("Component activated"); + console.log("QML Component (default slideshow) activated"); } } From fff5a43469382489c09ad96cab00c48f6ed6df16 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 2 Jul 2019 21:50:43 +0200 Subject: [PATCH 08/37] Changes: document luksbootkey issue --- CHANGES | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGES b/CHANGES index 5085ad3c7..723747e44 100644 --- a/CHANGES +++ b/CHANGES @@ -6,11 +6,31 @@ website will have to do for older versions. # 3.2.11 (unreleased) # This release contains contributions from (alphabetically by first name): + - No other contributors this time around. + +This is a security release with no functional changes (except for +improved security) relative to 3.2.10. The Calamares team would like +to acknowledge the help of the following people in reporting and +understanding the issues (alphabetically by first name): + - Kevin Kofler + - Seth Arnold + - Simon Quigley + - Thomas Ward + ## Core ## +No core changes. + ## Modules ## + - *initramfs* could create an initramfs with insecure permissions. + Since the keyfile is included in the initramfs, an attacker could + read the file from the initramfs. #1190 + - *luksbootkeyfile* created a key file where a window of opportunity + existed where the key file could have too-lax file permissions. + #1191 CVE-2019-13179 + # 3.2.10 (2019-06-28) # From c2fa31573566fd668a3a9646f7bf0bb27cccecb6 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 2 Jul 2019 22:52:22 +0200 Subject: [PATCH 09/37] [luksbootkeyfile] Prepare for C++-ification - Mess around with the CMakeFile in preparation of new code - Drop the Python implementation already --- src/modules/luksbootkeyfile/CMakeLists.txt | 9 ++ src/modules/luksbootkeyfile/main.py | 103 --------------------- src/modules/luksbootkeyfile/module.desc | 5 - 3 files changed, 9 insertions(+), 108 deletions(-) create mode 100644 src/modules/luksbootkeyfile/CMakeLists.txt delete mode 100644 src/modules/luksbootkeyfile/main.py delete mode 100644 src/modules/luksbootkeyfile/module.desc diff --git a/src/modules/luksbootkeyfile/CMakeLists.txt b/src/modules/luksbootkeyfile/CMakeLists.txt new file mode 100644 index 000000000..be0f0fa28 --- /dev/null +++ b/src/modules/luksbootkeyfile/CMakeLists.txt @@ -0,0 +1,9 @@ +calamares_add_plugin( luksbootkeyfile + TYPE job + EXPORT_MACRO PLUGINDLLEXPORT_PRO + SOURCES + LuksBootKeyFileJob.cpp + LINK_PRIVATE_LIBRARIES + calamares + SHARED_LIB +) diff --git a/src/modules/luksbootkeyfile/main.py b/src/modules/luksbootkeyfile/main.py deleted file mode 100644 index fb0146cf8..000000000 --- a/src/modules/luksbootkeyfile/main.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# === This file is part of Calamares - === -# -# Copyright 2016, Teo Mrnjavac -# Copyright 2017, Alf Gaida -# Copyright 2017, 2019, Adriaan de Groot -# -# Calamares is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Calamares is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Calamares. If not, see . - -import libcalamares -from libcalamares.utils import check_target_env_call - - -import gettext -_ = gettext.translation("calamares-python", - localedir=libcalamares.utils.gettext_path(), - languages=libcalamares.utils.gettext_languages(), - fallback=True).gettext - - -def pretty_name(): - return _("Configuring LUKS key file.") - - -def run(): - """ - This module sets up a file crypto_keyfile.bin on the rootfs, assuming the - rootfs is LUKS encrypted and a passphrase is provided. This file is then - included in the initramfs and used for unlocking the rootfs from a - previously unlocked GRUB2 session. - :return: - """ - - partitions = libcalamares.globalstorage.value("partitions") - - if not partitions: - libcalamares.utils.warning("partitions is empty, {!s}".format(partitions)) - return (_("Configuration Error"), - _("No partitions are defined for
{!s}
to use." ).format("luksbootkey")) - - luks_root_device = "" - luks_root_passphrase = "" - - additional_luks_devices = [] - - for partition in partitions: - if partition["mountPoint"] == "/" and "luksMapperName" in partition: - luks_root_device = partition["device"] - luks_root_passphrase = partition["luksPassphrase"] - elif "luksMapperName" in partition and\ - (partition["mountPoint"] or partition["fs"] == "linuxswap"): - additional_luks_devices.append((partition["device"], - partition["luksPassphrase"])) - - if not luks_root_device: - return None - - if not luks_root_passphrase: - libcalamares.utils.debug("No LUKS passphrase, root {!s}".format(luks_root_device)) - return ( - _("Encrypted rootfs setup error"), - _("Rootfs partition {!s} is LUKS but no passphrase found.").format(luks_root_device)) - - # Generate random keyfile - check_target_env_call(["dd", - "bs=512", - "count=4", - "if=/dev/urandom", - "of=/crypto_keyfile.bin"]) - - check_target_env_call(["cryptsetup", - "luksAddKey", - luks_root_device, - "/crypto_keyfile.bin"], - luks_root_passphrase, - 15) # timeout 15s - - for additional_device in additional_luks_devices: - check_target_env_call(["cryptsetup", - "luksAddKey", - additional_device[0], - "/crypto_keyfile.bin"], - additional_device[1], - 15) # timeout 15s - - check_target_env_call(["chmod", - "g-rwx,o-rwx", - "/crypto_keyfile.bin"]) - - return None diff --git a/src/modules/luksbootkeyfile/module.desc b/src/modules/luksbootkeyfile/module.desc deleted file mode 100644 index 11a0173d5..000000000 --- a/src/modules/luksbootkeyfile/module.desc +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: "job" -name: "luksbootkeyfile" -interface: "python" -script: "main.py" From 676df86712c0726bff113341487ed8dfed4ae2f5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 3 Jul 2019 00:01:19 +0200 Subject: [PATCH 10/37] [luksbootkeyfile] Stub job implementation in C++ --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 80 +++++++++++++++++++ .../luksbootkeyfile/LuksBootKeyFileJob.h | 48 +++++++++++ 2 files changed, 128 insertions(+) create mode 100644 src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp create mode 100644 src/modules/luksbootkeyfile/LuksBootKeyFileJob.h diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp new file mode 100644 index 000000000..fb659cfab --- /dev/null +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -0,0 +1,80 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "LuksBootKeyFileJob.h" + +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" +#include "utils/Variant.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" + +LuksBootKeyFileJob::LuksBootKeyFileJob( QObject* parent ) + : Calamares::CppJob( parent ) +{ +} + +LuksBootKeyFileJob::~LuksBootKeyFileJob() {} + +QString +LuksBootKeyFileJob::prettyName() const +{ + return tr( "Configuring LUKS key file." ); +} + +struct LuksPassphrase +{ + QString device; + QString passphrase; +}; + +struct GlobalSettings +{ + GlobalSettings( const QVariant& partitions ) + : valid( false ) + { + cDebug() << partitions; + } + + QList< LuksPassphrase > filesystems; + bool valid; +}; + +Calamares::JobResult +LuksBootKeyFileJob::exec() +{ + const auto* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( !gs ) + { + return Calamares::JobResult::internalError( + "LukeBootKeyFile", "No GlobalStorage defined.", Calamares::JobResult::InvalidConfiguration ); + } + if ( !gs->contains( "partitions" ) ) + { + return Calamares::JobResult::internalError( + "LukeBootKeyFile", + tr( "No partitions are defined for
%1
to use." ).arg( "luksbootkeyfile" ), + Calamares::JobResult::InvalidConfiguration ); + } + + GlobalSettings s( gs->value( "partitions" ) ); + return Calamares::JobResult::ok(); +} + +CALAMARES_PLUGIN_FACTORY_DEFINITION( LuksBootKeyFileJobFactory, registerPlugin< LuksBootKeyFileJob >(); ) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.h b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.h new file mode 100644 index 000000000..2d4d6d319 --- /dev/null +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.h @@ -0,0 +1,48 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef LUKSBOOTKEYFILEJOB_H +#define LUKSBOOTKEYFILEJOB_H + +#include "CppJob.h" +#include "PluginDllMacro.h" +#include "utils/PluginFactory.h" + +#include +#include + +/** @brief Creates the LUKS boot key file and adds it to the cryptsetup. + * + * This job has no configuration, because it takes everything + * from the global storage settings set by others. + */ +class PLUGINDLLEXPORT LuksBootKeyFileJob : public Calamares::CppJob +{ + Q_OBJECT +public: + explicit LuksBootKeyFileJob( QObject* parent = nullptr ); + virtual ~LuksBootKeyFileJob() override; + + QString prettyName() const override; + + Calamares::JobResult exec() override; +}; + +CALAMARES_PLUGIN_FACTORY_DECLARATION( LuksBootKeyFileJobFactory ) + +#endif // LUKSBOOTKEYFILEJOB_H From 745b4b169322724dca15d408f0ce391940064520 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 13:17:34 +0200 Subject: [PATCH 11/37] [luksbootkeyfile] Extract partitioning keyphrases from GS --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index fb659cfab..c05cb970d 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -49,7 +49,37 @@ struct GlobalSettings GlobalSettings( const QVariant& partitions ) : valid( false ) { - cDebug() << partitions; + if ( partitions.canConvert() ) + { + filesystems = getPartitionInfo( partitions.toList() ); + valid = true; + } + } + + /** @brief Extract the luks passphrases setup. + * + * Given a list of partitions (as set up by the partitioning module, + * so there's maps with keys inside), returns just the list of + * luks passphrases for each device. + */ + static QList< LuksPassphrase > getPartitionInfo( const QVariantList& list ) + { + int count = 0; + for( const auto& p : list ) + { + if ( p.canConvert< QVariantMap>() ) + { + auto pinfo = p.toMap(); + QString device = pinfo["device"].toString(); + QString fs = pinfo["fs"].toString(); + QString mountPoint = pinfo["mountPoint"].toString(); + QString uuid = pinfo["uuid"].toString(); + + cDebug() << count << "D=" << device << mountPoint << '(' << fs << ')'; + } + count++; + } + return QList< LuksPassphrase >(); } QList< LuksPassphrase > filesystems; @@ -69,7 +99,7 @@ LuksBootKeyFileJob::exec() { return Calamares::JobResult::internalError( "LukeBootKeyFile", - tr( "No partitions are defined for
%1
to use." ).arg( "luksbootkeyfile" ), + tr( "No partitions are defined for LUKS to use." ).arg( "luksbootkeyfile" ), Calamares::JobResult::InvalidConfiguration ); } From f6c50564cd5f2314ee3b6ef449519bd193910b1b Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 13:45:02 +0200 Subject: [PATCH 12/37] [luksbootkeyfile] Extract devices that need cryptsetup - Rename classes and functions to be more descriptive (a LuksDevice is .. information for a LUKS device, for instance). - Move the smarts of unpacking a QVariantMap to LuksDevice. - Apply code formatting --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 68 +++++++++++++------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index c05cb970d..6589c5330 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -38,20 +38,41 @@ LuksBootKeyFileJob::prettyName() const return tr( "Configuring LUKS key file." ); } -struct LuksPassphrase +struct LuksDevice { + LuksDevice( const QMap< QString, QVariant >& pinfo ) + : isValid( false ) + , isRoot( false ) + { + if ( pinfo.contains( "luksMapperName" ) ) + { + QString fs = pinfo[ "fs" ].toString(); + QString mountPoint = pinfo[ "mountPoint" ].toString(); + + if ( !mountPoint.isEmpty() || fs == QStringLiteral( "linuxswap" ) ) + { + isValid = true; + isRoot = mountPoint == '/'; + device = pinfo[ "device" ].toString(); + passphrase = pinfo[ "luksPassphrase" ].toString(); + } + } + } + + bool isValid; + bool isRoot; QString device; QString passphrase; }; -struct GlobalSettings +struct LuksDeviceList { - GlobalSettings( const QVariant& partitions ) + LuksDeviceList( const QVariant& partitions ) : valid( false ) { - if ( partitions.canConvert() ) + if ( partitions.canConvert< QVariantList >() ) { - filesystems = getPartitionInfo( partitions.toList() ); + devices = getLuksDevices( partitions.toList() ); valid = true; } } @@ -62,27 +83,26 @@ struct GlobalSettings * so there's maps with keys inside), returns just the list of * luks passphrases for each device. */ - static QList< LuksPassphrase > getPartitionInfo( const QVariantList& list ) + static QList< LuksDevice > + getLuksDevices( const QVariantList& list ) { - int count = 0; - for( const auto& p : list ) - { - if ( p.canConvert< QVariantMap>() ) - { - auto pinfo = p.toMap(); - QString device = pinfo["device"].toString(); - QString fs = pinfo["fs"].toString(); - QString mountPoint = pinfo["mountPoint"].toString(); - QString uuid = pinfo["uuid"].toString(); + QList< LuksDevice > luksItems; - cDebug() << count << "D=" << device << mountPoint << '(' << fs << ')'; + for ( const auto& p : list ) + { + if ( p.canConvert< QVariantMap >() ) + { + LuksDevice d( p.toMap() ); + if ( d.isValid ) + { + luksItems.append( d ); + } } - count++; } - return QList< LuksPassphrase >(); + return luksItems; } - QList< LuksPassphrase > filesystems; + QList< LuksDevice > devices; bool valid; }; @@ -103,7 +123,13 @@ LuksBootKeyFileJob::exec() Calamares::JobResult::InvalidConfiguration ); } - GlobalSettings s( gs->value( "partitions" ) ); + LuksDeviceList s( gs->value( "partitions" ) ); + cDebug() << "There are" << s.devices.count() << "LUKS partitions"; + for ( const auto& p : s.devices ) + { + cDebug() << Logger::SubEntry << p.isRoot << p.device << p.passphrase; + } + return Calamares::JobResult::ok(); } From 8706b579ec6db3c9d5fe67486c62c4f1dc364cfe Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 15:14:06 +0200 Subject: [PATCH 13/37] [luksbootkeyfile] Stub out an implementation - stubs for the actual work to be done - program-flow for looping over all the work --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 67 +++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index 6589c5330..c9c1cc8a1 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -106,6 +106,18 @@ struct LuksDeviceList bool valid; }; +static bool +generateTargetKeyfile() +{ + return false; +} + +static bool +setupLuks( const LuksDevice& d ) +{ + return false; +} + Calamares::JobResult LuksBootKeyFileJob::exec() { @@ -117,17 +129,60 @@ LuksBootKeyFileJob::exec() } if ( !gs->contains( "partitions" ) ) { + cError() << "No GS[partitions] key."; return Calamares::JobResult::internalError( - "LukeBootKeyFile", - tr( "No partitions are defined for LUKS to use." ).arg( "luksbootkeyfile" ), - Calamares::JobResult::InvalidConfiguration ); + "LukeBootKeyFile", tr( "No partitions are defined." ), Calamares::JobResult::InvalidConfiguration ); } LuksDeviceList s( gs->value( "partitions" ) ); - cDebug() << "There are" << s.devices.count() << "LUKS partitions"; - for ( const auto& p : s.devices ) + if ( !s.valid ) { - cDebug() << Logger::SubEntry << p.isRoot << p.device << p.passphrase; + cError() << "GS[partitions] is invalid"; + return Calamares::JobResult::internalError( + "LukeBootKeyFile", tr( "No partitions are defined." ), Calamares::JobResult::InvalidConfiguration ); + } + + cDebug() << "There are" << s.devices.count() << "LUKS partitions"; + if ( s.devices.count() < 1 ) + { + cDebug() << Logger::SubEntry << "Nothing to do for LUKS."; + return Calamares::JobResult::ok(); + } + + auto it = std::partition( s.devices.begin(), s.devices.end(), []( const LuksDevice& d ) { return d.isRoot; } ); + for ( const auto& d : s.devices ) + { + cDebug() << Logger::SubEntry << d.isRoot << d.device << d.passphrase; + } + + if ( it == s.devices.begin() ) + { + // Then there was no root partition + cDebug() << Logger::SubEntry << "No root partition."; + return Calamares::JobResult::ok(); + } + + if ( s.devices.first().passphrase.isEmpty() ) + { + cDebug() << Logger::SubEntry << "No root passphrase."; + return Calamares::JobResult::error( + tr( "Encrypted rootfs setup error" ), + tr( "Root partition %1 is LUKS but no passphrase has been set." ).arg( s.devices.first().device ) ); + } + + if ( !generateTargetKeyfile() ) + { + return Calamares::JobResult::error( + tr( "Encrypted rootfs setup error" ), + tr( "Could not create LUKS key file for root partition %1." ).arg( s.devices.first().device ) ); + } + + for ( const auto& d : s.devices ) + { + if ( !setupLuks( d ) ) + return Calamares::JobResult::error( + tr( "Encrypted rootfs setup error" ), + tr( "Could configure LUKS key file on partition %1." ).arg( d.device ) ); } return Calamares::JobResult::ok(); From 856a2eaa1d766b32f2d3e76a8a41873a91d4890a Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 15:47:37 +0200 Subject: [PATCH 14/37] [luksbootkeyfile] Implement keyfile creation and use - Just copy the commands from the existing Python code, including nonsensical dd. --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index c9c1cc8a1..b1a5fffdb 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -106,16 +106,33 @@ struct LuksDeviceList bool valid; }; +static const char keyfile[] = "/crypto_keyfile.bin"; + static bool generateTargetKeyfile() { - return false; + auto r = CalamaresUtils::System::instance()->targetEnvCommand( + { "dd", "bs=512", "count=4", "if=/dev/urandom", QString( "of=%1" ).arg( keyfile ) } ); + if ( r.getExitCode() != 0 ) + { + cWarning() << "Could not create LUKS keyfile:" << r.getOutput() << "(exit code" << r.getExitCode() << ')'; + return false; + } + return true; } static bool setupLuks( const LuksDevice& d ) { - return false; + auto r = CalamaresUtils::System::instance()->targetEnvCommand( + { "cryptsetup", "luksAddKey", d.device, keyfile }, QString(), d.passphrase, 15 ); + if ( r.getExitCode() != 0 ) + { + cWarning() << "Could not configure LUKS keyfile on" << d.device << ':' << r.getOutput() << "(exit code" + << r.getExitCode() << ')'; + return false; + } + return true; } Calamares::JobResult From af2a900276ee1d8b1fe84df96a6cd9005bf505ae Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 15:55:54 +0200 Subject: [PATCH 15/37] [luksbootkeyfile] Fix lax permissions on file. --- src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index b1a5fffdb..9b49b91cb 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -20,6 +20,7 @@ #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" +#include "utils/UMask.h" #include "utils/Variant.h" #include "GlobalStorage.h" @@ -111,6 +112,7 @@ static const char keyfile[] = "/crypto_keyfile.bin"; static bool generateTargetKeyfile() { + CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "dd", "bs=512", "count=4", "if=/dev/urandom", QString( "of=%1" ).arg( keyfile ) } ); if ( r.getExitCode() != 0 ) From e2028cf85b02a4d8fcb16fe88bb905893aaaaa17 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 16:20:26 +0200 Subject: [PATCH 16/37] [libcalamaresui] Warnings--, no copy constructor for CDebug --- src/libcalamaresui/utils/DebugWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcalamaresui/utils/DebugWindow.cpp b/src/libcalamaresui/utils/DebugWindow.cpp index 62ab504d3..ed016dd97 100644 --- a/src/libcalamaresui/utils/DebugWindow.cpp +++ b/src/libcalamaresui/utils/DebugWindow.cpp @@ -223,7 +223,7 @@ DebugWindow::DebugWindow() { for ( auto* w : qApp->topLevelWidgets() ) { - auto deb = cDebug(); + Logger::CDebug deb; dumpWidgetTree( deb, w, 0 ); } }); From 97e44f971d0a003aacaa82aebd64baa698325aea Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 16:23:21 +0200 Subject: [PATCH 17/37] [initramfs] That's not a safety setting - Don't confuse a method declaration with an object. - Thanks clang for warning me. --- src/modules/initramfs/InitramfsJob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index c04174837..d8a9ed6c3 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -41,7 +41,7 @@ InitramfsJob::prettyName() const Calamares::JobResult InitramfsJob::exec() { - CalamaresUtils::UMask( CalamaresUtils::UMask::Safe ); + CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( From 8a7884d47601d468fdd6b3f9dab7150ad21554fe Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 19:30:11 +0200 Subject: [PATCH 18/37] [luksbootkeyfile] More debugging of the crypt file --- src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index 9b49b91cb..e521e83a6 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -120,6 +120,9 @@ generateTargetKeyfile() cWarning() << "Could not create LUKS keyfile:" << r.getOutput() << "(exit code" << r.getExitCode() << ')'; return false; } + // Give ample time to check that the file was created correctly + r = CalamaresUtils::System::instance()->targetEnvCommand( { "ls", "-la", "/" } ); + cDebug() << "In target system" << r.getOutput(); return true; } From 7d7d4c69ef7bd57809e11d4c0ec486dcdfdd7ffe Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 19:37:37 +0200 Subject: [PATCH 19/37] [luksbootkeyfile] Don't log passphrase --- src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index e521e83a6..06cb5f9cd 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -174,7 +174,8 @@ LuksBootKeyFileJob::exec() auto it = std::partition( s.devices.begin(), s.devices.end(), []( const LuksDevice& d ) { return d.isRoot; } ); for ( const auto& d : s.devices ) { - cDebug() << Logger::SubEntry << d.isRoot << d.device << d.passphrase; + cDebug() << Logger::SubEntry << ( d.isRoot ? "root" : "dev." ) << d.device << "passphrase?" + << !d.passphrase.isEmpty(); } if ( it == s.devices.begin() ) From efd409cf78759c48280a167d2463295ae37fdb70 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 19:38:10 +0200 Subject: [PATCH 20/37] [luksbootkeyfile] Refactor static function to outside class --- .../luksbootkeyfile/LuksBootKeyFileJob.cpp | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index 06cb5f9cd..c84e79083 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -66,6 +66,31 @@ struct LuksDevice QString passphrase; }; +/** @brief Extract the luks passphrases setup. + * + * Given a list of partitions (as set up by the partitioning module, + * so there's maps with keys inside), returns just the list of + * luks passphrases for each device. + */ +static QList< LuksDevice > +getLuksDevices( const QVariantList& list ) +{ + QList< LuksDevice > luksItems; + + for ( const auto& p : list ) + { + if ( p.canConvert< QVariantMap >() ) + { + LuksDevice d( p.toMap() ); + if ( d.isValid ) + { + luksItems.append( d ); + } + } + } + return luksItems; +} + struct LuksDeviceList { LuksDeviceList( const QVariant& partitions ) @@ -78,31 +103,6 @@ struct LuksDeviceList } } - /** @brief Extract the luks passphrases setup. - * - * Given a list of partitions (as set up by the partitioning module, - * so there's maps with keys inside), returns just the list of - * luks passphrases for each device. - */ - static QList< LuksDevice > - getLuksDevices( const QVariantList& list ) - { - QList< LuksDevice > luksItems; - - for ( const auto& p : list ) - { - if ( p.canConvert< QVariantMap >() ) - { - LuksDevice d( p.toMap() ); - if ( d.isValid ) - { - luksItems.append( d ); - } - } - } - return luksItems; - } - QList< LuksDevice > devices; bool valid; }; From d5340f97431d0e94ba4b284511a4cdc4354757a0 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 20:05:48 +0200 Subject: [PATCH 21/37] [initramfs] Drop timeout entirely, even two minutes too short --- src/modules/initramfs/InitramfsJob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index d8a9ed6c3..e96855d23 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -45,7 +45,7 @@ InitramfsJob::exec() cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( - { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 120 ); + { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 0 ); return r.explainProcess( "update-initramfs", 10 ); } From bb6530577db46b0c976f8e0fed29949b507da304 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 20:21:13 +0200 Subject: [PATCH 22/37] [initcpio] Replace Python implementation with C++ - This is a simple variation on the theme of things-that-call-a- initramfs-updater, so the code is mostly a copy of initramfs/ module. I didn't even bother to strip out the configuration- handling (I figure it might be good for *something*) so now "" and "$uname" are valid kernel names as well. - Fixes security issue where the initramfs ends up readable by all, and that includes the cryptfile for LUKS. SEE #1190 --- src/modules/initcpio/CMakeLists.txt | 9 ++++ src/modules/initcpio/InitcpioJob.cpp | 77 ++++++++++++++++++++++++++++ src/modules/initcpio/InitcpioJob.h | 49 ++++++++++++++++++ src/modules/initcpio/initcpio.conf | 15 ++++++ src/modules/initcpio/main.py | 50 ------------------ src/modules/initcpio/module.desc | 5 -- 6 files changed, 150 insertions(+), 55 deletions(-) create mode 100644 src/modules/initcpio/CMakeLists.txt create mode 100644 src/modules/initcpio/InitcpioJob.cpp create mode 100644 src/modules/initcpio/InitcpioJob.h delete mode 100644 src/modules/initcpio/main.py delete mode 100644 src/modules/initcpio/module.desc diff --git a/src/modules/initcpio/CMakeLists.txt b/src/modules/initcpio/CMakeLists.txt new file mode 100644 index 000000000..d35a12f06 --- /dev/null +++ b/src/modules/initcpio/CMakeLists.txt @@ -0,0 +1,9 @@ +calamares_add_plugin( initcpio + TYPE job + EXPORT_MACRO PLUGINDLLEXPORT_PRO + SOURCES + InitcpioJob.cpp + LINK_PRIVATE_LIBRARIES + calamares + SHARED_LIB +) diff --git a/src/modules/initcpio/InitcpioJob.cpp b/src/modules/initcpio/InitcpioJob.cpp new file mode 100644 index 000000000..89c8a906d --- /dev/null +++ b/src/modules/initcpio/InitcpioJob.cpp @@ -0,0 +1,77 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "InitcpioJob.h" + +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" +#include "utils/UMask.h" +#include "utils/Variant.h" + +InitcpioJob::InitcpioJob( QObject* parent ) + : Calamares::CppJob( parent ) +{ +} + +InitcpioJob::~InitcpioJob() {} + + +QString +InitcpioJob::prettyName() const +{ + return tr( "Creating initramfs with mkinitcpio." ); +} + + +Calamares::JobResult +InitcpioJob::exec() +{ + CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); + + cDebug() << "Updating initramfs with kernel" << m_kernel; + auto r = CalamaresUtils::System::instance()->targetEnvCommand( + { "mkinitcpio", "-p", m_kernel }, QString(), QString(), 0 ); + return r.explainProcess( "mkinitcpio", 10 ); +} + +void +InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap ) +{ + m_kernel = CalamaresUtils::getString( configurationMap, "kernel" ); + if ( m_kernel.isEmpty() ) + { + m_kernel = QStringLiteral( "all" ); + } + else if ( m_kernel == "$uname" ) + { + auto r = CalamaresUtils::System::runCommand( + CalamaresUtils::System::RunLocation::RunInHost, { "/bin/uname", "-r" }, QString(), QString(), 3 ); + if ( r.getExitCode() == 0 ) + { + m_kernel = r.getOutput(); + cDebug() << "*initcpio* using running kernel" << m_kernel; + } + else + { + cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation + << r.getExitCode() << r.getOutput(); + } + } +} + +CALAMARES_PLUGIN_FACTORY_DEFINITION( InitcpioJobFactory, registerPlugin< InitcpioJob >(); ) diff --git a/src/modules/initcpio/InitcpioJob.h b/src/modules/initcpio/InitcpioJob.h new file mode 100644 index 000000000..7c0bcf2df --- /dev/null +++ b/src/modules/initcpio/InitcpioJob.h @@ -0,0 +1,49 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef INITCPIOJOB_H +#define INITCPIOJOB_H + +#include "CppJob.h" +#include "PluginDllMacro.h" +#include "utils/PluginFactory.h" + +#include +#include + +class PLUGINDLLEXPORT InitcpioJob : public Calamares::CppJob +{ + Q_OBJECT + +public: + explicit InitcpioJob( QObject* parent = nullptr ); + virtual ~InitcpioJob() override; + + QString prettyName() const override; + + Calamares::JobResult exec() override; + + void setConfigurationMap( const QVariantMap& configurationMap ) override; + +private: + QString m_kernel; +}; + +CALAMARES_PLUGIN_FACTORY_DECLARATION( InitcpioJobFactory ) + +#endif // INITCPIOJOB_H diff --git a/src/modules/initcpio/initcpio.conf b/src/modules/initcpio/initcpio.conf index 466a8785d..487a0289d 100644 --- a/src/modules/initcpio/initcpio.conf +++ b/src/modules/initcpio/initcpio.conf @@ -1,3 +1,18 @@ # Run mkinitcpio(8) with the given preset value --- +# There is only one configuration item for this module, +# the kernel to be loaded. This can have the following +# values: +# - empty or unset, interpreted as "all" +# - the literal string "$uname" (without quotes, with dollar), +# which will use the output of `uname -r` to determine the +# running kernel, and use that. +# - any other string. +# +# Whatever is set, that string is passed as *preset* argument to the +# `-p` option of *mkinitcpio*. Take care that both "$uname" operates +# in the host system, and might not be correct if the target system is +# updated (to a newer kernel) as part of the installation. +# +# Note that "all" is probably not a good preset to use either. kernel: linux312 diff --git a/src/modules/initcpio/main.py b/src/modules/initcpio/main.py deleted file mode 100644 index 796f68721..000000000 --- a/src/modules/initcpio/main.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# === This file is part of Calamares - === -# -# Copyright 2014, Philip Müller -# Copyright 2019, Adriaan de Groot -# -# Calamares is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Calamares is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Calamares. If not, see . - -import libcalamares -from libcalamares.utils import check_target_env_call - -import gettext -_ = gettext.translation("calamares-python", - localedir=libcalamares.utils.gettext_path(), - languages=libcalamares.utils.gettext_languages(), - fallback=True).gettext - - -def pretty_name(): - return _("Creating initramfs with mkinitcpio.") - -def run(): - """ Calls routine to create kernel initramfs image. - - :return: - """ - from subprocess import CalledProcessError - - kernel = libcalamares.job.configuration['kernel'] - try: - check_target_env_call(['mkinitcpio', '-p', kernel]) - except CalledProcessError as e: - libcalamares.utils.warning(str(e)) - return ( _( "Process Failed" ), - _( "Process
mkinitcpio
failed with error code {!s}. The command was
{!s}
." ).format( e.returncode, e.cmd ) ) - - return None diff --git a/src/modules/initcpio/module.desc b/src/modules/initcpio/module.desc deleted file mode 100644 index f84fc43a8..000000000 --- a/src/modules/initcpio/module.desc +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: "job" -name: "initcpio" -interface: "python" -script: "main.py" From 315e1ac54e74852100543ced3dffbd8c1eb688a1 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 4 Jul 2019 22:08:36 +0200 Subject: [PATCH 23/37] [luksbootkeyfile] Improve logging to distinguish from other modules --- src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp index c84e79083..292c768a9 100644 --- a/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp +++ b/src/modules/luksbootkeyfile/LuksBootKeyFileJob.cpp @@ -122,7 +122,7 @@ generateTargetKeyfile() } // Give ample time to check that the file was created correctly r = CalamaresUtils::System::instance()->targetEnvCommand( { "ls", "-la", "/" } ); - cDebug() << "In target system" << r.getOutput(); + cDebug() << "In target system after creating LUKS file" << r.getOutput(); return true; } From d220fcea2416a97b2909ffd52210be5579723da8 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 10:47:31 +0200 Subject: [PATCH 24/37] CI: allow different versions of clang-format --- ci/calamaresstyle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ci/calamaresstyle b/ci/calamaresstyle index 11c587ada..a877de7d1 100755 --- a/ci/calamaresstyle +++ b/ci/calamaresstyle @@ -9,7 +9,13 @@ set -e AS=$( which astyle ) -CF=$( which clang-format-7 ) + +for _cf in clang-format-7 clang-format-8 clang-format70 clang-format80 +do + # Not an error if this particular clang-format isn't found + CF=$( which $_cf || true ) + test -n "$CF" && break +done test -n "$AS" || { echo "! No astyle found in PATH"; exit 1 ; } test -n "$CF" || { echo "! No clang-format-7 found in PATH"; exit 1 ; } From b6974614974842020be591adccf8ebbe5c50ee13 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 11:29:14 +0200 Subject: [PATCH 25/37] [libcalamares] Add System::createTargetFile() - Calamares may need to create files in the target system; provide a convenient API for doing so. - This is mostly intended for small files with constant contents. --- .../utils/CalamaresUtilsSystem.cpp | 51 +++++++++++++++++++ src/libcalamares/utils/CalamaresUtilsSystem.h | 14 +++++ 2 files changed, 65 insertions(+) diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp index 5990fbc42..698a96f30 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp +++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp @@ -243,6 +243,57 @@ System::runCommand( return ProcessResult(r, output); } +QString +System::createTargetFile( const QString& path, const QByteArray& contents ) +{ + QString completePath; + + if ( doChroot() ) + { + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr; + + if ( !gs || !gs->contains( "rootMountPoint" ) ) + { + cWarning() << "No rootMountPoint in global storage, cannot create target file" << path; + return QString(); + } + + completePath = gs->value( "rootMountPoint" ).toString() + '/' + path; + } + else + { + completePath = QStringLiteral( "/" ) + path; + } + + QFile f( completePath ); + if ( f.exists() ) + { + return QString(); + } + + QIODevice::OpenMode m = +#if QT_VERSION >= QT_VERSION_CHECK( 5, 11, 0 ) + // New flag from Qt 5.11, implies WriteOnly + QIODevice::NewOnly | +#endif + QIODevice::WriteOnly | QIODevice::Truncate; + + if ( !f.open( m ) ) + { + return QString(); + } + + if ( f.write( contents ) != contents.size() ) + { + f.close(); + f.remove(); + return QString(); + } + + f.close(); + return QFileInfo( f ).canonicalFilePath(); +} + QPair System::getTotalMemoryB() const diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.h b/src/libcalamares/utils/CalamaresUtilsSystem.h index c17d52e93..8c8e61a5e 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.h +++ b/src/libcalamares/utils/CalamaresUtilsSystem.h @@ -205,6 +205,20 @@ public: return targetEnvOutput( QStringList{ command }, output, workingPath, stdInput, timeoutSec ); } + /** @brief Create a (small-ish) file in the target system. + * + * @param path Path to the file; this is **always** interpreted + * from the root of the target system (whatever that may be, + * but / in the chroot, or / in OEM modes). + * @param contents Actual content of the file. + * + * Will not overwrite files. Returns an empty string if the + * target file already exists. + * + * @return The complete canonical path to the target file, or empty on failure. + */ + QString createTargetFile( const QString& path, const QByteArray& contents ); + /** * @brief getTotalMemoryB returns the total main memory, in bytes. * From 43eb664e7d44d963bb7b82d03215d84b47100ba0 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 11:43:40 +0200 Subject: [PATCH 26/37] [initramfs] Configure mkinitramfs to be safe SEE #1191 --- src/modules/initramfs/InitramfsJob.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index e96855d23..c96bbb059 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -44,6 +44,17 @@ InitramfsJob::exec() CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); cDebug() << "Updating initramfs with kernel" << m_kernel; + + // First make sure we generate a safe initramfs with suitable permissions. + static const char confFile[] = "/etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf"; + static const char contents[] = "UMASK=0077\n"; + if ( CalamaresUtils::System::instance()->createTargetFile( confFile, QByteArray( contents ) ).isEmpty() ) + { + cWarning() << Logger::SubEntry << "Could not configure safe UMASK for initramfs."; + // But continue anyway. + } + + // And then do the ACTUAL work. auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 0 ); return r.explainProcess( "update-initramfs", 10 ); From 1a8543537265cd63bcb38d736c5cb0e15adb3fc0 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 13:05:49 +0200 Subject: [PATCH 27/37] [libcalamares] Get target path relative to host / --- .../utils/CalamaresUtilsSystem.cpp | 14 +++++++++- src/libcalamares/utils/CalamaresUtilsSystem.h | 26 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp index 698a96f30..10c76e482 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp +++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp @@ -244,7 +244,7 @@ System::runCommand( } QString -System::createTargetFile( const QString& path, const QByteArray& contents ) +System::targetPath( const QString& path ) const { QString completePath; @@ -265,6 +265,18 @@ System::createTargetFile( const QString& path, const QByteArray& contents ) completePath = QStringLiteral( "/" ) + path; } + return completePath; +} + +QString +System::createTargetFile( const QString& path, const QByteArray& contents ) const +{ + QString completePath = targetPath( path ); + if ( completePath.isEmpty() ) + { + return QString(); + } + QFile f( completePath ); if ( f.exists() ) { diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.h b/src/libcalamares/utils/CalamaresUtilsSystem.h index 8c8e61a5e..f778b67c9 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.h +++ b/src/libcalamares/utils/CalamaresUtilsSystem.h @@ -205,9 +205,27 @@ public: return targetEnvOutput( QStringList{ command }, output, workingPath, stdInput, timeoutSec ); } + + /** @brief Gets a path to a file in the target system, from the host. + * + * @param path Path to the file; this is interpreted + * from the root of the target system (whatever that may be, + * but / in the chroot, or / in OEM modes). + * + * @return The complete path to the target file, from + * the root of the host system, or empty on failure. + * + * For instance, during installation where the target root is + * mounted on /tmp/calamares-something, asking for targetPath("/etc/passwd") + * will give you /tmp/calamares-something/etc/passwd. + * + * No attempt is made to canonicalize anything, since paths might not exist. + */ + DLLEXPORT QString targetPath( const QString& path ) const; + /** @brief Create a (small-ish) file in the target system. * - * @param path Path to the file; this is **always** interpreted + * @param path Path to the file; this is interpreted * from the root of the target system (whatever that may be, * but / in the chroot, or / in OEM modes). * @param contents Actual content of the file. @@ -215,9 +233,11 @@ public: * Will not overwrite files. Returns an empty string if the * target file already exists. * - * @return The complete canonical path to the target file, or empty on failure. + * @return The complete canonical path to the target file from the + * root of the host system, or empty on failure. (Here, it is + * possible to be canonical because the file exists). */ - QString createTargetFile( const QString& path, const QByteArray& contents ); + DLLEXPORT QString createTargetFile( const QString& path, const QByteArray& contents ) const; /** * @brief getTotalMemoryB returns the total main memory, in bytes. From 5f6efd2822ada666c29effd8d3b0ce9eb79e1b63 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 13:17:55 +0200 Subject: [PATCH 28/37] [initcpio] Improve security by making initramfs files not world-readable --- src/modules/initcpio/InitcpioJob.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/modules/initcpio/InitcpioJob.cpp b/src/modules/initcpio/InitcpioJob.cpp index 89c8a906d..0b96ddcd2 100644 --- a/src/modules/initcpio/InitcpioJob.cpp +++ b/src/modules/initcpio/InitcpioJob.cpp @@ -23,6 +23,9 @@ #include "utils/UMask.h" #include "utils/Variant.h" +#include +#include + InitcpioJob::InitcpioJob( QObject* parent ) : Calamares::CppJob( parent ) { @@ -37,12 +40,31 @@ InitcpioJob::prettyName() const return tr( "Creating initramfs with mkinitcpio." ); } +static void +fixPermissions( const QDir& d ) +{ + for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) ) + { + QFile f( fi.absoluteFilePath() ); + if ( f.exists() ) + { + cDebug() << "initcpio fixing permissions for" << f.fileName(); + f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner ); + } + } +} Calamares::JobResult InitcpioJob::exec() { CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); + QDir d( CalamaresUtils::System::instance()->targetPath( "/boot" ) ); + if ( d.exists() ) + { + fixPermissions( d ); + } + cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "mkinitcpio", "-p", m_kernel }, QString(), QString(), 0 ); From 39d618c61e7ecdc9c068c799c26bcf811cd867ae Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 13:28:32 +0200 Subject: [PATCH 29/37] [initcpio] Simple test for fixPermissions() --- src/modules/initcpio/CMakeLists.txt | 17 ++++++++ src/modules/initcpio/InitcpioJob.cpp | 2 +- src/modules/initcpio/Tests.cpp | 59 ++++++++++++++++++++++++++++ src/modules/initcpio/Tests.h | 36 +++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/modules/initcpio/Tests.cpp create mode 100644 src/modules/initcpio/Tests.h diff --git a/src/modules/initcpio/CMakeLists.txt b/src/modules/initcpio/CMakeLists.txt index d35a12f06..990220b10 100644 --- a/src/modules/initcpio/CMakeLists.txt +++ b/src/modules/initcpio/CMakeLists.txt @@ -7,3 +7,20 @@ calamares_add_plugin( initcpio calamares SHARED_LIB ) + +if( ECM_FOUND AND BUILD_TESTING ) + ecm_add_test( + Tests.cpp + TEST_NAME + initcpiotest + LINK_LIBRARIES + ${CALAMARES_LIBRARIES} + calamares + calamares_job_initcpio # From above + ${YAMLCPP_LIBRARY} + Qt5::Core + Qt5::Test + ) + set_target_properties( initcpiotest PROPERTIES AUTOMOC TRUE ) + target_include_directories( initcpiotest PRIVATE /usr/local/include ) +endif() diff --git a/src/modules/initcpio/InitcpioJob.cpp b/src/modules/initcpio/InitcpioJob.cpp index 0b96ddcd2..d0d825cbf 100644 --- a/src/modules/initcpio/InitcpioJob.cpp +++ b/src/modules/initcpio/InitcpioJob.cpp @@ -40,7 +40,7 @@ InitcpioJob::prettyName() const return tr( "Creating initramfs with mkinitcpio." ); } -static void +void fixPermissions( const QDir& d ) { for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) ) diff --git a/src/modules/initcpio/Tests.cpp b/src/modules/initcpio/Tests.cpp new file mode 100644 index 000000000..e0590ba25 --- /dev/null +++ b/src/modules/initcpio/Tests.cpp @@ -0,0 +1,59 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "Tests.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "Settings.h" + +#include "utils/Logger.h" +#include "utils/Yaml.h" + +#include + +#include +#include + +extern void fixPermissions( const QDir& d ); + +QTEST_GUILESS_MAIN( InitcpioTests ) + +InitcpioTests::InitcpioTests() +{ +} + +InitcpioTests::~InitcpioTests() +{ +} + +void +InitcpioTests::initTestCase() +{ +} + +void InitcpioTests::testFixPermissions() +{ + Logger::setupLogLevel( Logger::LOGDEBUG ); + cDebug() << "Fixing up /boot"; + fixPermissions( QDir( "/boot" ) ); + cDebug() << "Fixing up /nonexistent"; + fixPermissions( QDir( "/nonexistent/nonexistent" ) ); + QVERIFY( true ); +} + diff --git a/src/modules/initcpio/Tests.h b/src/modules/initcpio/Tests.h new file mode 100644 index 000000000..5bab26d3f --- /dev/null +++ b/src/modules/initcpio/Tests.h @@ -0,0 +1,36 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef TESTS_H +#define TESTS_H + +#include + +class InitcpioTests : public QObject +{ + Q_OBJECT +public: + InitcpioTests(); + ~InitcpioTests() override; + +private Q_SLOTS: + void initTestCase(); + void testFixPermissions(); +}; + +#endif From 76ce0e4f2b85522509d7c1abfd81c5eb7d3cfacc Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 23:20:19 +0200 Subject: [PATCH 30/37] [libcalamares] Don't crash when creating System object - In tests, a System object might be created without first setting up a JobQueue. In that case, there's no instance, so no GS to insert into. Avoid crash here. --- src/libcalamares/utils/CalamaresUtilsSystem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp index 10c76e482..7e55e6119 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp +++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp @@ -85,8 +85,10 @@ System::System( bool doChroot, QObject* parent ) { Q_ASSERT( !s_instance ); s_instance = this; - if ( !doChroot ) + if ( !doChroot && Calamares::JobQueue::instance() && Calamares::JobQueue::instance()->globalStorage() ) + { Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" ); + } } From a761bf02807c74fdf36092ecd2172d51a28b145d Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 23:21:24 +0200 Subject: [PATCH 31/37] [initramfs] Add tests - These tests exercise the createTargetFile() logic, which is essential for creating a safe initramfs configuration snippet. - Could be moved into libcalamares instead, since the tests are not really initramfs specific. --- src/modules/initramfs/CMakeLists.txt | 17 +++++ src/modules/initramfs/Tests.cpp | 96 ++++++++++++++++++++++++++++ src/modules/initramfs/Tests.h | 39 +++++++++++ 3 files changed, 152 insertions(+) create mode 100644 src/modules/initramfs/Tests.cpp create mode 100644 src/modules/initramfs/Tests.h diff --git a/src/modules/initramfs/CMakeLists.txt b/src/modules/initramfs/CMakeLists.txt index 79bb650c5..c2496b2a1 100644 --- a/src/modules/initramfs/CMakeLists.txt +++ b/src/modules/initramfs/CMakeLists.txt @@ -7,3 +7,20 @@ calamares_add_plugin( initramfs calamares SHARED_LIB ) + +if( ECM_FOUND AND BUILD_TESTING ) + ecm_add_test( + Tests.cpp + TEST_NAME + initramfstest + LINK_LIBRARIES + ${CALAMARES_LIBRARIES} + calamares + calamares_job_initramfs # From above + ${YAMLCPP_LIBRARY} + Qt5::Core + Qt5::Test + ) + set_target_properties( initramfstest PROPERTIES AUTOMOC TRUE ) + target_include_directories( initramfstest PRIVATE /usr/local/include ) +endif() diff --git a/src/modules/initramfs/Tests.cpp b/src/modules/initramfs/Tests.cpp new file mode 100644 index 000000000..936c94097 --- /dev/null +++ b/src/modules/initramfs/Tests.cpp @@ -0,0 +1,96 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "Tests.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "Settings.h" + +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" +#include "utils/Yaml.h" + +#include + +#include +#include + +QTEST_GUILESS_MAIN( InitramfsTests ) + +InitramfsTests::InitramfsTests() +{ +} + +InitramfsTests::~InitramfsTests() +{ +} + +void +InitramfsTests::initTestCase() +{ + Logger::setupLogLevel( Logger::LOGDEBUG ); +} + +static const char contents[] = "UMASK=0077\n"; +static const char confFile[] = "/tmp/calamares-safe-umask"; + +void InitramfsTests::cleanup() +{ + QFile::remove( confFile ); +} + +void InitramfsTests::testCreateHostFile() +{ + + CalamaresUtils::System s( false ); // don't chroot + QString path = s.createTargetFile( confFile, QByteArray( contents ) ); + QVERIFY( !path.isEmpty() ); + QCOMPARE( path, confFile ); // don't chroot, so path create relative to / + QVERIFY( QFile::exists( confFile ) ); + + QFileInfo fi( confFile ); + QVERIFY( fi.exists() ); + QCOMPARE( fi.size(), sizeof( contents )-1 ); // don't count trailing NUL + + QFile::remove( confFile ); +} + +void InitramfsTests::testCreateTargetFile() +{ + static const char short_confFile[] = "/calamares-safe-umask"; + + CalamaresUtils::System s( true ); + QString path = s.createTargetFile( short_confFile, QByteArray( contents ) ); + QVERIFY( path.isEmpty() ); // because no rootmountpoint is set + + Calamares::JobQueue j; + j.globalStorage()->insert( "rootMountPoint", "/tmp" ); + + path = s.createTargetFile( short_confFile, QByteArray( contents ) ); + QVERIFY( path.endsWith( short_confFile ) ); // chroot, so path create relative to + QVERIFY( path.startsWith( "/tmp/" ) ); + QVERIFY( QFile::exists( path ) ); + + QFileInfo fi( path ); + QVERIFY( fi.exists() ); + QCOMPARE( fi.size(), sizeof( contents )-1 ); // don't count trailing NUL + + QFile::remove( path ); + +} diff --git a/src/modules/initramfs/Tests.h b/src/modules/initramfs/Tests.h new file mode 100644 index 000000000..01394d4fa --- /dev/null +++ b/src/modules/initramfs/Tests.h @@ -0,0 +1,39 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef TESTS_H +#define TESTS_H + +#include + +class InitramfsTests : public QObject +{ + Q_OBJECT +public: + InitramfsTests(); + ~InitramfsTests() override; + +private Q_SLOTS: + void initTestCase(); + void cleanup(); + + void testCreateHostFile(); + void testCreateTargetFile(); +}; + +#endif From 263c0166c6dd054efa0e154c09a344aeed711bf6 Mon Sep 17 00:00:00 2001 From: Calamares CI Date: Fri, 5 Jul 2019 23:31:28 +0200 Subject: [PATCH 32/37] i18n: [calamares] Automatic merge of Transifex translations --- lang/calamares_cs_CZ.ts | 8 ++++---- lang/calamares_fi_FI.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lang/calamares_cs_CZ.ts b/lang/calamares_cs_CZ.ts index 058848a3f..1f6ef2129 100644 --- a/lang/calamares_cs_CZ.ts +++ b/lang/calamares_cs_CZ.ts @@ -99,12 +99,12 @@ Reload Stylesheet - + Znovunačíst sešit se styly Widget Tree - + Strom widgetu @@ -159,12 +159,12 @@ Run command '%1' in target system. - + Spustit v cílovém systému příkaz „%1“. Run command '%1'. - + Spustit příkaz „%1“ diff --git a/lang/calamares_fi_FI.ts b/lang/calamares_fi_FI.ts index 22a7a81f6..be8928448 100644 --- a/lang/calamares_fi_FI.ts +++ b/lang/calamares_fi_FI.ts @@ -210,12 +210,12 @@ Waiting for %n module(s). - + Odotetaan %n moduuli(t).Odotetaan %n moduuli(t). (%n second(s)) - + (%n sekunttia(s))(%n sekunttia(s)) From b43dee45e1c3ee554685b99b27eb570b5e29c752 Mon Sep 17 00:00:00 2001 From: Calamares CI Date: Fri, 5 Jul 2019 23:31:28 +0200 Subject: [PATCH 33/37] i18n: [python] Automatic merge of Transifex translations --- lang/python/ast/LC_MESSAGES/python.mo | Bin 5167 -> 5387 bytes lang/python/ast/LC_MESSAGES/python.po | 4 ++-- lang/python/tr_TR/LC_MESSAGES/python.mo | Bin 8934 -> 8938 bytes lang/python/tr_TR/LC_MESSAGES/python.po | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/python/ast/LC_MESSAGES/python.mo b/lang/python/ast/LC_MESSAGES/python.mo index c3c75acd64f9405139893e93b993fa4ed2657a59..6cacaf7af9f624b2104cbaf7dddf65b6b38f0190 100644 GIT binary patch delta 1218 zcmZY8Pe>GD7{~E9T}{h0&0Hr`8IzAARp z(Aw$s^cyRTIf7+{{LpG+#%#el+<-l}2a{NfQ@9@Q;sJb$P52F)FQCM5Q|ET*^GU-14pm}uc2O?MICej8}S$F{rXbA61#C2FQE=J zhY9?G+cCZ>idY}^v%g7lp^a~&gYR&XG%R5+@tRkv~Uerdzn8Zoci?4AP{=jY6Oq^94 zLs*BSsMK9X)yg#P#uv-uCEUk2QAzxjLyy^q@j7)574 zP;YjzLL_juDT*<=4yTBywb99hZ7gs1Q5qb2tMb2zu13M!r8172a`Kb@Tk)^yxnmWdW4{5QCXEdM delta 1043 zcmY+@Pe>GD7{~D^9si}JZdO{ElUeR=yR?|8X%R?4kwNMqiY%5&5UMF@$wRRi9ik2* zl;;i+-GY`1NjygoT{;g3xxY;ak zIVN?Sn8c0v1XDPRwYU^r|Ahm@u~K)VT}0hCj{4se*5FfY$7$3;Ur`&0m4zGW#75$C z*u(mEi^(?KfV=P`X0WV0ys-SzA4r?D^1Mxjn${(Y8;U%`=ViY%0 zhYsR?OyOPZ#TU2_f1)zoR!jannVjWmde9WA6mL;~SdQZQSlE=^nC1K!YNK`jBWh)Ef!ae?xRa57go`tQ(Zm)lD`1J4lF2ojwlM{BLN( zyqJ6AG!}EvO0IY4UGq6K^ff7~O$tf|W>OTq!86>j`i* zRvD8VdRrRb=rz~0)|7@LZT^+x=?!crjS9DlscqnL|t&o#z5SXx^zj62&BQ`($>%i2pt;@ z9Gx26bm>Dl_ywY-{)eXD;o+R;eb3CDyC0LqZd_6(DsA97uHp@b@d+dNf?4e0K7L^a z7h=*O9-!&D!W0Hr#&e*740&S8E)833hRXmOK`*gl#O~08P;x&4A5> zM5oG_#u~Dd0^Gws-r^M3@yL<3v5IH-h(#PZ$NvT21TBKZ7Qe?=Gy{H+-DD-D3(TQ; g_>4RFIb059t*~?5xbwz+zwzMtUZ;6KtVDZDe}JGZ`2YX_ delta 350 zcmXBOF-t;W7{&1eA`v#!#RR)qHw6{MltcofBI+*M;2<;w4oZq95rN~St)UMP1vNCf z1b1+1bO^!^(csW3wh8@ToPIBd=RME!>rUK{?|`=Q0b3b^3R!lm@8eZa4OrF9#{s=M{qNRxYc!<|n!U3A137Q3w zZHZ2mFohS$E%GpnFWA8^T*sm#C9#5Mc#8)(bdDDVQ-T`;dq-;FBbo&>N5LxN9ovUWAJ$mal@BDN7b?F~)j4YP` diff --git a/lang/python/tr_TR/LC_MESSAGES/python.po b/lang/python/tr_TR/LC_MESSAGES/python.po index 82b24e462..d61c4cc2b 100644 --- a/lang/python/tr_TR/LC_MESSAGES/python.po +++ b/lang/python/tr_TR/LC_MESSAGES/python.po @@ -96,7 +96,7 @@ msgstr "Dosya sistemlerini ayırın." #: src/modules/unpackfs/main.py:41 msgid "Filling up filesystems." -msgstr "Dosya sistemini genişlet." +msgstr "Dosya sistemi genişletiliyor." #: src/modules/unpackfs/main.py:159 msgid "rsync failed with error code {}." From 940c99026869079a676bdc2c918d4f6b6455e33c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 6 Jul 2019 00:04:16 +0200 Subject: [PATCH 34/37] [initcpio] [initramfs] Allow turning off CVE mitigations - The mitigations are slightly intrusive, and may clash with other, similar mitigations (especially for initramfs, the recommended solution is to configure the system with the snippet outside of Calamares). --- src/modules/initcpio/InitcpioJob.cpp | 17 +++++++++++++---- src/modules/initcpio/InitcpioJob.h | 1 + src/modules/initcpio/initcpio.conf | 5 +++++ src/modules/initramfs/InitramfsJob.cpp | 25 +++++++++++++++++-------- src/modules/initramfs/InitramfsJob.h | 1 + src/modules/initramfs/initramfs.conf | 5 +++++ 6 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/modules/initcpio/InitcpioJob.cpp b/src/modules/initcpio/InitcpioJob.cpp index d0d825cbf..38017d83e 100644 --- a/src/modules/initcpio/InitcpioJob.cpp +++ b/src/modules/initcpio/InitcpioJob.cpp @@ -59,12 +59,19 @@ InitcpioJob::exec() { CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); - QDir d( CalamaresUtils::System::instance()->targetPath( "/boot" ) ); - if ( d.exists() ) + if ( m_unsafe ) { - fixPermissions( d ); + cDebug() << "Skipping mitigations for unsafe initramfs permissions."; } - + else + { + QDir d( CalamaresUtils::System::instance()->targetPath( "/boot" ) ); + if ( d.exists() ) + { + fixPermissions( d ); + } + } + cDebug() << "Updating initramfs with kernel" << m_kernel; auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "mkinitcpio", "-p", m_kernel }, QString(), QString(), 0 ); @@ -94,6 +101,8 @@ InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap ) << r.getExitCode() << r.getOutput(); } } + + m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false ); } CALAMARES_PLUGIN_FACTORY_DEFINITION( InitcpioJobFactory, registerPlugin< InitcpioJob >(); ) diff --git a/src/modules/initcpio/InitcpioJob.h b/src/modules/initcpio/InitcpioJob.h index 7c0bcf2df..11358d749 100644 --- a/src/modules/initcpio/InitcpioJob.h +++ b/src/modules/initcpio/InitcpioJob.h @@ -42,6 +42,7 @@ public: private: QString m_kernel; + bool m_unsafe = false; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( InitcpioJobFactory ) diff --git a/src/modules/initcpio/initcpio.conf b/src/modules/initcpio/initcpio.conf index 487a0289d..8ad71e9f5 100644 --- a/src/modules/initcpio/initcpio.conf +++ b/src/modules/initcpio/initcpio.conf @@ -16,3 +16,8 @@ # # Note that "all" is probably not a good preset to use either. kernel: linux312 + +# Set this to true to turn off mitigations for lax file +# permissions on initramfs (which, in turn, can compromise +# your LUKS encryption keys, CVS-2019-13179). +be_unsafe: false diff --git a/src/modules/initramfs/InitramfsJob.cpp b/src/modules/initramfs/InitramfsJob.cpp index c96bbb059..01d400443 100644 --- a/src/modules/initramfs/InitramfsJob.cpp +++ b/src/modules/initramfs/InitramfsJob.cpp @@ -44,16 +44,23 @@ InitramfsJob::exec() CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe ); cDebug() << "Updating initramfs with kernel" << m_kernel; - - // First make sure we generate a safe initramfs with suitable permissions. - static const char confFile[] = "/etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf"; - static const char contents[] = "UMASK=0077\n"; - if ( CalamaresUtils::System::instance()->createTargetFile( confFile, QByteArray( contents ) ).isEmpty() ) + + if ( m_unsafe ) { - cWarning() << Logger::SubEntry << "Could not configure safe UMASK for initramfs."; - // But continue anyway. + cDebug() << "Skipping mitigations for unsafe initramfs permissions."; } - + else + { + // First make sure we generate a safe initramfs with suitable permissions. + static const char confFile[] = "/etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf"; + static const char contents[] = "UMASK=0077\n"; + if ( CalamaresUtils::System::instance()->createTargetFile( confFile, QByteArray( contents ) ).isEmpty() ) + { + cWarning() << Logger::SubEntry << "Could not configure safe UMASK for initramfs."; + // But continue anyway. + } + } + // And then do the ACTUAL work. auto r = CalamaresUtils::System::instance()->targetEnvCommand( { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 0 ); @@ -84,6 +91,8 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap ) << r.getExitCode() << r.getOutput(); } } + + m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false ); } CALAMARES_PLUGIN_FACTORY_DEFINITION( InitramfsJobFactory, registerPlugin< InitramfsJob >(); ) diff --git a/src/modules/initramfs/InitramfsJob.h b/src/modules/initramfs/InitramfsJob.h index 63aed4136..9eeb81fea 100644 --- a/src/modules/initramfs/InitramfsJob.h +++ b/src/modules/initramfs/InitramfsJob.h @@ -42,6 +42,7 @@ public: private: QString m_kernel; + bool m_unsafe = false; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( InitramfsJobFactory ) diff --git a/src/modules/initramfs/initramfs.conf b/src/modules/initramfs/initramfs.conf index 4e5eda202..a989d83c3 100644 --- a/src/modules/initramfs/initramfs.conf +++ b/src/modules/initramfs/initramfs.conf @@ -29,3 +29,8 @@ # 3.2.9 and earlier which passed "all" as version. kernel: "all" + +# Set this to true to turn off mitigations for lax file +# permissions on initramfs (which, in turn, can compromise +# your LUKS encryption keys, CVS-2019-13179). +be_unsafe: false From 937dac47d8c7a9ad2944e306dac7a9e6b374cd39 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 5 Jul 2019 23:33:46 +0200 Subject: [PATCH 35/37] Changes: refer to CVE numbers for both issues --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 723747e44..37dc7a71c 100644 --- a/CHANGES +++ b/CHANGES @@ -16,7 +16,7 @@ understanding the issues (alphabetically by first name): - Seth Arnold - Simon Quigley - Thomas Ward - +Both CVE's have been resolved. ## Core ## @@ -26,7 +26,7 @@ No core changes. - *initramfs* could create an initramfs with insecure permissions. Since the keyfile is included in the initramfs, an attacker could - read the file from the initramfs. #1190 + read the file from the initramfs. #1190 CVE-2019-13178 - *luksbootkeyfile* created a key file where a window of opportunity existed where the key file could have too-lax file permissions. #1191 CVE-2019-13179 From e88269089bd5f727e59884c7313643dd2afc06ad Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 6 Jul 2019 00:52:35 +0200 Subject: [PATCH 36/37] Changes: pre-release housekeeping --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7706ec5b..ca2a6f98a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ project( CALAMARES VERSION 3.2.11 LANGUAGES C CXX ) -set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development +set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development ### OPTIONS # From ca58b67eb95d7f4488e4dc662a8d09c6724dab11 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 6 Jul 2019 01:16:28 +0200 Subject: [PATCH 37/37] Changes: post-release housekeeping --- CHANGES | 11 ++++++++++- CMakeLists.txt | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 37dc7a71c..a73684e6a 100644 --- a/CHANGES +++ b/CHANGES @@ -3,7 +3,16 @@ contributors are listed. Note that Calamares does not have a historical changelog -- this log starts with version 3.2.0. The release notes on the website will have to do for older versions. -# 3.2.11 (unreleased) # +# 3.2.12 (unreleased) # + +This release contains contributions from (alphabetically by first name): + +## Core ## + +## Modules ## + + +# 3.2.11 (2019-07-06) # This release contains contributions from (alphabetically by first name): - No other contributors this time around. diff --git a/CMakeLists.txt b/CMakeLists.txt index ca2a6f98a..cae89fc91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,10 +37,10 @@ cmake_minimum_required( VERSION 3.2 FATAL_ERROR ) project( CALAMARES - VERSION 3.2.11 + VERSION 3.2.12 LANGUAGES C CXX ) -set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development +set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development ### OPTIONS #