mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
xen-blkback: Avoid UAF when reading I/O statistics
Reading I/O statistics via sysfs concurrently with tearing down a
frontend device might result in UAF or a NULL dereference, as the
reading of the statistics data is not synchronized with freeing the
data.
Use a rwlock for synchronizing.
This is XSA-528 / CVE-2026-100082
Fixes: db6fbc1067 ("xen/blkback: make st_ statistics per ring")
Reported-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
This commit is contained in:
parent
bfddc420af
commit
a02926f7c8
|
|
@ -318,8 +318,10 @@ struct xen_blkif {
|
|||
unsigned int nr_ring_pages;
|
||||
bool multi_ref;
|
||||
/* All rings for this device. */
|
||||
rwlock_t rings_lock;
|
||||
struct xen_blkif_ring *rings;
|
||||
unsigned int nr_rings;
|
||||
|
||||
unsigned long buffer_squeeze_end;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -127,14 +127,23 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
|
|||
return;
|
||||
}
|
||||
|
||||
static int xen_blkif_alloc_rings(struct xen_blkif *blkif)
|
||||
static int xen_blkif_alloc_rings(struct xen_blkif *blkif,
|
||||
unsigned int nr_rings)
|
||||
{
|
||||
unsigned int r;
|
||||
struct xen_blkif_ring *rings;
|
||||
|
||||
blkif->rings = kzalloc_objs(struct xen_blkif_ring, blkif->nr_rings);
|
||||
if (!blkif->rings)
|
||||
rings = kzalloc_objs(struct xen_blkif_ring, nr_rings);
|
||||
if (!rings)
|
||||
return -ENOMEM;
|
||||
|
||||
write_lock(&blkif->rings_lock);
|
||||
|
||||
blkif->rings = rings;
|
||||
blkif->nr_rings = nr_rings;
|
||||
|
||||
write_unlock(&blkif->rings_lock);
|
||||
|
||||
for (r = 0; r < blkif->nr_rings; r++) {
|
||||
struct xen_blkif_ring *ring = &blkif->rings[r];
|
||||
|
||||
|
|
@ -174,6 +183,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
|
|||
blkif->domid = domid;
|
||||
atomic_set(&blkif->refcnt, 1);
|
||||
init_completion(&blkif->drain_complete);
|
||||
rwlock_init(&blkif->rings_lock);
|
||||
|
||||
/*
|
||||
* Because freeing back to the cache may be deferred, it is not
|
||||
|
|
@ -268,6 +278,7 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
|
|||
struct pending_req *req, *n;
|
||||
unsigned int j, r;
|
||||
bool busy = false;
|
||||
struct xen_blkif_ring *rings;
|
||||
|
||||
for (r = 0; r < blkif->nr_rings; r++) {
|
||||
struct xen_blkif_ring *ring = &blkif->rings[r];
|
||||
|
|
@ -334,10 +345,16 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
|
|||
* blkif->rings was allocated in connect_ring, so we should free it in
|
||||
* here.
|
||||
*/
|
||||
kfree(blkif->rings);
|
||||
write_lock(&blkif->rings_lock);
|
||||
|
||||
rings = blkif->rings;
|
||||
blkif->rings = NULL;
|
||||
blkif->nr_rings = 0;
|
||||
|
||||
write_unlock(&blkif->rings_lock);
|
||||
|
||||
kfree(rings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +402,7 @@ void xen_blkif_interface_fini(void)
|
|||
unsigned int i; \
|
||||
unsigned long long result = 0; \
|
||||
\
|
||||
read_lock(&blkif->rings_lock); \
|
||||
if (!blkif->rings) \
|
||||
goto out; \
|
||||
\
|
||||
|
|
@ -395,6 +413,7 @@ void xen_blkif_interface_fini(void)
|
|||
} \
|
||||
\
|
||||
out: \
|
||||
read_unlock(&blkif->rings_lock); \
|
||||
return sprintf(buf, format, result); \
|
||||
} \
|
||||
static DEVICE_ATTR(name, 0444, show_##name, NULL)
|
||||
|
|
@ -1102,8 +1121,7 @@ static int connect_ring(struct backend_info *be)
|
|||
requested_num_queues, xenblk_max_queues);
|
||||
return -ENOSYS;
|
||||
}
|
||||
blkif->nr_rings = requested_num_queues;
|
||||
if (xen_blkif_alloc_rings(blkif))
|
||||
if (xen_blkif_alloc_rings(blkif, requested_num_queues))
|
||||
return -ENOMEM;
|
||||
|
||||
pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user