summaryrefslogtreecommitdiffstats
path: root/debian/patches/Try-to-avoid-OOM-killer-on-low-memory-systems-without-swa.patch
blob: b8f81b9cbd6c4095f962bc47df1ece0ecaa4551b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
From: Milan Broz <gmazyland@gmail.com>
Date: Mon, 20 Feb 2023 16:45:36 +0100
Subject: Try to avoid OOM killer on low-memory systems without swap.

Benchmark for memory-hard KDF is tricky, seems that relying
on maximum half of physical memory is not enough.

Let's allow only free physical available space if there is no swap.
This should not cause changes on normal systems, at least.

Origin: https://gitlab.com/cryptsetup/cryptsetup/-/commit/899bad8c06957a94a198d1eaa293ed8db205f1de
Bug: https://gitlab.com/cryptsetup/cryptsetup/-/issues/802
Bug-Debian: https://bugs.debian.org/1028250
---
 lib/internal.h     |  2 ++
 lib/utils.c        | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/utils_pbkdf.c  | 11 ++++++++++-
 tests/api-test-2.c | 12 ++++++++----
 4 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/lib/internal.h b/lib/internal.h
index b5cb4e3..98095fa 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -168,6 +168,8 @@ int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
 size_t crypt_getpagesize(void);
 unsigned crypt_cpusonline(void);
 uint64_t crypt_getphysmemory_kb(void);
+uint64_t crypt_getphysmemoryfree_kb(void);
+bool crypt_swapavailable(void);
 
 int init_crypto(struct crypt_device *ctx);
 
diff --git a/lib/utils.c b/lib/utils.c
index bfcf60d..e9d5b5b 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -59,6 +59,53 @@ uint64_t crypt_getphysmemory_kb(void)
 	return phys_memory_kb;
 }
 
+uint64_t crypt_getphysmemoryfree_kb(void)
+{
+	long pagesize, phys_pages;
+	uint64_t phys_memoryfree_kb;
+
+	pagesize = sysconf(_SC_PAGESIZE);
+	phys_pages = sysconf(_SC_AVPHYS_PAGES);
+
+	if (pagesize < 0 || phys_pages < 0)
+		return 0;
+
+	phys_memoryfree_kb = pagesize / 1024;
+	phys_memoryfree_kb *= phys_pages;
+
+	return phys_memoryfree_kb;
+}
+
+bool crypt_swapavailable(void)
+{
+	int fd;
+	ssize_t size;
+	char buf[4096], *p;
+	uint64_t total;
+
+	if ((fd = open("/proc/meminfo", O_RDONLY)) < 0)
+		return true;
+
+	size = read(fd, buf, sizeof(buf));
+	close(fd);
+	if (size < 1)
+		return true;
+
+	if (size < (ssize_t)sizeof(buf))
+		buf[size] = 0;
+	else
+		buf[sizeof(buf) - 1] = 0;
+
+	p = strstr(buf, "SwapTotal:");
+	if (!p)
+		return true;
+
+	if (sscanf(p, "SwapTotal: %" PRIu64 " kB", &total) != 1)
+		return true;
+
+	return total > 0;
+}
+
 void crypt_process_priority(struct crypt_device *cd, int *priority, bool raise)
 {
 	int _priority, new_priority;
diff --git a/lib/utils_pbkdf.c b/lib/utils_pbkdf.c
index 4d7e18d..d8f41c7 100644
--- a/lib/utils_pbkdf.c
+++ b/lib/utils_pbkdf.c
@@ -63,7 +63,7 @@ const struct crypt_pbkdf_type *crypt_get_pbkdf_type_params(const char *pbkdf_typ
 
 static uint32_t adjusted_phys_memory(void)
 {
-	uint64_t memory_kb = crypt_getphysmemory_kb();
+	uint64_t free_kb, memory_kb = crypt_getphysmemory_kb();
 
 	/* Ignore bogus value */
 	if (memory_kb < (128 * 1024) || memory_kb > UINT32_MAX)
@@ -75,6 +75,15 @@ static uint32_t adjusted_phys_memory(void)
 	 */
 	memory_kb /= 2;
 
+	/*
+	 * Never use more that available free space on system without swap.
+	 */
+	if (!crypt_swapavailable()) {
+		free_kb = crypt_getphysmemoryfree_kb();
+		if (free_kb > (64 * 1024) && free_kb < memory_kb)
+			return free_kb;
+	}
+
 	return memory_kb;
 }
 
diff --git a/tests/api-test-2.c b/tests/api-test-2.c
index 824ae65..923165c 100644
--- a/tests/api-test-2.c
+++ b/tests/api-test-2.c
@@ -2802,7 +2802,8 @@ static void Pbkdf(void)
 	OK_(strcmp(pbkdf->type, default_luks2_pbkdf));
 	OK_(strcmp(pbkdf->hash, default_luks1_hash));
 	EQ_(pbkdf->time_ms, default_luks2_iter_time);
-	EQ_(pbkdf->max_memory_kb, adjusted_pbkdf_memory());
+	GE_(pbkdf->max_memory_kb, 64 * 1024);
+	GE_(adjusted_pbkdf_memory(), pbkdf->max_memory_kb);
 	EQ_(pbkdf->parallel_threads, _min(cpus_online(), default_luks2_parallel_threads));
 	// set and verify argon2 type
 	OK_(crypt_set_pbkdf_type(cd, &argon2));
@@ -2827,7 +2828,8 @@ static void Pbkdf(void)
 	OK_(strcmp(pbkdf->type, default_luks2_pbkdf));
 	OK_(strcmp(pbkdf->hash, default_luks1_hash));
 	EQ_(pbkdf->time_ms, default_luks2_iter_time);
-	EQ_(pbkdf->max_memory_kb, adjusted_pbkdf_memory());
+	GE_(pbkdf->max_memory_kb, 64 * 1024);
+	GE_(adjusted_pbkdf_memory(), pbkdf->max_memory_kb);
 	EQ_(pbkdf->parallel_threads, _min(cpus_online(), default_luks2_parallel_threads));
 	// try to pass illegal values
 	argon2.parallel_threads = 0;
@@ -2858,14 +2860,16 @@ static void Pbkdf(void)
 	OK_(strcmp(pbkdf->type, default_luks2_pbkdf));
 	OK_(strcmp(pbkdf->hash, default_luks1_hash));
 	EQ_(pbkdf->time_ms, default_luks2_iter_time);
-	EQ_(pbkdf->max_memory_kb, adjusted_pbkdf_memory());
+	GE_(pbkdf->max_memory_kb, 64 * 1024);
+	GE_(adjusted_pbkdf_memory(), pbkdf->max_memory_kb);
 	EQ_(pbkdf->parallel_threads, _min(cpus_online(), default_luks2_parallel_threads));
 	crypt_set_iteration_time(cd, 1);
 	OK_(crypt_load(cd, CRYPT_LUKS, NULL));
 	OK_(strcmp(pbkdf->type, default_luks2_pbkdf));
 	OK_(strcmp(pbkdf->hash, default_luks1_hash));
 	EQ_(pbkdf->time_ms, 1);
-	EQ_(pbkdf->max_memory_kb, adjusted_pbkdf_memory());
+	GE_(pbkdf->max_memory_kb, 64 * 1024);
+	GE_(adjusted_pbkdf_memory(), pbkdf->max_memory_kb);
 	EQ_(pbkdf->parallel_threads, _min(cpus_online(), default_luks2_parallel_threads));
 	CRYPT_FREE(cd);