s390/dasd: Guard sysfs discipline callbacks against unallocated private data

Several sysfs show/store handlers call a discipline callback that
dereferences device->private, either directly or through the
DASD_DEFINE_ATTR() macro. During dasd_generic_set_online() the discipline
is assigned before check_device() allocates device->private, so an
unprivileged read of one of these world-readable attributes in that window
dereferences a NULL pointer and panics.

Guard the dereference inside each callback that actually touches
device->private.

Fixes: c729696bcf ("s390/dasd: Recognise data for ESE volumes")
Cc: stable@vger.kernel.org
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Link: https://patch.msgid.link/20260805111612.1285190-4-sth@linux.ibm.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Stefan Haberland 2026-08-05 13:15:56 +02:00 committed by Jens Axboe
parent 6fb5ba2e7e
commit 2a1780f9fc

View File

@ -1491,6 +1491,8 @@ static void dasd_eckd_reset_path(struct dasd_device *device, __u8 pm)
struct dasd_eckd_private *private = device->private;
unsigned long flags;
if (!private)
return;
if (!private->fcx_max_data)
private->fcx_max_data = get_fcx_max_data(device);
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
@ -1646,6 +1648,9 @@ static int dasd_eckd_is_ese(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->vsq.vol_info.ese;
}
@ -1653,6 +1658,9 @@ static int dasd_eckd_ext_pool_id(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->vsq.extent_pool_id;
}
@ -1666,6 +1674,9 @@ static int dasd_eckd_space_configured(struct dasd_device *device)
struct dasd_eckd_private *private = device->private;
int rc;
if (!private)
return 0;
rc = dasd_eckd_read_vol_info(device);
return rc ? : private->vsq.space_configured;
@ -1680,6 +1691,9 @@ static int dasd_eckd_space_allocated(struct dasd_device *device)
struct dasd_eckd_private *private = device->private;
int rc;
if (!private)
return 0;
rc = dasd_eckd_read_vol_info(device);
return rc ? : private->vsq.space_allocated;
@ -1689,6 +1703,9 @@ static int dasd_eckd_logical_capacity(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->vsq.logical_capacity;
}
@ -1831,7 +1848,11 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
static int dasd_eckd_ext_size(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
struct dasd_ext_pool_sum eps = private->eps;
struct dasd_ext_pool_sum eps;
if (!private)
return 0;
eps = private->eps;
if (!eps.flags.extent_size_valid)
return 0;
@ -1847,6 +1868,9 @@ static int dasd_eckd_ext_pool_warn_thrshld(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->eps.warn_thrshld;
}
@ -1854,6 +1878,9 @@ static int dasd_eckd_ext_pool_cap_at_warnlevel(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->eps.flags.capacity_at_warnlevel;
}
@ -1864,6 +1891,9 @@ static int dasd_eckd_ext_pool_oos(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->eps.flags.pool_oos;
}
@ -5935,8 +5965,11 @@ static int dasd_eckd_query_host_access(struct dasd_device *device,
struct ccw1 *ccw;
int rc;
if (!private)
return -ENODEV;
/* not available for HYPER PAV alias devices */
if (!device->block && private->lcu->pav == HYPER_PAV)
if (!device->block && private->lcu && private->lcu->pav == HYPER_PAV)
return -EOPNOTSUPP;
/* may not be supported by the storage server */
@ -6801,6 +6834,9 @@ static int dasd_eckd_hpf_enabled(struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
if (!private)
return 0;
return private->fcx_max_data ? 1 : 0;
}