That's qemu_rbd_unescape()'s job! No need to duplicate the labor. Furthermore, this was causing some confusion in the parsing logic to where the caller might test for the presence of a character to split on like so:
if (strchr(image_name, '/')) { found_str = qemu_rbd_next_tok(image_name, '/', &image_name); [..] When qemu_rbd_next_tok() performs unescaping as a side effect, the parser can get confused thinking that it can split this string, but really the delimiter '/' gets unescaped and so qemu_rbd_next_tok() never "finds" the delimiter and consumes the rest of the token input stream. This is problematic because qemu_rbd_next_tok() also steals the input pointer to the token stream and sets it to NULL. This causes a segfault where the parser expects to split one string into two. In this case, the parser is determining if a string is a namespace/image_name pair like so: "foo/bar" And clearly it's looking to split it like so: namespace: foo image_name: bar but if the input is "foo\/bar", it *should* split into namespace: foo\ image_name: bar and its subordinate parts can be unescaped after tokenization. So, instead of tokenizing *and* escaping all at once, do one before the other to avoid stumbling into a segfault by confusing the parsing logic. Reported-by: Han Han <h...@redhat.com> Fixes: https://bugzilla.redhat.com/1873913 Signed-off-by: Connor Kuehl <cku...@redhat.com> --- block/rbd.c | 3 --- tests/qemu-iotests/231 | 4 ++++ tests/qemu-iotests/231.out | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/block/rbd.c b/block/rbd.c index 9071a00e3f..9bed0863e5 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -123,9 +123,6 @@ static char *qemu_rbd_next_tok(char *src, char delim, char **p) if (*end == delim) { break; } - if (*end == '\\' && end[1] != '\0') { - end++; - } } if (*end == delim) { *p = end + 1; diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 index 0f66d0ca36..8e6c6447c1 100755 --- a/tests/qemu-iotests/231 +++ b/tests/qemu-iotests/231 @@ -55,6 +55,10 @@ _filter_conf() $QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf $QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf +# Regression test: the qemu-img invocation is expected to fail, but it should +# not seg fault the parser. +$QEMU_IMG create "rbd:rbd/aa\/bb:conf=${BOGUS_CONF}" 1M 2>&1 | _filter_conf + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out index 747dd221bb..a785a6e859 100644 --- a/tests/qemu-iotests/231.out +++ b/tests/qemu-iotests/231.out @@ -4,4 +4,7 @@ unable to get monitor info from DNS SRV with service name: ceph-mon qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory unable to get monitor info from DNS SRV with service name: ceph-mon qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory +Formatting 'rbd:rbd/aa\/bb:conf=BOGUS_CONF', fmt=raw size=1048576 +unable to get monitor info from DNS SRV with service name: ceph-mon +qemu-img: rbd:rbd/aa\/bb:conf=BOGUS_CONF: error connecting: No such file or directory *** done -- 2.30.2