daemon: btrfs: Simplify snapshot code and fix invalid memory access

The existing code had a bug which you can demonstrate by doing:

  $ guestfish -N fs:btrfs:10G -m /dev/sda1 \
  btrfs-subvolume-create /sub :
  btrfs-subvolume-snapshot /sub /snap1 : \
  btrfs-subvolume-snapshot /sub /snap123 : \
  btrfs-subvolume-snapshot /sub /snap123456 : \
  btrfs-subvolume-show /sub
  ...
  libguestfs: error: appliance closed the connection unexpectedly.
  This usually means the libguestfs appliance crashed.

As the code for parsing the output and creating the comma-separated
list of snapshots was unncessarily complicated in the first place,
simplify it.  This also fixes the bug.

This also adds a regression test.

Thanks: Arye Yurkovsky
Link: https://lists.libguestfs.org/archives/list/guestfs@lists.libguestfs.org/thread/QV5VDHIH7WRUNAE54K6OEOKJMWL6M7EM/
This commit is contained in:
Richard W.M. Jones
2025-11-21 17:19:29 +00:00
committed by rwmjones
parent 6c8e3992fc
commit 56da6b36d3
3 changed files with 82 additions and 22 deletions

View File

@@ -957,8 +957,8 @@ do_btrfs_subvolume_show (const char *subvolume)
while (key) {
/* snapshot is special, see the output above */
if (STREQLEN (key, "Snapshot(s)", sizeof ("Snapshot(s)") - 1)) {
char *ss = NULL;
int ss_len = 0;
CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (snapshots);
char *ss;
if (add_string (&ret, key) == -1)
return NULL;
@@ -966,27 +966,18 @@ do_btrfs_subvolume_show (const char *subvolume)
p = analyze_line (p, &key, &value, ':');
while (key && !value) {
ss = realloc (ss, ss_len + strlen (key) + 1);
if (!ss)
return NULL;
if (ss_len != 0)
ss[ss_len++] = ',';
memcpy (ss + ss_len, key, strlen (key));
ss_len += strlen (key);
ss[ss_len] = '\0';
if (add_string (&snapshots, key) == -1)
return NULL;
p = analyze_line (p, &key, &value, ':');
}
if (ss) {
if (add_string_nodup (&ret, ss) == -1)
return NULL;
} else {
if (add_string (&ret, "") == -1)
return NULL;
}
if (end_stringsbuf (&snapshots) == -1)
return NULL;
/* Turn the snapshots into a comma-separated list. */
ss = guestfs_int_join_strings (",", snapshots.argv);
if (add_string_nodup (&ret, ss) == -1)
return NULL;
} else {
if (add_string (&ret, key) == -1)
return NULL;