Skip to content

Commit

Permalink
crypto: run qcrypto_pbkdf2_count_iters in a new thread
Browse files Browse the repository at this point in the history
CPU time accounting in the kernel has been demonstrated to have a
sawtooth pattern[1][2]. This can cause the getrusage system call to
not be as accurate as we are expecting, which can cause this calculation
to stall.

The kernel discussions shows that this inaccuracy happens when CPU time
gets big enough, so this patch changes qcrypto_pbkdf2_count_iters to run
in a fresh thread to avoid this inaccuracy. It also adds a sanity check
to fail the process if CPU time is not accounted.

[1] https://lore.kernel.org/lkml/159231011694.16989.16351419333851309713.tip-bot2@tip-bot2/
[2] https://lore.kernel.org/lkml/[email protected]/t/#m1c7f2fdc0ea742776a70fd1aa2a2e414c437f534

Resolves: #2398
Signed-off-by: Tiago Pasqualini <[email protected]>
Signed-off-by: Daniel P. Berrangé <[email protected]>
(cherry picked from commit c72cab5)
Signed-off-by: Michael Tokarev <[email protected]>
  • Loading branch information
tpsilva authored and Michael Tokarev committed Sep 25, 2024
1 parent f74e5bd commit ae2dc2a
Showing 1 changed file with 46 additions and 7 deletions.
53 changes: 46 additions & 7 deletions crypto/pbkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "qapi/error.h"
#include "crypto/pbkdf.h"
#ifndef _WIN32
Expand Down Expand Up @@ -85,12 +86,28 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
#endif
}

uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp)
typedef struct CountItersData {
QCryptoHashAlgorithm hash;
const uint8_t *key;
size_t nkey;
const uint8_t *salt;
size_t nsalt;
size_t nout;
uint64_t iterations;
Error **errp;
} CountItersData;

static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
{
CountItersData *iters_data = (CountItersData *) data;
QCryptoHashAlgorithm hash = iters_data->hash;
const uint8_t *key = iters_data->key;
size_t nkey = iters_data->nkey;
const uint8_t *salt = iters_data->salt;
size_t nsalt = iters_data->nsalt;
size_t nout = iters_data->nout;
Error **errp = iters_data->errp;

uint64_t ret = -1;
g_autofree uint8_t *out = g_new(uint8_t, nout);
uint64_t iterations = (1 << 15);
Expand All @@ -114,7 +131,10 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,

delta_ms = end_ms - start_ms;

if (delta_ms > 500) {
if (delta_ms == 0) { /* sanity check */
error_setg(errp, "Unable to get accurate CPU usage");
goto cleanup;
} else if (delta_ms > 500) {
break;
} else if (delta_ms < 100) {
iterations = iterations * 10;
Expand All @@ -129,5 +149,24 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,

cleanup:
memset(out, 0, nout);
return ret;
iters_data->iterations = ret;
return NULL;
}

uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp)
{
CountItersData data = {
hash, key, nkey, salt, nsalt, nout, 0, errp
};
QemuThread thread;

qemu_thread_create(&thread, "pbkdf2", threaded_qcrypto_pbkdf2_count_iters,
&data, QEMU_THREAD_JOINABLE);
qemu_thread_join(&thread);

return data.iterations;
}

0 comments on commit ae2dc2a

Please sign in to comment.