pirq_cleanup_check() leaks

Its original introduction had two issues: For one the "common" part of
the checks (carried out in the macro) was inverted. And then after
removal from the radix tree the structure wasn't scheduled for freeing.
(All structures still left in the radix tree would be freed upon domain
destruction, though.)

For the freeing to be safe even if it didn't use RCU (i.e. to avoid use-
after-free), re-arrange checks/operations in evtchn_close(), such that
the pointer wouldn't be used anymore after calling pirq_cleanup_check()
(noting that unmap_domain_pirq_emuirq() itself calls the function in the
success case).

Fixes: c24536b636 ("replace d->nr_pirqs sized arrays with radix tree")
Fixes: 79858fee30 ("xen: fix hvm_domain_use_pirq's behavior")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
master commit: daa90dfea9
master date: 2024-07-02 08:35:56 +0200
This commit is contained in:
Jan Beulich committed 2024-07-04 14:20:50 +02:00
1 parent 8e522bfa48
commit fb9f984293
3 files changed
+10 -4

No files matched your search

+1
View File
@@ -1413,6 +1413,7 @@ void (pirq_cleanup_check)(struct pirq *pirq, struct domain *d)
if ( radix_tree_delete(&d->pirq_tree, pirq->pirq) != pirq )
BUG();
free_pirq_struct(pirq);
}
/* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */
+8 -3
View File
@@ -680,11 +680,16 @@ int evtchn_close(struct domain *d1, int port1, bool guest)
if ( !is_hvm_domain(d1) )
pirq_guest_unbind(d1, pirq);
pirq->evtchn = 0;
pirq_cleanup_check(pirq, d1);
#ifdef CONFIG_X86
if ( is_hvm_domain(d1) && domain_pirq_to_irq(d1, pirq->pirq) > 0 )
unmap_domain_pirq_emuirq(d1, pirq->pirq);
if ( !is_hvm_domain(d1) ||
domain_pirq_to_irq(d1, pirq->pirq) <= 0 ||
unmap_domain_pirq_emuirq(d1, pirq->pirq) < 0 )
/*
* The successful path of unmap_domain_pirq_emuirq() will have
* called pirq_cleanup_check() already.
*/
#endif
pirq_cleanup_check(pirq, d1);
}
unlink_pirq_port(chn1, d1->vcpu[chn1->notify_vcpu_id]);
break;
+1 -1
View File
@@ -179,7 +179,7 @@ extern struct pirq *pirq_get_info(struct domain *, int pirq);
void pirq_cleanup_check(struct pirq *, struct domain *);
#define pirq_cleanup_check(pirq, d) \
((pirq)->evtchn ? pirq_cleanup_check(pirq, d) : (void)0)
(!(pirq)->evtchn ? pirq_cleanup_check(pirq, d) : (void)0)
extern void pirq_guest_eoi(struct pirq *);
extern void desc_guest_eoi(struct irq_desc *, struct pirq *);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.