Commit 952835ed authored by Stefan Haberland's avatar Stefan Haberland Committed by Jens Axboe

s390/dasd: fix use after free in dasd path handling

When new configuration data is obtained after a path event it is stored
in the per path array. The old data needs to be freed.
The first valid configuration data is also referenced in the device
private structure to identify the device.
When the old per path configuration data was freed the device still
pointed to the already freed data leading to a use after free.

Fix by replacing also the device configuration data with the newly
obtained one before the old data gets freed.

Fixes: 46018121 ("s390/dasd: Store path configuration data during path handling")
Cc: stable@vger.kernel.org # 5.11+
Signed-off-by: default avatarStefan Haberland <sth@linux.ibm.com>
Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.ibm.com>
Link: https://lore.kernel.org/r/20210804151800.4031761-2-sth@linux.ibm.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 340e8457
...@@ -1004,15 +1004,23 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) ...@@ -1004,15 +1004,23 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
static void dasd_eckd_store_conf_data(struct dasd_device *device, static void dasd_eckd_store_conf_data(struct dasd_device *device,
struct dasd_conf_data *conf_data, int chp) struct dasd_conf_data *conf_data, int chp)
{ {
struct dasd_eckd_private *private = device->private;
struct channel_path_desc_fmt0 *chp_desc; struct channel_path_desc_fmt0 *chp_desc;
struct subchannel_id sch_id; struct subchannel_id sch_id;
void *cdp;
ccw_device_get_schid(device->cdev, &sch_id);
/* /*
* path handling and read_conf allocate data * path handling and read_conf allocate data
* free it before replacing the pointer * free it before replacing the pointer
* also replace the old private->conf_data pointer
* with the new one if this points to the same data
*/ */
kfree(device->path[chp].conf_data); cdp = device->path[chp].conf_data;
if (private->conf_data == cdp) {
private->conf_data = (void *)conf_data;
dasd_eckd_identify_conf_parts(private);
}
ccw_device_get_schid(device->cdev, &sch_id);
device->path[chp].conf_data = conf_data; device->path[chp].conf_data = conf_data;
device->path[chp].cssid = sch_id.cssid; device->path[chp].cssid = sch_id.cssid;
device->path[chp].ssid = sch_id.ssid; device->path[chp].ssid = sch_id.ssid;
...@@ -1020,6 +1028,7 @@ static void dasd_eckd_store_conf_data(struct dasd_device *device, ...@@ -1020,6 +1028,7 @@ static void dasd_eckd_store_conf_data(struct dasd_device *device,
if (chp_desc) if (chp_desc)
device->path[chp].chpid = chp_desc->chpid; device->path[chp].chpid = chp_desc->chpid;
kfree(chp_desc); kfree(chp_desc);
kfree(cdp);
} }
static void dasd_eckd_clear_conf_data(struct dasd_device *device) static void dasd_eckd_clear_conf_data(struct dasd_device *device)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment