Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paths added by disassemble_map() may be leaked when the multipath device is freed #2

Open
bmarzins opened this issue Apr 28, 2020 · 0 comments

Comments

@bmarzins
Copy link
Owner

If multipathd discovers a path in disassemble_maps() that it isn't already tracking (this can happen if the config has been changed to allow the path, but multipathd has not been reloaded since the change), it will add it to the multipath device, but not to the pathvec:

if (!pp) {
pp = alloc_path();
if (!pp)
goto out1;
strlcpy(pp->dev_t, word, BLK_DEV_SIZE);
strlcpy(pp->dev, devname, FILE_NAME_SIZE);
if (strlen(mpp->wwid)) {
strlcpy(pp->wwid, mpp->wwid,
WWID_SIZE);
}
/* Only call this in multipath client mode */
if (!is_daemon && store_path(pathvec, pp))
goto out1;
} else {
if (!strlen(pp->wwid) &&
strlen(mpp->wwid))
strlcpy(pp->wwid, mpp->wwid,
WWID_SIZE);
}
FREE(word);
if (store_path(pgp->paths, pp))
goto out;

When the multiapth device is later freed, if free_multipath is called with KEEP_PATHS, the paths will
not get freed, leaking memory.

void
free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
{
if (!mpp)
return;
free_multipath_attributes(mpp);
if (mpp->alias) {
FREE(mpp->alias);
mpp->alias = NULL;
}
if (mpp->dmi) {
FREE(mpp->dmi);
mpp->dmi = NULL;
}
free_pathvec(mpp->paths, free_paths);
free_pgvec(mpp->pg, free_paths);
FREE_PTR(mpp->mpcontext);
FREE(mpp);
}

bmarzins pushed a commit that referenced this issue Feb 9, 2021
Integrate basic Github CI
bmarzins pushed a commit that referenced this issue Dec 13, 2021
... by the paths and pg vectors of the map to be removed.

Original bug report from Lixiaokeng ("libmultipath: clear removed path from mpp"):

multipathd[3525635]: ==3525635==ERROR: AddressSanitizer: heap-use-after-free on address 0xffffa4902fc0 at pc 0xffffac7d5b88 bp 0xffffa948dac0 sp 0xffffa948dae0
multipathd[3525635]: READ of size 8 at 0xffffa4902fc0 thread T7
multipathd[3525635]:    #0 0xffffac7d5b87 in free_multipath (/usr/lib64/libmultipath.so.0+0x4bb87)
multipathd[3525635]:    #1 0xaaaad6cf7057  (/usr/sbin/multipathd+0x17057)
multipathd[3525635]:    #2 0xaaaad6cf78eb  (/usr/sbin/multipathd+0x178eb)
multipathd[3525635]:    #3 0xaaaad6cff4df  (/usr/sbin/multipathd+0x1f4df)
multipathd[3525635]:    #4 0xaaaad6cfffe7  (/usr/sbin/multipathd+0x1ffe7)
multipathd[3525635]:    #5 0xffffac807be3 in uevent_dispatch (/usr/lib64/libmultipath.so.0+0x7dbe3)
multipathd[3525635]:    #6 0xaaaad6cf563f  (/usr/sbin/multipathd+0x1563f)
multipathd[3525635]:    #7 0xffffac6877af  (/usr/lib64/libpthread.so.0+0x87af)
multipathd[3525635]:    #8 0xffffac44118b  (/usr/lib64/libc.so.6+0xd518b)
multipathd[3525635]: 0xffffa4902fc0 is located 1344 bytes inside of 1440-byte region [0xffffa4902a80,0xffffa4903020)
multipathd[3525635]: freed by thread T7 here:
multipathd[3525635]:    #0 0xffffac97d703 in free (/usr/lib64/libasan.so.4+0xd0703)
multipathd[3525635]:    #1 0xffffac824827 in orphan_paths (/usr/lib64/libmultipath.so.0+0x9a827)
multipathd[3525635]:    #2 0xffffac824a43 in remove_map (/usr/lib64/libmultipath.so.0+0x9aa43)
multipathd[3525635]:    #3 0xaaaad6cf7057  (/usr/sbin/multipathd+0x17057)
multipathd[3525635]:    #4 0xaaaad6cf78eb  (/usr/sbin/multipathd+0x178eb)
multipathd[3525635]:    #5 0xaaaad6cff4df  (/usr/sbin/multipathd+0x1f4df)
multipathd[3525635]:    #6 0xaaaad6cfffe7  (/usr/sbin/multipathd+0x1ffe7)
multipathd[3525635]:    #7 0xffffac807be3 in uevent_dispatch (/usr/lib64/libmultipath.so.0+0x7dbe3)
multipathd[3525635]:    #8 0xaaaad6cf563f  (/usr/sbin/multipathd+0x1563f)
multipathd[3525635]:    #9 0xffffac6877af  (/usr/lib64/libpthread.so.0+0x87af)
multipathd[3525635]:    #10 0xffffac44118b  (/usr/lib64/libc.so.6+0xd518b)

When mpp only has one path and log out the path, there is an asan error.
In remove_mpp, the pp is freed firstly in orphan_path but is accessed,
changed in free_multipath later. Before free_path(pp), the pp should be
cleared from pp->mpp.

Reported-by: Lixiaokeng <lixiaokeng@huawei.com>
Tested-by: Lixiaokeng <lixiaokeng@huawei.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant