diff --git a/0029-clear-path-in-mpp-pg-in-clear_ref_from_mpp.patch b/0029-clear-path-in-mpp-pg-in-clear_ref_from_mpp.patch new file mode 100644 index 0000000000000000000000000000000000000000..16b0894e180c58a3e77f6c84b78d34aa966702dd --- /dev/null +++ b/0029-clear-path-in-mpp-pg-in-clear_ref_from_mpp.patch @@ -0,0 +1,86 @@ +From 11e3f4d3ce82fad0d324f220e8339deed13f1e56 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 13 Jul 2020 13:07:40 +0200 +Subject: [PATCH] clear path in mpp->pg in clear_ref_from_mpp + +When multipathd del path xxx, multipathd -v2, multipathd add path xxx and multipath -U +dm-x are executed simultaneously, multipath -U dm-x will case coredump. + +The reason is that there are two paths with same dev_t in dm_table. The process +is as follows: + +multipathd del path xxx(such as sde whose dev_t is 8:64): + +cli_del_path + ->ev_remove_path + ->domap //dm_table in kernel will be reloaded and doesn't contain 8:64. + //Then multipath -v2 is executed, and the dm_table in kernel + //will be reloaded and contains 8:64. + ->setup_multipath + ->update_multipath_strings + ->update_multipath_table + ->dm_get_map //get params with 8:64 + ->disassemble_map //pp1 will be saved mpp->pg + ->delete pp1 in pathvec + ->clear_ref_from_mpp //pp is cleared in mpp->paths but still saved in + //mpp->pg + ->free_paths //pp1 is freed but still exist in mpp->pg and is not null + +multipathd add path sde +cli_add_path + ->store_pathinfo //alloc pp2 (dev_t is 8:64), and store it to gvecs->pathvec + //pp2 is not equal to pp1 + ->ev_add_path + ->adopt_paths + ->update_mpp_paths //pp1 is found in mpp->pg and its dev_t is + //8:64 and dev is not sde (cased by free). + //it will be stored in mpp->paths. + ->pp2 is stored to mpp->paths + ->setup_map //params with two 8:64 + ->domap //dm_table is reloaded and contains two 8:64 + +multipath -U dm-x(sde is one path of dm-x) +main + ->check_usable_paths + ->dm_get_maps //get params with two 8:64 + ->disassemble_map //alloc pp3 whose dev_t is 8:64, and pp3 is saved + //twice in mpp->pg + ->free_multipath(mpp, FREE_PATHS) //double free pp3 + +Here, we add that pp1 in mpp->pg is cleared in clear_ref_from_mpp. + +Reported-by: Tianxiong Lu +Signed-off-by: lixiaokeng +--- + multipathd/main.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/multipathd/main.c b/multipathd/main.c +index 09ea102..e7e176b 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -845,7 +845,9 @@ static + void clear_ref_from_mpp(struct path * pp, struct vectors * vecs) + { + struct multipath * mpp = NULL; ++ struct pathgroup * pgp; + int i = -1; ++ int j; + + mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); + if(!!mpp){ +@@ -853,6 +855,11 @@ void clear_ref_from_mpp(struct path * pp, struct vectors * vecs) + if ((i = find_slot(mpp->paths, (void *)pp)) != -1){ + vector_del_slot(mpp->paths, i); + } ++ vector_foreach_slot (mpp->pg, pgp, j) { ++ if ((i = find_slot(pgp->paths, (void *)pp)) != -1){ ++ vector_del_slot(pgp->paths, i); ++ } ++ } + } + } + +-- +2.14.3 (Apple Git-98) + diff --git a/0030-multipathd-fix-mpp-hwe-use-after-free-in-ev_remove_p.patch b/0030-multipathd-fix-mpp-hwe-use-after-free-in-ev_remove_p.patch new file mode 100644 index 0000000000000000000000000000000000000000..2df747ea712f25a0172410637fea2d4410501756 --- /dev/null +++ b/0030-multipathd-fix-mpp-hwe-use-after-free-in-ev_remove_p.patch @@ -0,0 +1,56 @@ +From 0b0062058ef0bcf2a80194700ed20304d4445854 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 13 Jul 2020 13:07:40 +0200 +Subject: [PATCH] multipathd: fix mpp->hwe use after free in ev_remove_path + +When a multipath device (for example mpatha) has only one path +and it can't flush because of occupation, "multipathd del path" +and "multipath -v2" may lead to multipathd coredump. The reason +is that mpp->hwe = pp->hwe but pp->hwe will be free later. Here +we clear mpp->hwe in clear_ref_from_mpp. + +Signed-off-by: Lixiaokeng +--- + multipathd/main.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/multipathd/main.c b/multipathd/main.c +index e7e176b..1c02441 100644 +--- a/multipathd/main.c ++++ b/multipathd/main.c +@@ -850,17 +850,23 @@ void clear_ref_from_mpp(struct path * pp, struct vectors * vecs) + int j; + + mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); +- if(!!mpp){ +- condlog(2, "%s: clear path from mpp %s", pp->dev, mpp->alias); +- if ((i = find_slot(mpp->paths, (void *)pp)) != -1){ +- vector_del_slot(mpp->paths, i); +- } +- vector_foreach_slot (mpp->pg, pgp, j) { +- if ((i = find_slot(pgp->paths, (void *)pp)) != -1){ +- vector_del_slot(pgp->paths, i); +- } ++ if (!mpp) { ++ return; ++ } ++ ++ condlog(2, "%s: clear path from mpp %s", pp->dev, mpp->alias); ++ if (mpp->hwe == pp->hwe) { ++ mpp->hwe = NULL; ++ } ++ if ((i = find_slot(mpp->paths, (void *)pp)) != -1) { ++ vector_del_slot(mpp->paths, i); ++ } ++ vector_foreach_slot(mpp->pg, pgp, j) { ++ if ((i = find_slot(pgp->paths, (void *)pp)) != -1) { ++ vector_del_slot(pgp->paths, i); + } + } ++ extract_hwe_from_path(mpp); + } + + static int +-- +2.14.3 (Apple Git-98) + diff --git a/0031-libmultipath-fix-daemon-memory-leak-in-disassemble_m.patch b/0031-libmultipath-fix-daemon-memory-leak-in-disassemble_m.patch new file mode 100644 index 0000000000000000000000000000000000000000..edf4bb34834a3495861a0e97e7e7acc7bbafd1f7 --- /dev/null +++ b/0031-libmultipath-fix-daemon-memory-leak-in-disassemble_m.patch @@ -0,0 +1,82 @@ +From cb7441c91c27c685ea47043a0eab20c1eb56206e Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 13 Jul 2020 13:07:40 +0200 +Subject: [PATCH] libmultipath: fix daemon memory leak in disassemble_map + +When one iscsi device logs in and logs out with the "multipath -r" +executed at the same time, memory leak happens in multipathd +process. + +The reason is following. When "multipath -r" is executed, the path +will be free in configure function. Before path_discovery executed, +iscsi device logs out. Then path_discovery will not find any path and +there is no path in the gvecs->pathvec. When map_discovery function +is executed, disassemble_map function will be called. Because +gvecs->pathvec->slot is empty and is_deamon is 1, a path will be +allocated and is not stored in gvecs->pathvec but store in +mpp->pg. But when the mpp is removed and freed by remove_map +function, the path will not be free and can't be find anymore. + +The procedure details given as follows, +1."multipath -r" is executed +main + ->child + ->reconfigure + ->configure + ->path_discovery //after iscsi logout + ->map_discovery + ->update_multipath_table + ->disassemble_map + ->alloc_path +2.then "multipath -r" is executed again +main + ->child + ->reconfigure + ->remove_maps_and_stop_waiters + ->remove_maps + +Here, we skip alloc_path if pp isn't find in pathvec and process is daemon. In +daemon, we should not store path with incomplete information to pathvec. The +pathvec stores all paths in daemon, so it is reasonable keep same with pathvec. + +Reported-by: Tianxiong Lu +Signed-off-by: Lixiaokeng +Signed-off-by: Zhiqiang Liu +--- + libmultipath/dmparser.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c +index 7da5fbf..3ce6eb3 100644 +--- a/libmultipath/dmparser.c ++++ b/libmultipath/dmparser.c +@@ -305,6 +305,16 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp, + } + + if (!pp) { ++ /* daemon should keep same with pathvec */ ++ /* pp is not find in pathvec, skip it */ ++ if (is_daemon) { ++ FREE(word); ++ for (k = 0; k < num_paths_args; k++) { ++ p += get_word(p, NULL); ++ } ++ continue; ++ } ++ + pp_unfound = 1; + pp = alloc_path(); + +@@ -317,8 +327,7 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp, + strlcpy(pp->wwid, mpp->wwid, + WWID_SIZE); + } +- /* Only call this in multipath client mode */ +- if (!is_daemon && store_path(pathvec, pp)) { ++ if (store_path(pathvec, pp)) { + free_path(pp); + goto out1; + } +-- +2.14.3 (Apple Git-98) + diff --git a/0032-libmultipath-fix-multipathd-coredump-in-disassemble_.patch b/0032-libmultipath-fix-multipathd-coredump-in-disassemble_.patch new file mode 100644 index 0000000000000000000000000000000000000000..6a2b754cd91f699121ff343355992dcfc615ae89 --- /dev/null +++ b/0032-libmultipath-fix-multipathd-coredump-in-disassemble_.patch @@ -0,0 +1,62 @@ +From 72816e34d2e4a3197e4a590e573c4fc64a360145 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Mon, 13 Jul 2020 13:07:40 +0200 +Subject: [PATCH] libmultipath: fix multipathd coredump in disassemble_map + +Coredump appears when events are executed in a certain order. +1. The sdc and sdd are added as paths of d1. The sdc is added +firstly and d1->wait_for_udev be set to 1. Then sdd is added but +it just adds to pathvec because d1->wait_for_udev is 1. +2. The uev_remove_path(sdc) are executed. Because d1 has one +path, d1 will be flushed. +3. The uev_add_path(sdc) are executed. Now sdc and sdd will +both add to d1 in adopt_paths because sdd->wwid is d1. And +d1->wait_for_udev be set to 1. +4. The uev_remove_path(sdd) are executed. Because d1->wait_for_udev +is 1, domap doesn't executed and the major:minor of sdd(8:64) +still exist in kernel d1. The sdd in pathvec is deleted. +5. The uev_add_path(sdd) are executed. Now the sdd(8:64) is +a path of d2. And new sdd is added to pathvec. +6. The update_multipath_strings(d1) are executed. The d1 find +sdd in pathvec by dev_t(8:64)and sdd will be add to d1. Now +the pointer of sdd is store in paths of d1 and d2. +7. When NIC is down and a new path add to d1, sdd will be freed +in verify_paths (because sdd is actually a path of d2). +8. When d2->hwe is sdd->hwe and setup_map(d2) is called. Core +causes. + +The path shouldn't be add to the mpp whose wwid is different +with its. Here we add wwid check in disassemble_map. This bug +has been solved in upstream in update_pathvec_from_dm. It is +a great change, so we fix it with huawei patch. This patch could +be discarded when multipath-tools update. + +Signed-off-by:lixiaokeng +--- + libmultipath/dmparser.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c +index 3ce6eb3..9aa6bc5 100644 +--- a/libmultipath/dmparser.c ++++ b/libmultipath/dmparser.c +@@ -332,6 +332,16 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp, + goto out1; + } + } else { ++ if (strlen(pp->wwid) && strlen(mpp->wwid) && ++ strcmp(pp->wwid, mpp->wwid) != 0) { ++ condlog(0, "%s: path wwid is different with that of %s.\n", pp->dev_t, mpp->alias); ++ FREE(word); ++ for (k = 0; k < num_paths_args; k++) { ++ p += get_word(p, NULL); ++ } ++ continue; ++ } ++ + if (!strlen(pp->wwid) && + strlen(mpp->wwid)) + strlcpy(pp->wwid, mpp->wwid, +-- +2.14.3 (Apple Git-98) + diff --git a/multipath-tools.spec b/multipath-tools.spec index 717b6f3d164e925e46c0a50bb7ff88fbed61bb99..6bdf00b7f696810b6153f12a144826d3bf3afd94 100644 --- a/multipath-tools.spec +++ b/multipath-tools.spec @@ -2,7 +2,7 @@ Name: multipath-tools Version: 0.8.4 -Release: 13 +Release: 14 Summary: Tools to manage multipath devices with the device-mapper License: GPL-2.0-or-later and LGPL-2.0-only URL: http://christophe.varoqui.free.fr/ @@ -38,6 +38,10 @@ Patch25: 0025-fix-boolean-value-with-json-c-0.14.patch Patch26: 0026-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch Patch27: 0027-libmultipath-refactor-path-counting.patch Patch28: 0028-libmultipath-count-pending-paths-as-active-on-loads.patch +Patch29: 0029-clear-path-in-mpp-pg-in-clear_ref_from_mpp.patch +Patch30: 0030-multipathd-fix-mpp-hwe-use-after-free-in-ev_remove_p.patch +Patch31: 0031-libmultipath-fix-daemon-memory-leak-in-disassemble_m.patch +Patch32: 0032-libmultipath-fix-multipathd-coredump-in-disassemble_.patch BuildRequires: multipath-tools, libcmocka, libcmocka-devel BuildRequires: gcc, libaio-devel, userspace-rcu-devel, device-mapper-devel >= 1.02.89 @@ -184,6 +188,9 @@ fi %changelog +* Fri Apr 8 2022 lixiaokeng - 0.8.4-14 +- fix coredump and memory leak in long-term stability test + * Tue Mar 8 2022 lixiaokeng - 0.8.4-13 - don't create local nvme multipath device when enable remove_local_path