Skip to content

Commit 856d185

Browse files
ahrenstonyhutter
authored andcommitted
Fix use-after-free of vd_path in spa_vdev_remove()
After spa_vdev_remove_aux() is called, the config nvlist is no longer valid, as it's been replaced by the new one (with the specified device removed). Therefore any pointers into the nvlist are no longer valid. So we can't save the result of `fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH)` (in vd_path) across the call to spa_vdev_remove_aux(). Instead, use spa_strdup() to save a copy of the string before calling spa_vdev_remove_aux. Found by AddressSanitizer: ERROR: AddressSanitizer: heap-use-after-free on address ... READ of size 34 at 0x608000a1fcd0 thread T686 #0 0x7fe88b0c166d (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5166d) #1 0x7fe88a5acd6e in spa_strdup spa_misc.c:1447 #2 0x7fe88a688034 in spa_vdev_remove vdev_removal.c:2259 #3 0x55ffbc7748f8 in ztest_vdev_aux_add_remove ztest.c:3229 #4 0x55ffbc769fba in ztest_execute ztest.c:6714 #5 0x55ffbc779a90 in ztest_thread ztest.c:6761 #6 0x7fe889cbc6da in start_thread #7 0x7fe8899e588e in __clone 0x608000a1fcd0 is located 48 bytes inside of 88-byte region freed by thread T686 here: #0 0x7fe88b14e7b8 in __interceptor_free #1 0x7fe88ae541c5 in nvlist_free nvpair.c:874 #2 0x7fe88ae543ba in nvpair_free nvpair.c:844 #3 0x7fe88ae57400 in nvlist_remove_nvpair nvpair.c:978 #4 0x7fe88a683c81 in spa_vdev_remove_aux vdev_removal.c:185 #5 0x7fe88a68857c in spa_vdev_remove vdev_removal.c:2221 #6 0x55ffbc7748f8 in ztest_vdev_aux_add_remove ztest.c:3229 #7 0x55ffbc769fba in ztest_execute ztest.c:6714 #8 0x55ffbc779a90 in ztest_thread ztest.c:6761 #9 0x7fe889cbc6da in start_thread Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Ryan Moeller <[email protected]> Signed-off-by: Matthew Ahrens <[email protected]> Closes openzfs#9706
1 parent 4d658bd commit 856d185

File tree

1 file changed

+11
-11
lines changed

1 file changed

+11
-11
lines changed

module/zfs/vdev_removal.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,7 +2136,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
21362136
int error = 0, error_log;
21372137
boolean_t locked = MUTEX_HELD(&spa_namespace_lock);
21382138
sysevent_t *ev = NULL;
2139-
char *vd_type = NULL, *vd_path = NULL, *vd_path_log = NULL;
2139+
char *vd_type = NULL, *vd_path = NULL;
21402140

21412141
ASSERT(spa_writeable(spa));
21422142

@@ -2171,7 +2171,8 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
21712171
ESC_ZFS_VDEV_REMOVE_AUX);
21722172

21732173
vd_type = VDEV_TYPE_SPARE;
2174-
vd_path = fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH);
2174+
vd_path = spa_strdup(fnvlist_lookup_string(
2175+
nv, ZPOOL_CONFIG_PATH));
21752176
spa_vdev_remove_aux(spa->spa_spares.sav_config,
21762177
ZPOOL_CONFIG_SPARES, spares, nspares, nv);
21772178
spa_load_spares(spa);
@@ -2184,7 +2185,8 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
21842185
ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0 &&
21852186
(nv = spa_nvlist_lookup_by_guid(l2cache, nl2cache, guid)) != NULL) {
21862187
vd_type = VDEV_TYPE_L2CACHE;
2187-
vd_path = fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH);
2188+
vd_path = spa_strdup(fnvlist_lookup_string(
2189+
nv, ZPOOL_CONFIG_PATH));
21882190
/*
21892191
* Cache devices can always be removed.
21902192
*/
@@ -2197,7 +2199,8 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
21972199
} else if (vd != NULL && vd->vdev_islog) {
21982200
ASSERT(!locked);
21992201
vd_type = VDEV_TYPE_LOG;
2200-
vd_path = (vd->vdev_path != NULL) ? vd->vdev_path : "-";
2202+
vd_path = spa_strdup((vd->vdev_path != NULL) ?
2203+
vd->vdev_path : "-");
22012204
error = spa_vdev_remove_log(vd, &txg);
22022205
} else if (vd != NULL) {
22032206
ASSERT(!locked);
@@ -2209,9 +2212,6 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
22092212
error = SET_ERROR(ENOENT);
22102213
}
22112214

2212-
if (vd_path != NULL)
2213-
vd_path_log = spa_strdup(vd_path);
2214-
22152215
error_log = error;
22162216

22172217
if (!locked)
@@ -2224,12 +2224,12 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
22242224
* Doing that would prevent the txg sync from actually happening,
22252225
* causing a deadlock.
22262226
*/
2227-
if (error_log == 0 && vd_type != NULL && vd_path_log != NULL) {
2227+
if (error_log == 0 && vd_type != NULL && vd_path != NULL) {
22282228
spa_history_log_internal(spa, "vdev remove", NULL,
2229-
"%s vdev (%s) %s", spa_name(spa), vd_type, vd_path_log);
2229+
"%s vdev (%s) %s", spa_name(spa), vd_type, vd_path);
22302230
}
2231-
if (vd_path_log != NULL)
2232-
spa_strfree(vd_path_log);
2231+
if (vd_path != NULL)
2232+
spa_strfree(vd_path);
22332233

22342234
if (ev != NULL)
22352235
spa_event_post(ev);

0 commit comments

Comments
 (0)