This commit is contained in:
Alexis Métaireau 2024-12-18 16:12:41 +00:00 committed by GitHub
commit caf4ce938f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 77 additions and 6 deletions

View file

@ -42,6 +42,11 @@ def print_header(s: str) -> None:
type=click.UNPROCESSED, type=click.UNPROCESSED,
callback=args.validate_input_filenames, callback=args.validate_input_filenames,
) )
@click.option(
"--debug",
"debug",
flag_value=True,
help="Run Dangerzone in debug mode, to get logs from gVisor.")
@click.version_option(version=get_version(), message="%(version)s") @click.version_option(version=get_version(), message="%(version)s")
@errors.handle_document_errors @errors.handle_document_errors
def cli_main( def cli_main(
@ -50,6 +55,7 @@ def cli_main(
filenames: List[str], filenames: List[str],
archive: bool, archive: bool,
dummy_conversion: bool, dummy_conversion: bool,
debug: bool,
) -> None: ) -> None:
setup_logging() setup_logging()
@ -58,7 +64,7 @@ def cli_main(
elif is_qubes_native_conversion(): elif is_qubes_native_conversion():
dangerzone = DangerzoneCore(Qubes()) dangerzone = DangerzoneCore(Qubes())
else: else:
dangerzone = DangerzoneCore(Container()) dangerzone = DangerzoneCore(Container(debug=debug))
display_banner() display_banner()
if len(filenames) == 1 and output_filename: if len(filenames) == 1 and output_filename:

View file

@ -5,6 +5,8 @@ import platform
import signal import signal
import subprocess import subprocess
import sys import sys
import threading
from queue import Queue
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import IO, Callable, Iterator, Optional from typing import IO, Callable, Iterator, Optional
@ -86,11 +88,20 @@ class IsolationProvider(ABC):
Abstracts an isolation provider Abstracts an isolation provider
""" """
def __init__(self) -> None: def __init__(self, debug: bool = False) -> None:
if getattr(sys, "dangerzone_dev", False) is True: self.debug = debug
if self.should_capture_stderr():
self.proc_stderr = subprocess.PIPE self.proc_stderr = subprocess.PIPE
else: else:
self.proc_stderr = subprocess.DEVNULL self.proc_stderr = subprocess.DEVNULL
self.stderr_queue = Queue()
def should_capture_stderr(self) -> bool:
return self.debug or getattr(sys, "dangerzone_dev", False)
@staticmethod
def is_runtime_available() -> bool:
return True
@abstractmethod @abstractmethod
def install(self) -> bool: def install(self) -> bool:
@ -344,9 +355,9 @@ class IsolationProvider(ABC):
) )
# Read the stderr of the process only if: # Read the stderr of the process only if:
# * Dev mode is enabled. # * We're in debug mode
# * The process has exited (else we risk hanging). # * The process has exited (else we risk hanging).
if getattr(sys, "dangerzone_dev", False) and p.poll() is not None: if self.should_capture_stderr() and p.poll() is not None:
assert p.stderr assert p.stderr
debug_log = read_debug_text(p.stderr, MAX_CONVERSION_LOG_CHARS) debug_log = read_debug_text(p.stderr, MAX_CONVERSION_LOG_CHARS)
log.info( log.info(
@ -355,3 +366,23 @@ class IsolationProvider(ABC):
f"{debug_log}" # no need for an extra newline here f"{debug_log}" # no need for an extra newline here
f"{DOC_TO_PIXELS_LOG_END}" f"{DOC_TO_PIXELS_LOG_END}"
) )
def _stream_stderr(self, stderr, queue: Queue) -> None:
"""Read stderr in a separate thread to avoid blocking"""
try:
for line in stderr:
queue.put(line)
if self.debug:
log.debug(line.decode().strip())
except (ValueError, IOError) as e:
log.debug(f"Stderr stream closed: {e}")
def start_stderr_thread(self, process: subprocess.Popen) -> None:
"""Start a thread to read stderr from the process"""
if process.stderr:
stderr_thread = threading.Thread(
target=self._stream_stderr,
args=(process.stderr, self.stderr_queue),
daemon=True
)
stderr_thread.start()

View file

@ -168,6 +168,10 @@ class Container(IsolationProvider):
) -> subprocess.Popen: ) -> subprocess.Popen:
container_runtime = container_utils.get_runtime() container_runtime = container_utils.get_runtime()
security_args = self.get_runtime_security_args() security_args = self.get_runtime_security_args()
debug_args = []
if self.debug:
debug_args += ["-e", "RUNSC_DEBUG=1"]
enable_stdin = ["-i"] enable_stdin = ["-i"]
set_name = ["--name", name] set_name = ["--name", name]
prevent_leakage_args = ["--rm"] prevent_leakage_args = ["--rm"]
@ -177,6 +181,7 @@ class Container(IsolationProvider):
args = ( args = (
["run"] ["run"]
+ security_args + security_args
+ debug_args
+ prevent_leakage_args + prevent_leakage_args
+ enable_stdin + enable_stdin
+ set_name + set_name
@ -184,7 +189,22 @@ class Container(IsolationProvider):
+ command + command
) )
args = [container_runtime] + args args = [container_runtime] + args
return self.exec(args) args_str = " ".join(shlex.quote(s) for s in args)
log.info("> " + args_str)
process = subprocess.Popen(
args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, # Always pipe stderr
startupinfo=startupinfo,
start_new_session=True,
)
# Start stderr reader thread
self.start_stderr_thread(process)
return process
def kill_container(self, name: str) -> None: def kill_container(self, name: str) -> None:
"""Terminate a spawned container. """Terminate a spawned container.

View file

@ -66,11 +66,25 @@ class DangerzoneCore(object):
) -> None: ) -> None:
def convert_doc(document: Document) -> None: def convert_doc(document: Document) -> None:
try: try:
# Clear any existing stderr output
while not self.isolation_provider.stderr_queue.empty():
self.isolation_provider.stderr_queue.get_nowait()
self.isolation_provider.convert( self.isolation_provider.convert(
document, document,
ocr_lang, ocr_lang,
stdout_callback, stdout_callback,
) )
# Process any stderr output that was captured
while not self.isolation_provider.stderr_queue.empty():
try:
line = self.isolation_provider.stderr_queue.get_nowait()
if stdout_callback:
stdout_callback(True, line.decode().strip(), -1)
except Exception as e:
log.error(f"Error processing stderr: {e}")
except Exception: except Exception:
log.exception( log.exception(
f"Unexpected error occurred while converting '{document}'" f"Unexpected error occurred while converting '{document}'"