Skip to content

Commit

Permalink
libbtrfsutil: fix accidentally closing fd passed to subvolume iterator
Browse files Browse the repository at this point in the history
For an unprivileged subvolume iterator, append_to_search_stack() closes
cur_fd. On the first call to btrfs_util_subvolume_iterator_next(),
cur_fd is equal to the fd that was passed to
btrfs_util_create_subvolume_iterator_fd(). We're not supposed to close
that. We didn't notice it because it's more common to use it through
btrfs_util_create_subvolume_iterator(), which opens its own fd that
should be closed, and because the fd number is often reused internally
by the subvolume iterator.

pop_search_stack() already has a check to avoid closing the passed fd;
add the same check to append_to_search_stack(). Also add a regression
test.

Signed-off-by: Omar Sandoval <[email protected]>
Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
osandov authored and kdave committed Jun 25, 2024
1 parent d1f27c6 commit 16add32
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
18 changes: 18 additions & 0 deletions libbtrfsutil/python/tests/test_subvolume.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,3 +561,21 @@ def test_subvolume_iterator_race_unprivileged(self):
self._test_subvolume_iterator_race()
finally:
os.chdir(pwd)

def test_subvolume_iterator_fd_unprivileged(self):
pwd = os.getcwd()
try:
os.chdir(self.mountpoint)
btrfsutil.create_subvolume('subvol')
with drop_privs():
fd = os.open('.', os.O_RDONLY | os.O_DIRECTORY)
try:
with btrfsutil.SubvolumeIterator(fd) as it:
for _ in it:
break
finally:
# A bug in SubvolumeIterator previously made it close the
# passed in fd, so this would fail with EBADF.
os.close(fd)
finally:
os.chdir(pwd)
3 changes: 2 additions & 1 deletion libbtrfsutil/subvolume.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,8 @@ static enum btrfs_util_error append_to_search_stack(struct btrfs_util_subvolume_
return err;
}

close(iter->cur_fd);
if (iter->cur_fd != iter->fd)
close(iter->cur_fd);
iter->cur_fd = fd;
}
}
Expand Down

0 comments on commit 16add32

Please sign in to comment.