v30.3-roots.1 · Commit 50: [PATCH 50/68] qt: cleanse and release transient sweep cache
src/qt/sweepdialog.cpp
Before: src/qt/sweepdialog.cpp · After: src/qt/sweepdialog.cpp
File metadata
index c410a97daa2643469ab2a149605b2ae48d09a3fd..4cdfcb7e5d350a1e1327ec5ee9dd199494361ec6 100644
Download original patch · Release notes
Diff rows 1–97 of 97. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/qt/sweepdialog.cpp
CHANGED
|
@@ -36,7 +36,8 @@ public:
|
|
|
36
36
|
SecureString result{encoded.constData(), static_cast<size_t>(encoded.size())};
|
|
37
37
|
if (!encoded.isEmpty()) memory_cleanse(encoded.data(), encoded.size());
|
|
38
38
|
// QLineEdit does not expose its internal buffer for cleansing. Replace
|
|
39
|
-
// its contents before clearing so the widget no longer retains the WIF.
|
|
39
|
+
// its visible contents before clearing; Qt does not guarantee physical
|
|
40
|
+
// erasure of every internal QString or undo-buffer copy.
|
|
40
41
|
setText(QString(text().size(), QChar{' '}));
|
|
41
42
|
clear();
|
|
42
43
|
return result;
|
|
@@ -118,7 +119,7 @@ SweepDialog::SweepDialog(WalletModel* wallet_model, QWidget* parent)
|
|
|
118
119
|
m_request_generation = 0;
|
|
119
120
|
const QSignalBlocker block{m_private_key};
|
|
120
121
|
m_private_key->clear();
|
|
121
|
-
m_private_key_cache.clear();
|
|
122
|
+
clearPrivateKeyCache();
|
|
122
123
|
m_preview_txid.clear();
|
|
123
124
|
setBusy(false);
|
|
124
125
|
m_preview_current = false;
|
|
@@ -130,6 +131,15 @@ SweepDialog::SweepDialog(WalletModel* wallet_model, QWidget* parent)
|
|
|
130
131
|
|
|
131
132
|
SweepDialog::~SweepDialog() { clearSensitive(); }
|
|
132
133
|
|
|
134
|
+
void SweepDialog::clearPrivateKeyCache()
|
|
135
|
+
{
|
|
136
|
+
// clear() alone retains storage, including the old secret beyond size().
|
|
137
|
+
// Wipe live bytes first, including short-string storage, then release any
|
|
138
|
+
// allocation through secure_allocator's cleansing deallocator.
|
|
139
|
+
if (!m_private_key_cache.empty()) memory_cleanse(m_private_key_cache.data(), m_private_key_cache.size());
|
|
140
|
+
SecureString{}.swap(m_private_key_cache);
|
|
141
|
+
}
|
|
142
|
+
|
|
133
143
|
void SweepDialog::invalidate()
|
|
134
144
|
{
|
|
135
145
|
if (m_request_generation != 0 && !m_wallet_model->invalidateSweepRequests()) {
|
|
@@ -137,7 +147,7 @@ void SweepDialog::invalidate()
|
|
|
137
147
|
return;
|
|
138
148
|
}
|
|
139
149
|
m_request_generation = 0;
|
|
140
|
-
m_private_key_cache.clear();
|
|
150
|
+
clearPrivateKeyCache();
|
|
141
151
|
m_preview_txid.clear();
|
|
142
152
|
m_preview_current = false;
|
|
143
153
|
m_broadcast->setEnabled(false);
|
|
@@ -162,6 +172,7 @@ void SweepDialog::setResult(const QString& text, bool can_broadcast)
|
|
|
162
172
|
|
|
163
173
|
void SweepDialog::preview()
|
|
164
174
|
{
|
|
175
|
+
clearPrivateKeyCache();
|
|
165
176
|
const CTxDestination destination{DecodeDestination(m_destination->text().toStdString())};
|
|
166
177
|
if (!IsValidDestination(destination)) { setResult(tr("Enter a valid destination address."), false); return; }
|
|
167
178
|
const QSignalBlocker block{m_private_key};
|
|
@@ -170,7 +181,11 @@ void SweepDialog::preview()
|
|
|
170
181
|
setBusy(true);
|
|
171
182
|
m_result->setText(tr("Scanning for eligible coins and preparing a preview…"));
|
|
172
183
|
m_request_generation = m_wallet_model->requestSweep(m_private_key_cache, destination, false);
|
|
173
|
-
if (m_request_generation == 0) setResult(tr("Another sweep broadcast is already being submitted."), false);
|
|
184
|
+
if (m_request_generation == 0) {
|
|
185
|
+
clearPrivateKeyCache();
|
|
186
|
+
setBusy(false);
|
|
187
|
+
setResult(tr("Another sweep broadcast is already being submitted."), false);
|
|
188
|
+
}
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
void SweepDialog::broadcast()
|
|
@@ -182,12 +197,20 @@ void SweepDialog::broadcast()
|
|
|
182
197
|
if (answer != QMessageBox::Yes) return;
|
|
183
198
|
const CTxDestination destination{DecodeDestination(m_destination->text().toStdString())};
|
|
184
199
|
const auto expected_txid{Txid::FromHex(m_preview_txid.toStdString())};
|
|
185
|
-
if (!expected_txid) { setResult(tr("The preview is no longer valid. Create a fresh preview."), false); return; }
|
|
200
|
+
if (!expected_txid) {
|
|
201
|
+
clearPrivateKeyCache();
|
|
202
|
+
setResult(tr("The preview is no longer valid. Create a fresh preview."), false);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
186
205
|
setBusy(true);
|
|
187
206
|
m_preview_current = false;
|
|
188
207
|
m_result->setText(tr("Rechecking the preview and broadcasting the sweep…"));
|
|
189
208
|
m_request_generation = m_wallet_model->requestSweep(m_private_key_cache, destination, true, expected_txid);
|
|
190
|
-
if (m_request_generation == 0) setResult(tr("Sweep broadcast submission has already started. Wait for its result."), false);
|
|
209
|
+
if (m_request_generation == 0) {
|
|
210
|
+
clearPrivateKeyCache();
|
|
211
|
+
setBusy(false);
|
|
212
|
+
setResult(tr("Sweep broadcast submission has already started. Wait for its result."), false);
|
|
213
|
+
}
|
|
191
214
|
}
|
|
192
215
|
|
|
193
216
|
void SweepDialog::reject()
|
|
@@ -211,7 +234,7 @@ void SweepDialog::handleSweepFinished(uint64_t generation, bool broadcast, bool
|
|
|
211
234
|
setResult(broadcast
|
|
212
235
|
? tr("Broadcast failed: %1. Create a fresh preview before trying again.").arg(error)
|
|
213
236
|
: tr("Preview failed: %1").arg(error), false);
|
|
214
|
-
m_private_key_cache.clear();
|
|
237
|
+
clearPrivateKeyCache();
|
|
215
238
|
m_preview_txid.clear();
|
|
216
239
|
return;
|
|
217
240
|
}
|
|
@@ -237,7 +260,7 @@ void SweepDialog::clearSensitive()
|
|
|
237
260
|
m_request_generation = 0;
|
|
238
261
|
const QSignalBlocker block{m_private_key};
|
|
239
262
|
m_private_key->clear();
|
|
240
|
-
m_private_key_cache.clear();
|
|
263
|
+
clearPrivateKeyCache();
|
|
241
264
|
m_preview_txid.clear();
|
|
242
265
|
m_preview_current = false;
|
|
243
266
|
setBusy(false);
|