host: check reply_fds before sending them

If there are fds to send back to the client, do a check that none
of them are invalid, so that we do not raise an exception in send
later. This allows us to send a proper RemoteError instead of no
reply at all.
This commit is contained in:
Christian Kellner 2021-09-24 11:17:45 +02:00 committed by Tom Gundersen
parent 6a39067772
commit 28dcd0ee9a

View file

@ -38,6 +38,7 @@ their clean up, independent of any control of osbuild.
import abc import abc
import argparse import argparse
import asyncio import asyncio
import fcntl
import importlib import importlib
import io import io
import os import os
@ -252,11 +253,17 @@ class Service(abc.ABC):
if not msg: if not msg:
break break
reply_fds = None
try: try:
reply, reply_fds = self._handle_message(msg, fds) reply, reply_fds = self._handle_message(msg, fds)
# Catch invalid file descriptors early so that
# we send an error reply instead of throwing
# an exception in `sock.send` later.
self._check_fds(reply_fds)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
reply_fds = None reply_fds = self._close_all(reply_fds)
_, val, tb = sys.exc_info() _, val, tb = sys.exc_info()
reply = self.protocol.encode_exception(val, tb) reply = self.protocol.encode_exception(val, tb)
@ -289,13 +296,22 @@ class Service(abc.ABC):
@staticmethod @staticmethod
def _close_all(fds: Optional[List[int]]): def _close_all(fds: Optional[List[int]]):
if not fds: if not fds:
return return []
for fd in fds: for fd in fds:
try: try:
os.close(fd) os.close(fd)
except OSError as e: except OSError as e:
print(f"error closing fd '{fd}': {e!s}") print(f"error closing fd '{fd}': {e!s}")
return []
@staticmethod
def _check_fds(fds: Optional[List[int]]):
if not fds:
return
for fd in fds:
fcntl.fcntl(fd, fcntl.F_GETFD)
class ServiceClient: class ServiceClient: