geli: allocate a UMA pool earlier

The functions g_eli_init_uma and g_eli_fini_uma are used to trace
the number of devices in GELI. There is an issue where the g_eli_create
function may fail before g_eli_init_uma is called, however
g_eli_fini_uma is still executed in the fail path. This can
incorrectly decrease the device count to zero, potentially leading to
the UMA pool being freed. Accessing the device after the pool has been
freed causes a system panic.

This commit resolves the issue by ensuring devices count is increassed
eariler.

PR:		278828
Reported by:	Andre Albsmeier <mail@fbsd2.e4m.org>
Reviewed by:	asomers
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D45225
This commit is contained in:
Mariusz Zaborski 2024-05-19 14:53:17 +02:00
parent ff4480baf6
commit 4b3141f5d5
2 changed files with 32 additions and 1 deletions

View file

@ -1046,10 +1046,12 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
bioq_init(&sc->sc_queue);
mtx_init(&sc->sc_queue_mtx, "geli:queue", NULL, MTX_DEF);
mtx_init(&sc->sc_ekeys_lock, "geli:ekeys", NULL, MTX_DEF);
g_eli_init_uma();
pp = NULL;
cp = g_new_consumer(gp);
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
error = g_attach(cp, bpp);
if (error != 0) {
if (req != NULL) {
@ -1092,7 +1094,6 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
if (threads == 0)
threads = mp_ncpus;
sc->sc_cpubind = (mp_ncpus > 1 && threads == mp_ncpus);
g_eli_init_uma();
for (i = 0; i < threads; i++) {
if (g_eli_cpu_is_disabled(i)) {
G_ELI_DEBUG(1, "%s: CPU %u disabled, skipping.",
@ -1164,6 +1165,7 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
sc->sc_crypto == G_ELI_CRYPTO_SW_ACCEL ? "accelerated software" :
sc->sc_crypto == G_ELI_CRYPTO_SW ? "software" : "hardware");
return (gp);
failed:
mtx_lock(&sc->sc_queue_mtx);
sc->sc_flags |= G_ELI_FLAG_DESTROY;

View file

@ -39,6 +39,34 @@ attach_d_cleanup()
geli_test_cleanup
}
atf_test_case atach_multiple_fails cleanup
attach_multiple_fails_head()
{
atf_set "descr" "test multiple failed attach of geli provider"
atf_set "require.user" "root"
}
attach_multiple_fails_body()
{
geli_test_setup
sectors=1000
attach_md md -t malloc -s `expr $sectors + 1`
atf_check dd if=/dev/random of=keyfile bs=512 count=16 status=none
atf_check geli init -B none -P -K keyfile ${md}
atf_check geli attach -d -p -k keyfile ${md}
for i in $(jot 100); do
atf_check -s not-exit:0 -e ignore -- geli attach -d -p -k keyfile ${md}
done
atf_check -o ignore -- newfs ${md}.eli
}
attach_multiple_fails_cleanup()
{
geli_test_cleanup
}
atf_test_case attach_r cleanup
attach_r_head()
{
@ -125,5 +153,6 @@ atf_init_test_cases()
atf_add_test_case attach_d
atf_add_test_case attach_r
atf_add_test_case attach_multiple
atf_add_test_case attach_multiple_fails
atf_add_test_case nokey
}