From c9a29dea3f53b546d1f83865b7e178b95e321f5d Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Fri, 1 Apr 2022 15:21:13 -0400 Subject: [PATCH] Open block devices in qubesd This makes race conditions (e.g. against udev) more obviously impossible. It also allows perfoming verification steps on the block device if that becomes necessary in the future. --- qubes/backup.py | 52 ++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/qubes/backup.py b/qubes/backup.py index ed40d9792..57a015226 100644 --- a/qubes/backup.py +++ b/qubes/backup.py @@ -638,28 +638,36 @@ async def _wrap_and_send_files(self, files_to_backup, output_queue): os.path.basename(path) ]) file_stat = os.stat(path) - if stat.S_ISBLK(file_stat.st_mode) or \ - file_info.name != os.path.basename(path): - # tar doesn't handle content of block device, use our - # writer - # also use our tar writer when renaming file - assert not stat.S_ISDIR(file_stat.st_mode), \ - "Renaming directories not supported" - tar_cmdline = ['python3', '-m', 'qubes.tarwriter', - '--override-name=%s' % ( - os.path.join(file_info.subdir, os.path.basename( - file_info.name))), - path] - if self.compressed: - tar_cmdline.insert(-2, - "--use-compress-program=%s" % self.compression_filter) - - self.log.debug(" ".join(tar_cmdline)) - - # Pipe: tar-sparse | scrypt | tar | backup_target - # TODO: log handle stderr - tar_sparse = await asyncio.create_subprocess_exec( - *tar_cmdline, stdout=subprocess.PIPE) + fd_to_close = None + subprocess_kwargs = {'stdout': subprocess.PIPE} + try: + if stat.S_ISBLK(file_stat.st_mode) or \ + file_info.name != os.path.basename(path): + # tar doesn't handle content of block device, use our + # writer + # also use our tar writer when renaming file + assert not stat.S_ISDIR(file_stat.st_mode), \ + "Renaming directories not supported" + # pylint: disable=line-too-long + fd_to_close = os.open(path, os.O_RDONLY | os.O_NOCTTY | os.O_CLOEXEC) + subprocess_kwargs['stdin'] = fd_to_close + tar_cmdline = ['python3', '-m', 'qubes.tarwriter', + '--override-name=%s' % ( + os.path.join(file_info.subdir, os.path.basename( + file_info.name))), + '/proc/self/fd/0'] + if self.compressed: + tar_cmdline.insert(-2, + "--use-compress-program=" + self.compression_filter) + + # Pipe: tar-sparse | scrypt | tar | backup_target + # TODO: log handle stderr + tar_sparse = await asyncio.create_subprocess_exec( + *tar_cmdline, **subprocess_kwargs) + finally: + if fd_to_close is not None: + os.close(fd_to_close) + del fd_to_close, subprocess_kwargs try: await self._split_and_send(