diff -Nru multipath-tools-0.8.3/debian/changelog multipath-tools-0.8.3/debian/changelog --- multipath-tools-0.8.3/debian/changelog 2023-07-24 23:06:36.000000000 +0000 +++ multipath-tools-0.8.3/debian/changelog 2023-11-07 21:20:27.000000000 +0000 @@ -1,3 +1,22 @@ +multipath-tools (0.8.3-1ubuntu2.3) focal; urgency=medium + + [ Jorge Merlino ] + * Multipath devices not removed with high load (LP: #2039719) + - d/p/lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch: + change the return value of some functions from a boolean to symbolic codes + to differentiate errors + - d/p/lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch: + use the new error codes to change the error processing on the + check_path() procedure + + [ Mauricio Faria de Oliveira ] + * Add upstream fixes: + - d/p/lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch + - d/p/lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch + (LP: #2042366) + + -- Jorge Merlino Tue, 07 Nov 2023 18:20:27 -0300 + multipath-tools (0.8.3-1ubuntu2.2) focal; urgency=medium * Do not install init scripts (LP: #2000186) diff -Nru multipath-tools-0.8.3/debian/patches/lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch multipath-tools-0.8.3/debian/patches/lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch --- multipath-tools-0.8.3/debian/patches/lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.8.3/debian/patches/lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch 2023-11-07 21:19:21.000000000 +0000 @@ -0,0 +1,324 @@ +From db7a0bc38d59e4fd67b1df2a01f111c64de5cdf3 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 2 Jul 2020 19:07:00 -0500 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2039719 +Origin: backport, https://github.com/opensvc/multipath-tools/commit/db7a0bc +Subject: [PATCH] libmultipath: make dm_get_map/status return codes symbolic + +dm_get_map() and dm_get_status() now use symbolic return codes. They +also differentiate between failing to get information from device-mapper +and not finding the requested device. These symboilc return codes are +also used by update_multipath_* functions. + +Signed-off-by: Benjamin Marzinski +--- + libmultipath/devmapper.c | 51 +++++++++++++++++++++++++------------- + libmultipath/devmapper.h | 6 +++++ + libmultipath/structs_vec.c | 45 +++++++++++++++++++-------------- + multipathd/main.c | 12 ++++----- + 4 files changed, 72 insertions(+), 42 deletions(-) + +[mfo: backport: refresh context lines in devmapper.h (last 2 lines) +and last hunk of structs_vec.c (last line).] + +Index: multipath-tools-0.8.3/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-0.8.3.orig/libmultipath/devmapper.c ++++ multipath-tools-0.8.3/libmultipath/devmapper.c +@@ -520,36 +520,43 @@ int dm_map_present(const char * str) + + int dm_get_map(const char *name, unsigned long long *size, char *outparams) + { +- int r = 1; ++ int r = DMP_ERR; + struct dm_task *dmt; + uint64_t start, length; + char *target_type = NULL; + char *params = NULL; + + if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE))) +- return 1; ++ return r; + + if (!dm_task_set_name(dmt, name)) + goto out; + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) ++ errno = 0; ++ if (!dm_task_run(dmt)) { ++ if (dm_task_get_errno(dmt) == ENXIO) ++ r = DMP_NOT_FOUND; + goto out; ++ } + ++ r = DMP_NOT_FOUND; + /* Fetch 1st target */ +- dm_get_next_target(dmt, NULL, &start, &length, +- &target_type, ¶ms); ++ if (dm_get_next_target(dmt, NULL, &start, &length, ++ &target_type, ¶ms) != NULL) ++ /* more than one target */ ++ goto out; + + if (size) + *size = length; + + if (!outparams) { +- r = 0; ++ r = DMP_OK; + goto out; + } + if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE) +- r = 0; ++ r = DMP_OK; + out: + dm_task_destroy(dmt); + return r; +@@ -623,35 +630,45 @@ is_mpath_part(const char *part_name, con + + int dm_get_status(const char *name, char *outstatus) + { +- int r = 1; ++ int r = DMP_ERR; + struct dm_task *dmt; + uint64_t start, length; + char *target_type = NULL; + char *status = NULL; + + if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS))) +- return 1; ++ return r; + + if (!dm_task_set_name(dmt, name)) + goto out; + + dm_task_no_open_count(dmt); + +- if (!dm_task_run(dmt)) ++ errno = 0; ++ if (!dm_task_run(dmt)) { ++ if (dm_task_get_errno(dmt) == ENXIO) ++ r = DMP_NOT_FOUND; + goto out; ++ } + ++ r = DMP_NOT_FOUND; + /* Fetch 1st target */ +- dm_get_next_target(dmt, NULL, &start, &length, +- &target_type, &status); ++ if (dm_get_next_target(dmt, NULL, &start, &length, ++ &target_type, &status) != NULL) ++ goto out; ++ ++ if (!target_type || strcmp(target_type, TGT_MPATH) != 0) ++ goto out; ++ + if (!status) { + condlog(2, "get null status."); + goto out; + } + + if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE) +- r = 0; ++ r = DMP_OK; + out: +- if (r) ++ if (r != DMP_OK) + condlog(0, "%s: error getting map status string", name); + + dm_task_destroy(dmt); +@@ -860,7 +877,7 @@ int _dm_flush_map (const char * mapname, + return 1; + + if (need_suspend && +- !dm_get_map(mapname, &mapsize, params) && ++ dm_get_map(mapname, &mapsize, params) == DMP_OK && + strstr(params, "queue_if_no_path")) { + if (!dm_queue_if_no_path(mapname, 0)) + queue_if_no_path = 1; +@@ -1069,7 +1086,7 @@ struct multipath *dm_get_multipath(const + if (!mpp->alias) + goto out; + +- if (dm_get_map(name, &mpp->size, NULL)) ++ if (dm_get_map(name, &mpp->size, NULL) != DMP_OK) + goto out; + + dm_get_uuid(name, mpp->wwid, WWID_SIZE); +@@ -1253,7 +1270,7 @@ do_foreach_partmaps (const char * mapnam + /* + * and we can fetch the map table from the kernel + */ +- !dm_get_map(names->name, &size, ¶ms[0]) && ++ dm_get_map(names->name, &size, ¶ms[0]) == DMP_OK && + + /* + * and the table maps over the multipath map +Index: multipath-tools-0.8.3/libmultipath/devmapper.h +=================================================================== +--- multipath-tools-0.8.3.orig/libmultipath/devmapper.h ++++ multipath-tools-0.8.3/libmultipath/devmapper.h +@@ -27,6 +27,12 @@ + #define UUID_PREFIX "mpath-" + #define UUID_PREFIX_LEN (sizeof(UUID_PREFIX) - 1) + ++enum { ++ DMP_ERR, ++ DMP_OK, ++ DMP_NOT_FOUND, ++}; ++ + void dm_init(int verbosity); + void libmp_dm_init(void); + void libmp_udev_set_sync_support(int on); +Index: multipath-tools-0.8.3/libmultipath/structs_vec.c +=================================================================== +--- multipath-tools-0.8.3.orig/libmultipath/structs_vec.c ++++ multipath-tools-0.8.3/libmultipath/structs_vec.c +@@ -196,43 +196,47 @@ extract_hwe_from_path(struct multipath * + int + update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon) + { ++ int r = DMP_ERR; + char params[PARAMS_SIZE] = {0}; + + if (!mpp) +- return 1; ++ return r; + +- if (dm_get_map(mpp->alias, &mpp->size, params)) { +- condlog(3, "%s: cannot get map", mpp->alias); +- return 1; ++ r = dm_get_map(mpp->alias, &mpp->size, params); ++ if (r != DMP_OK) { ++ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present"); ++ return r; + } + + if (disassemble_map(pathvec, params, mpp, is_daemon)) { + condlog(3, "%s: cannot disassemble map", mpp->alias); +- return 1; ++ return DMP_ERR; + } + +- return 0; ++ return DMP_OK; + } + + int + update_multipath_status (struct multipath *mpp) + { ++ int r = DMP_ERR; + char status[PARAMS_SIZE] = {0}; + + if (!mpp) +- return 1; ++ return r; + +- if (dm_get_status(mpp->alias, status)) { +- condlog(3, "%s: cannot get status", mpp->alias); +- return 1; ++ r = dm_get_status(mpp->alias, status); ++ if (r != DMP_OK) { ++ condlog(3, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present"); ++ return r; + } + + if (disassemble_status(status, mpp)) { + condlog(3, "%s: cannot disassemble status", mpp->alias); +- return 1; ++ return DMP_ERR; + } + +- return 0; ++ return DMP_OK; + } + + void sync_paths(struct multipath *mpp, vector pathvec) +@@ -264,10 +268,10 @@ int + update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon) + { + struct pathgroup *pgp; +- int i; ++ int i, r = DMP_ERR; + + if (!mpp) +- return 1; ++ return r; + + update_mpp_paths(mpp, pathvec); + condlog(4, "%s: %s", mpp->alias, __FUNCTION__); +@@ -276,18 +280,21 @@ update_multipath_strings(struct multipat + free_pgvec(mpp->pg, KEEP_PATHS); + mpp->pg = NULL; + +- if (update_multipath_table(mpp, pathvec, is_daemon)) +- return 1; ++ r = update_multipath_table(mpp, pathvec, is_daemon); ++ if (r != DMP_OK) ++ return r; ++ + sync_paths(mpp, pathvec); + +- if (update_multipath_status(mpp)) +- return 1; ++ r = update_multipath_status(mpp); ++ if (r != DMP_OK) ++ return r; + + vector_foreach_slot(mpp->pg, pgp, i) + if (pgp->paths) + path_group_prio_update(pgp); + +- return 0; ++ return DMP_OK; + } + + void enter_recovery_mode(struct multipath *mpp) +Index: multipath-tools-0.8.3/multipathd/main.c +=================================================================== +--- multipath-tools-0.8.3.orig/multipathd/main.c ++++ multipath-tools-0.8.3/multipathd/main.c +@@ -448,7 +448,7 @@ int __setup_multipath(struct vectors *ve + goto out; + } + +- if (update_multipath_strings(mpp, vecs->pathvec, 1)) { ++ if (update_multipath_strings(mpp, vecs->pathvec, 1) != DMP_OK) { + condlog(0, "%s: failed to setup multipath", mpp->alias); + goto out; + } +@@ -587,9 +587,9 @@ add_map_without_path (struct vectors *ve + mpp->mpe = find_mpe(conf->mptable, mpp->wwid); + put_multipath_config(conf); + +- if (update_multipath_table(mpp, vecs->pathvec, 1)) ++ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK) + goto out; +- if (update_multipath_status(mpp)) ++ if (update_multipath_status(mpp) != DMP_OK) + goto out; + + if (!vector_alloc_slot(vecs->mpvec)) +@@ -1380,8 +1380,8 @@ map_discovery (struct vectors * vecs) + return 1; + + vector_foreach_slot (vecs->mpvec, mpp, i) +- if (update_multipath_table(mpp, vecs->pathvec, 1) || +- update_multipath_status(mpp)) { ++ if (update_multipath_table(mpp, vecs->pathvec, 1) != DMP_OK || ++ update_multipath_status(mpp) != DMP_OK) { + remove_map(mpp, vecs, 1); + i--; + } +@@ -2121,7 +2121,7 @@ check_path (struct vectors * vecs, struc + /* + * Synchronize with kernel state + */ +- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1)) { ++ if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) { + condlog(1, "%s: Could not synchronize with kernel state", + pp->dev); + pp->dmstate = PSTATE_UNDEF; diff -Nru multipath-tools-0.8.3/debian/patches/lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch multipath-tools-0.8.3/debian/patches/lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch --- multipath-tools-0.8.3/debian/patches/lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.8.3/debian/patches/lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch 2023-11-07 21:20:27.000000000 +0000 @@ -0,0 +1,118 @@ +From bf44dda958c4e8c5852626b3c6d5a449754fa730 Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Thu, 2 Jul 2020 19:07:01 -0500 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2039719 +Origin: backport, https://github.com/opensvc/multipath-tools/commit/bf44dda +Subject: [PATCH] multipathd: fix check_path errors with removed map + +If a multipath device is removed during, or immediately before the call +to check_path(), multipathd can behave incorrectly. A missing multpath +device will cause update_multipath_strings() to fail, setting +pp->dmstate to PSTATE_UNDEF. If the path is up, this state will cause +reinstate_path() to be called, which will also fail. This will trigger +a reload, restoring the recently removed device. + +If update_multipath_strings() fails because there is no multipath +device, check_path should just quit, since the remove dmevent and uevent +are likely already queued up. Also, I don't see any reason to reload the +multipath device if reinstate fails. This code was added by +fac68d7a99ef17d496079538a5c6836acd7911ab, which clamined that reinstate +could fail if the path was disabled. Looking through the current kernel +code, I can't see any reason why a reinstate would fail, where a reload +would help. If the path was missing from the multipath device, +update_multipath_strings() would already catch that, and quit +check_path() early, which make more sense to me than reloading does. + +Signed-off-by: Benjamin Marzinski +--- + multipathd/main.c | 44 +++++++++++++++++++------------------------- + 1 file changed, 19 insertions(+), 25 deletions(-) + +[mfo/jorge-merlino: backport: reinstate_path() has add_active param.] + +Index: multipath-tools-0.8.3/multipathd/main.c +=================================================================== +--- multipath-tools-0.8.3.orig/multipathd/main.c ++++ multipath-tools-0.8.3/multipathd/main.c +@@ -1645,23 +1645,19 @@ fail_path (struct path * pp, int del_act + /* + * caller must have locked the path list before calling that function + */ +-static int ++static void + reinstate_path (struct path * pp, int add_active) + { +- int ret = 0; +- + if (!pp->mpp) +- return 0; ++ return; + +- if (dm_reinstate_path(pp->mpp->alias, pp->dev_t)) { ++ if (dm_reinstate_path(pp->mpp->alias, pp->dev_t)) + condlog(0, "%s: reinstate failed", pp->dev_t); +- ret = 1; +- } else { ++ else { + condlog(2, "%s: reinstated", pp->dev_t); + if (add_active) + update_queue_mode_add_path(pp->mpp); + } +- return ret; + } + + static void +@@ -2121,9 +2117,16 @@ check_path (struct vectors * vecs, struc + /* + * Synchronize with kernel state + */ +- if (update_multipath_strings(pp->mpp, vecs->pathvec, 1) != DMP_OK) { +- condlog(1, "%s: Could not synchronize with kernel state", +- pp->dev); ++ ret = update_multipath_strings(pp->mpp, vecs->pathvec, 1); ++ if (ret != DMP_OK) { ++ if (ret == DMP_NOT_FOUND) { ++ /* multipath device missing. Likely removed */ ++ condlog(1, "%s: multipath device '%s' not found", ++ pp->dev, pp->mpp->alias); ++ return 0; ++ } else ++ condlog(1, "%s: Couldn't synchronize with kernel state", ++ pp->dev); + pp->dmstate = PSTATE_UNDEF; + } + /* if update_multipath_strings orphaned the path, quit early */ +@@ -2218,12 +2221,8 @@ check_path (struct vectors * vecs, struc + add_active = 1; + else + add_active = 0; +- if (!disable_reinstate && reinstate_path(pp, add_active)) { +- condlog(3, "%s: reload map", pp->dev); +- ev_add_path(pp, vecs, 1); +- pp->tick = 1; +- return 0; +- } ++ if (!disable_reinstate) ++ reinstate_path(pp, add_active); + new_path_up = 1; + + if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST) +@@ -2239,15 +2238,10 @@ check_path (struct vectors * vecs, struc + else if (newstate == PATH_UP || newstate == PATH_GHOST) { + if ((pp->dmstate == PSTATE_FAILED || + pp->dmstate == PSTATE_UNDEF) && +- !disable_reinstate) { ++ !disable_reinstate) + /* Clear IO errors */ +- if (reinstate_path(pp, 0)) { +- condlog(3, "%s: reload map", pp->dev); +- ev_add_path(pp, vecs, 1); +- pp->tick = 1; +- return 0; +- } +- } else { ++ reinstate_path(pp, 0); ++ else { + LOG_MSG(4, verbosity, pp); + if (pp->checkint != max_checkint) { + /* diff -Nru multipath-tools-0.8.3/debian/patches/lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch multipath-tools-0.8.3/debian/patches/lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch --- multipath-tools-0.8.3/debian/patches/lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.8.3/debian/patches/lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch 2023-11-07 21:19:21.000000000 +0000 @@ -0,0 +1,40 @@ +From e282f54a5d57ebd8750b5f0193eac0651a7ecc76 Mon Sep 17 00:00:00 2001 +From: lixiaokeng +Date: Tue, 23 Mar 2021 19:50:02 +0800 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2039719 +Origin: upstream, https://github.com/opensvc/multipath-tools/commit/e282f54 +Subject: [PATCH] multipathd fix NULL dereference in check_path + +When iscsi login/logout and multipath command are executed +concurrently, there is a coredump. + +The reason is: +check_path + ->update_multipath_strings + ->sync_paths + ->orphan_path //pp->mpp is set to NULL + ->update_multipath_status + ->dm_get_status //return DMP_NOT_FOUND + ->condlog //pp->mpp->alias, NULL dereference + +Here we don't dereference pp-> mpp if it is NULL. + +Signed-off-by: Lixiaokeng +Reviewed-by: Martin Wilck +--- + multipathd/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: multipath-tools-0.8.3/multipathd/main.c +=================================================================== +--- multipath-tools-0.8.3.orig/multipathd/main.c ++++ multipath-tools-0.8.3/multipathd/main.c +@@ -2122,7 +2122,7 @@ check_path (struct vectors * vecs, struc + if (ret == DMP_NOT_FOUND) { + /* multipath device missing. Likely removed */ + condlog(1, "%s: multipath device '%s' not found", +- pp->dev, pp->mpp->alias); ++ pp->dev, pp->mpp ? pp->mpp->alias : ""); + return 0; + } else + condlog(1, "%s: Couldn't synchronize with kernel state", diff -Nru multipath-tools-0.8.3/debian/patches/lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch multipath-tools-0.8.3/debian/patches/lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch --- multipath-tools-0.8.3/debian/patches/lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch 1970-01-01 00:00:00.000000000 +0000 +++ multipath-tools-0.8.3/debian/patches/lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch 2023-11-07 21:20:27.000000000 +0000 @@ -0,0 +1,55 @@ +From 7439a41fa12dd4da31348ce97e54495ae8167cd8 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Fri, 27 May 2022 10:27:37 +0800 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/2042366 +Origin: upstream, https://github.com/opensvc/multipath-tools/commit/7439a41 +Subject: [PATCH] dm_get_map: fix segfault when can't found target + +We got a segfault when we test multipath + iscsi. + +(gdb) bt + size=size@entry=0x55d4bc0270d8, outparams=outparams@entry=0x7f6941add640) at devmapper.c:688 + pathvec=pathvec@entry=0x55d4bc063990, flags=flags@entry=0) at structs_vec.c:426 + at structs_vec.c:526 + at main.c:2280 +(gdb) f 2 + size=size@entry=0x55d4bc0270d8, outparams=outparams@entry=0x7f6941add640) at devmapper.c:688 +688 *outparams = strdup(params); +(gdb) l +683 *size = length; +684 +685 if (!outparams) +686 r = DMP_OK; +687 else { +688 *outparams = strdup(params); +689 r = *outparams ? DMP_OK : DMP_ERR; +690 } +691 +692 out: +(gdb) p params +$1 = 0x0 + +If can't found target, we should goto out + +Signed-off-by: Wu Guanghao +Reviewed-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +--- + libmultipath/devmapper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: multipath-tools-0.8.3/libmultipath/devmapper.c +=================================================================== +--- multipath-tools-0.8.3.orig/libmultipath/devmapper.c ++++ multipath-tools-0.8.3/libmultipath/devmapper.c +@@ -544,8 +544,8 @@ int dm_get_map(const char *name, unsigne + r = DMP_NOT_FOUND; + /* Fetch 1st target */ + if (dm_get_next_target(dmt, NULL, &start, &length, +- &target_type, ¶ms) != NULL) +- /* more than one target */ ++ &target_type, ¶ms) != NULL || !params) ++ /* more than one target or not found target */ + goto out; + + if (size) diff -Nru multipath-tools-0.8.3/debian/patches/series multipath-tools-0.8.3/debian/patches/series --- multipath-tools-0.8.3/debian/patches/series 2023-07-24 23:06:36.000000000 +0000 +++ multipath-tools-0.8.3/debian/patches/series 2023-11-07 21:20:27.000000000 +0000 @@ -14,3 +14,7 @@ no-start-in-containers.patch CVE-2022-41973.patch CVE-2022-41974.patch +lp2039719-1-libmultipath-make-dm_get_map-status-return-codes-sym.patch +lp2039719-2-multipathd-fix-check_path-errors-with-removed-map.patch +lp2039719-3-multipathd-fix-NULL-dereference-in-check_path.patch +lp2042366-dm_get_map-fix-segfault-when-can-t-found-target.patch