It can happen that a path group contains references to paths that are
already freed. If we access pp->pgindex in such a case, a use-after-free
occurs. In particular, this occurs if we call remove_map() from configure()
-> coalesce_paths(), and some paths are freed in orphan_paths() because
they are in INIT_PARTIAL or INIT_REMOVED state. The paths of the removed
map may still be referenced by maps in the "old" mpvec in configure(). The
UAF occurs when configure() calls remove_maps(vecs).
This code has been introduced in cd912cf ("libmultipath: fix handling of
pp->pgindex"). The commit message stated: "The hunk in group_paths is
mostly redundant with the hunk in free_pgvec(), but because we're looping
over pg->paths in the former and over pg->pgp in the latter, I think it's
better too play safe". It turns out that it would have been better not
to "play safe" here. No caller of free_pgvec() requires the pgindex to
be reset. For the functions in pgpolicies.c, the reset of pgindex is
redundant, as remarked in cd912cf. disassemble_map() will set the pgindex
later anyway, and update_multipath_strings() will call disassemble_map().
The other callers remove the struct multipath, in which case the paths
will eventually be orphaned or freed (except for the special case of
coalesce_paths() mentioned above).
Fixes: cd912cf ("libmultipath: fix handling of pp->pgindex")
Signed-off-by: Martin Wilck <[email protected]>
Reviewed-by: Benjamin Marzinski <[email protected]>
---
libmultipath/structs.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 1cbbea8..cde5991 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -239,18 +239,8 @@ free_pgvec (vector pgvec, enum free_path_mode free_paths)
if (!pgvec)
return;
- vector_foreach_slot(pgvec, pgp, i) {
-
- /* paths are going to be re-grouped, reset pgindex */
- if (free_paths != FREE_PATHS) {
- struct path *pp;
- int j;
-
- vector_foreach_slot(pgp->paths, pp, j)
- pp->pgindex = 0;
- }
+ vector_foreach_slot (pgvec, pgp, i)
free_pathgroup(pgp, free_paths);
- }
vector_free(pgvec);
}
--
2.52.0