Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

9p/trans_xen: make cleanup idempotent after dataring alloc errors

xen_9pfs_front_alloc_dataring() tears down resources on failure but
leaves ring fields stale. If xen_9pfs_front_init() later jumps to the
common error path, xen_9pfs_front_free() may touch the same resources
again, causing duplicate/invalid gnttab_end_foreign_access() calls and
potentially dereferencing a freed intf pointer.

Initialize dataring sentinels before allocation, gate teardown on those
sentinels, and clear ref/intf/data/irq immediately after each release.

This keeps cleanup idempotent for partially initialized rings and
prevents repeated teardown during init failure handling.

Signed-off-by: Yufan Chen <ericterminal@gmail.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Message-ID: <20260324153023.86853-2-ericterminal@gmail.com>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>

authored by

Yufan Chen and committed by
Dominique Martinet
72cb9ee4 890d5696

+37 -14
+37 -14
net/9p/trans_xen.c
··· 283 283 284 284 cancel_work_sync(&ring->work); 285 285 286 - if (!priv->rings[i].intf) 286 + if (!ring->intf) 287 287 break; 288 - if (priv->rings[i].irq > 0) 289 - unbind_from_irqhandler(priv->rings[i].irq, ring); 290 - if (priv->rings[i].data.in) { 291 - for (j = 0; 292 - j < (1 << priv->rings[i].intf->ring_order); 288 + if (ring->irq >= 0) { 289 + unbind_from_irqhandler(ring->irq, ring); 290 + ring->irq = -1; 291 + } 292 + if (ring->data.in) { 293 + for (j = 0; j < (1 << ring->intf->ring_order); 293 294 j++) { 294 295 grant_ref_t ref; 295 296 296 - ref = priv->rings[i].intf->ref[j]; 297 + ref = ring->intf->ref[j]; 297 298 gnttab_end_foreign_access(ref, NULL); 299 + ring->intf->ref[j] = INVALID_GRANT_REF; 298 300 } 299 - free_pages_exact(priv->rings[i].data.in, 300 - 1UL << (priv->rings[i].intf->ring_order + 301 - XEN_PAGE_SHIFT)); 301 + free_pages_exact(ring->data.in, 302 + 1UL << (ring->intf->ring_order + 303 + XEN_PAGE_SHIFT)); 304 + ring->data.in = NULL; 305 + ring->data.out = NULL; 302 306 } 303 - gnttab_end_foreign_access(priv->rings[i].ref, NULL); 304 - free_page((unsigned long)priv->rings[i].intf); 307 + if (ring->ref != INVALID_GRANT_REF) { 308 + gnttab_end_foreign_access(ring->ref, NULL); 309 + ring->ref = INVALID_GRANT_REF; 310 + } 311 + free_page((unsigned long)ring->intf); 312 + ring->intf = NULL; 305 313 } 306 314 kfree(priv->rings); 307 315 } ··· 341 333 int i = 0; 342 334 int ret = -ENOMEM; 343 335 void *bytes = NULL; 336 + 337 + ring->intf = NULL; 338 + ring->data.in = NULL; 339 + ring->data.out = NULL; 340 + ring->ref = INVALID_GRANT_REF; 341 + ring->irq = -1; 344 342 345 343 init_waitqueue_head(&ring->wq); 346 344 spin_lock_init(&ring->lock); ··· 393 379 for (i--; i >= 0; i--) 394 380 gnttab_end_foreign_access(ring->intf->ref[i], NULL); 395 381 free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT)); 382 + ring->data.in = NULL; 383 + ring->data.out = NULL; 396 384 } 397 - gnttab_end_foreign_access(ring->ref, NULL); 398 - free_page((unsigned long)ring->intf); 385 + if (ring->ref != INVALID_GRANT_REF) { 386 + gnttab_end_foreign_access(ring->ref, NULL); 387 + ring->ref = INVALID_GRANT_REF; 388 + } 389 + if (ring->intf) { 390 + free_page((unsigned long)ring->intf); 391 + ring->intf = NULL; 392 + } 393 + ring->irq = -1; 399 394 return ret; 400 395 } 401 396