mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
s390/dasd: fix double free in dasd_eckd_read_conf
The configuration data is stored per path and also the first valid configuration data per device. When dasd_eckd_read_conf is called again after a path got lost the device configuration data is cleared but possibly not the per path configuration data. This might lead to a double free when the lost path gets operational again. Fix by clearing all per path configuration data when the first valid configuration data is received and stored. Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
55a423b6f1
commit
c7c0c9deb0
1 changed files with 25 additions and 12 deletions
|
@ -1032,6 +1032,21 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dasd_eckd_clear_conf_data(struct dasd_device *device)
|
||||
{
|
||||
struct dasd_eckd_private *private;
|
||||
int i;
|
||||
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
private->conf_data = NULL;
|
||||
private->conf_len = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
kfree(private->path_conf_data[i]);
|
||||
private->path_conf_data[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int dasd_eckd_read_conf(struct dasd_device *device)
|
||||
{
|
||||
void *conf_data;
|
||||
|
@ -1068,19 +1083,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
path_data->opm |= lpm;
|
||||
continue; /* no error */
|
||||
}
|
||||
pos = pathmask_to_pos(lpm);
|
||||
kfree(private->path_conf_data[pos]);
|
||||
if ((__u8 *)private->path_conf_data[pos] ==
|
||||
private->conf_data) {
|
||||
private->conf_data = NULL;
|
||||
private->conf_len = 0;
|
||||
conf_data_saved = 0;
|
||||
}
|
||||
private->path_conf_data[pos] =
|
||||
(struct dasd_conf_data *) conf_data;
|
||||
/* save first valid configuration data */
|
||||
if (!conf_data_saved) {
|
||||
kfree(private->conf_data);
|
||||
/* initially clear previously stored conf_data */
|
||||
dasd_eckd_clear_conf_data(device);
|
||||
private->conf_data = conf_data;
|
||||
private->conf_len = conf_len;
|
||||
if (dasd_eckd_identify_conf_parts(private)) {
|
||||
|
@ -1089,6 +1095,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
kfree(conf_data);
|
||||
continue;
|
||||
}
|
||||
pos = pathmask_to_pos(lpm);
|
||||
/* store per path conf_data */
|
||||
private->path_conf_data[pos] =
|
||||
(struct dasd_conf_data *) conf_data;
|
||||
/*
|
||||
* build device UID that other path data
|
||||
* can be compared to it
|
||||
|
@ -1146,7 +1156,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
|
|||
path_data->cablepm |= lpm;
|
||||
continue;
|
||||
}
|
||||
|
||||
pos = pathmask_to_pos(lpm);
|
||||
/* store per path conf_data */
|
||||
private->path_conf_data[pos] =
|
||||
(struct dasd_conf_data *) conf_data;
|
||||
path_private.conf_data = NULL;
|
||||
path_private.conf_len = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue