提交 c7c0c9de 编写于 作者: S Stefan Haberland 提交者: Martin Schwidefsky

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: NSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: NStefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: NMartin Schwidefsky <schwidefsky@de.ibm.com>
上级 55a423b6
...@@ -1032,6 +1032,21 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) ...@@ -1032,6 +1032,21 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
return 0; 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) static int dasd_eckd_read_conf(struct dasd_device *device)
{ {
void *conf_data; void *conf_data;
...@@ -1068,19 +1083,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device) ...@@ -1068,19 +1083,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
path_data->opm |= lpm; path_data->opm |= lpm;
continue; /* no error */ 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 */ /* save first valid configuration data */
if (!conf_data_saved) { 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_data = conf_data;
private->conf_len = conf_len; private->conf_len = conf_len;
if (dasd_eckd_identify_conf_parts(private)) { if (dasd_eckd_identify_conf_parts(private)) {
...@@ -1089,6 +1095,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device) ...@@ -1089,6 +1095,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
kfree(conf_data); kfree(conf_data);
continue; 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 * build device UID that other path data
* can be compared to it * can be compared to it
...@@ -1146,7 +1156,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device) ...@@ -1146,7 +1156,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
path_data->cablepm |= lpm; path_data->cablepm |= lpm;
continue; 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_data = NULL;
path_private.conf_len = 0; path_private.conf_len = 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册