File kdump-calibrate-Add-LUKS2-Argon2-requirements-to-the-reser.patch of Package kdump.23238

From: Petr Tesarik <ptesarik@suse.com>
Date: Mon, 1 Mar 2021 12:29:50 +0100
Subject: calibrate: Add LUKS2 Argon2 requirements to the reservation
References: bsc#1180513
Upstream: merged
Git-commit: 3aa70633444ecd0f3fbd213a15b64c78f64bcd6b

The Argon2 key derivation function (default for LUKS2 devices)
usually requires a lot of RAM, which must be available in the
kdump panic environment if such a device is needed to save the
dump.

Signed-off-by: Petr Tesarik <ptesarik@suse.com>
References: jsc#SLE-13779
---
 kdumptool/calibrate.cc |  111 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

--- a/kdumptool/calibrate.cc
+++ b/kdumptool/calibrate.cc
@@ -31,6 +31,9 @@
 #include "configuration.h"
 #include "util.h"
 #include "fileutil.h"
+#include "mounts.h"
+#include "process.h"
+#include "rootdirurl.h"
 
 // All calculations are in KiB
 
@@ -928,6 +931,69 @@ unsigned long long MemMap::find(unsigned
 }
 
 //}}}
+//{{{ CryptInfo ----------------------------------------------------------------
+
+/**
+ * Given a LUKS crypto device, dump the header using 'cryptinfo' and
+ * parse the output looking for maximum memory requirements.
+ */
+class CryptInfo {
+        unsigned long m_memory;
+
+    public:
+        CryptInfo(std::string const& device);
+
+	/**
+	 * Get memory requirements.
+	 *
+	 * @return Maximum memory in KiB needed to open the device
+	 */
+        unsigned long memory(void) const
+        { return m_memory; }
+};
+
+// -----------------------------------------------------------------------------
+CryptInfo::CryptInfo(std::string const& device)
+    : m_memory(0)
+{
+    Debug::debug()->trace("CryptInfo::CryptInfo(%s)", device.c_str());
+
+    ProcessFilter p;
+
+    StringVector args;
+    args.push_back("luksDump");
+    args.push_back(device);
+
+    std::ostringstream stdoutStream, stderrStream;
+    p.setStdout(&stdoutStream);
+    p.setStderr(&stderrStream);
+    int ret = p.execute("cryptsetup", args);
+    if (ret != 0) {
+        KString error = stderrStream.str();
+        throw KError("cryptsetup failed: " + error.trim());
+    }
+
+    KString out = stdoutStream.str();
+    size_t pos = 0;
+    while (pos < out.length()) {
+        size_t end = out.find_first_of("\r\n", pos);
+        size_t sep = out.find(':', pos);
+        if (sep < end) {
+            KString key = out.substr(pos, sep - pos);
+            if (key.trim() == "Memory") {
+                KString val = out.substr(sep + 1, end - sep - 1);
+                unsigned long memory = Stringutil::string2llong(val.trim());
+                Debug::debug()->dbg("Crypto device %s needs %lu KiB",
+                                    device.c_str(), memory);
+                if (memory > m_memory)
+                    m_memory = memory;
+            }
+        }
+        pos = out.find_first_not_of("\r\n", end);
+    }
+}
+
+//}}}
 //{{{ Calibrate ----------------------------------------------------------------
 
 // -----------------------------------------------------------------------------
@@ -996,6 +1062,51 @@ void Calibrate::execute()
 	    required += DEF_FRAMEBUFFER_KB;
 	}
 
+        // LUKS Argon2 hash requires a lot of memory
+        try {
+            FilesystemTypeMap map;
+
+            if (config->KDUMP_COPY_KERNEL.value()) {
+                try {
+                    map.addPath("/boot");
+                } catch (KError) {
+                    // ignore device resolution failures
+                }
+            }
+
+            std::istringstream iss(config->KDUMP_SAVEDIR.value());
+            std::string elem;
+            while (iss >> elem) {
+                RootDirURL url(elem, std::string());
+                if (url.getProtocol() == RootDirURL::PROT_FILE) {
+                    try {
+                        map.addPath(url.getRealPath());
+                    } catch (KError) {
+                        // ignore device resolution failures
+                    }
+                }
+            }
+
+            unsigned long crypto_mem = 0;
+            StringStringMap devices = map.devices();
+            for (StringStringMap::iterator it = devices.begin();
+                 it != devices.end();
+                 ++it) {
+                if (it->second == "crypto_LUKS") {
+                    CryptInfo info(it->first);
+                    if (crypto_mem < info.memory())
+                        crypto_mem = info.memory();
+                }
+            }
+            required += crypto_mem;
+
+            Debug::debug()->dbg("Adding %lu KiB for crypto devices",
+                                crypto_mem);
+        } catch (KError e) {
+	    Debug::debug()->dbg("Cannot check encrypted volumes: %s", e.what());
+            // Fall back to no allocation
+        }
+
 	// Add space for constant slabs
 	try {
 	    SlabInfos slab;
openSUSE Build Service is sponsored by