@samitouri / QOSamiQemu / commits / 5b0ba385a0

block/accounting: take stats->lock in latency histogram setters

block_latency_histogram_set() and block_latency_histograms_clear() replace BlockLatencyHistogram's nbins/boundaries/bins without taking stats->lock, while block_account_one_io() reads those same fields under that lock from whatever iothread completes the I/O. The result is usual use-after-free and qemu crash. Take stats->lock in both setters, matching the lock already held by the reader. Signed-off-by: Denis V. Lunev <den@openvz.org> CC: Kevin Wolf <kwolf@redhat.com> CC: Hanna Reitz <hreitz@redhat.com> CC: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> CC: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> Message-ID: <20260724111311.4086859-2-den@openvz.org> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Denis V. Lunev committed Jul 24, 2026 at 13:13 UTC 5b0ba385a024ad92c63c175317cd9374de2e6165
1 file changed +8
block/accounting.c
+8
@@ -194,6 +194,8 @@ int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type,
194 return -EINVAL;
195 }
196
197 + qemu_mutex_lock(&stats->lock);
198 +
199 hist->nbins = new_nbins;
200 g_free(hist->boundaries);
201 hist->boundaries = g_new(uint64_t, hist->nbins - 1);
@@ -206,6 +208,8 @@ int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type,
208 g_free(hist->bins);
209 hist->bins = g_new0(uint64_t, hist->nbins);
210
211 + qemu_mutex_unlock(&stats->lock);
212 +
213 return 0;
214 }
215
@@ -213,12 +217,16 @@ void block_latency_histograms_clear(BlockAcctStats *stats)
217 {
218 int i;
219
220 + qemu_mutex_lock(&stats->lock);
221 +
222 for (i = 0; i < BLOCK_MAX_IOTYPE; i++) {
223 BlockLatencyHistogram *hist = &stats->latency_histogram[i];
224 g_free(hist->bins);
225 g_free(hist->boundaries);
226 memset(hist, 0, sizeof(*hist));
227 }
228 +
229 + qemu_mutex_unlock(&stats->lock);
230 }
231
232 static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie,