kern: osd: avoid dereferencing freed slots

If a slot is freed that isn't the last one, we'll set its destructor to
NULL to indicate that it's been freed and leave a hole in the slot map.
Check osd_destructors in osd_call() to avoid dereferencing a method that
is potentially from a module that's been unloaded.

This scenario would most commonly surface when two modules are loaded
that osd_register(), then the earlier one deregisters and an osd_call()
is made after the fact.  In the specific report that triggered the
investigation, kldload if_wg -> kldload linux* -> kldunload if_wg ->
destroy a jail -> panic.

Noted in the review, but left for follow-up work, is that the realloc
that may happen in osd_deregister() should likely go away and the
assumption that reallocating to a smaller size cannot fail is actually
not correct.

Reported by:	dim
Reviewed by:	markj, jamie
Differential Revision:	https://reviews.freebsd.org/D41404
This commit is contained in:
Kyle Evans 2023-08-10 12:32:33 -05:00
parent 60a41168d1
commit 2bd446d7f1

View File

@ -396,6 +396,9 @@ osd_call(u_int type, u_int method, void *obj, void *data)
error = 0;
sx_slock(&osdm[type].osd_module_lock);
for (i = 0; i < osdm[type].osd_ntslots; i++) {
/* Hole in the slot map; avoid dereferencing. */
if (osdm[type].osd_destructors[i] == NULL)
continue;
methodfun = osdm[type].osd_methods[i * osdm[type].osd_nmethods +
method];
if (methodfun != NULL && (error = methodfun(obj, data)) != 0)