Skip to content

Commit

Permalink
Qubes: add test if MAX_PAGES is enforced in client
Browse files Browse the repository at this point in the history
Because the server also checks the MAX_PAGES limit, the test in base
would hide the fact that the client is not enforcing the limit. This
ensures that's not the case.

When the pages in containers are streamed (#443), then this test should
be in base.py.
  • Loading branch information
deeplow committed Sep 21, 2023
1 parent 5cc9f17 commit d9ffbf0
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
19 changes: 19 additions & 0 deletions dangerzone/conversion/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# XXX: errors start at 128 for conversion-related issues
ERROR_SHIFT = 128
MAX_PAGES = 10000
MAX_PAGE_WIDTH = 10000
MAX_PAGE_HEIGHT = 10000


class ConversionException(Exception):
Expand Down Expand Up @@ -62,6 +64,16 @@ class MaxPagesException(PagesException):
error_message = f"Number of pages exceeds maximum ({MAX_PAGES})"


class MaxPageWidthException(PagesException):
error_code = 44
error_message = f"A page exceeded the maximum width."


class MaxPageHeightException(PagesException):
error_code = 45
error_message = f"A page exceeded the maximum height."


class PDFtoPPMException(ConversionException):
error_code = ERROR_SHIFT + 50
error_message = "Error converting PDF to Pixels (pdftoppm)"
Expand All @@ -77,6 +89,13 @@ class PDFtoPPMInvalidDepth(PDFtoPPMException):
error_message = "Error converting PDF to Pixels (Invalid PPM depth)"


class InterruptedConversion(ConversionException):
error_code = ERROR_SHIFT + 60
error_message = (
"Something interrupted the conversion and it could not be completed."
)


class UnexpectedConversionError(PDFtoPPMException):
error_code = ERROR_SHIFT + 100
error_message = "Some unexpected error occurred while converting the document"
Expand Down
14 changes: 10 additions & 4 deletions dangerzone/isolation_provider/qubes.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,21 @@ def _convert(
sw = Stopwatch(timeout)
sw.start()
for page in range(1, n_pages + 1):
# TODO handle too width > MAX_PAGE_WIDTH
# TODO handle too big height > MAX_PAGE_HEIGHT
width = read_int(p.stdout, timeout=sw.remaining)
height = read_int(p.stdout, timeout=sw.remaining)
if not (1 <= width <= errors.MAX_PAGE_WIDTH):
raise errors.MaxPageWidthException()
if not (1 <= height <= errors.MAX_PAGE_HEIGHT):
raise errors.MaxPageHeightException()

num_pixels = width * height * 3 # three color channels
untrusted_pixels = read_bytes(
p.stdout,
width * height * 3,
num_pixels,
timeout=sw.remaining,
) # three color channels
)
if len(untrusted_pixels) != num_pixels:
raise errors.InterruptedConversion()

# Wrapper code
with open(f"/tmp/dangerzone/page-{page}.width", "w") as f_width:
Expand Down
10 changes: 10 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ def sample_doc() -> str:
return str(test_docs_dir.joinpath(BASIC_SAMPLE_DOC))


@pytest.fixture
def sample_bad_height() -> str:
return str(test_docs_dir.joinpath("sample_bad_max_height.pdf"))


@pytest.fixture
def sample_bad_width() -> str:
return str(test_docs_dir.joinpath("sample_bad_max_width.pdf"))


def get_docs_external(pattern: str = "*") -> List[Path]:
if not pattern.endswith("*"):
pattern = f"{pattern}.b64"
Expand Down
46 changes: 43 additions & 3 deletions tests/isolation_provider/test_qubes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import pytest
from pytest_mock import MockerFixture

from dangerzone.isolation_provider.qubes import Qubes
from dangerzone.conversion import errors
from dangerzone.document import Document
from dangerzone.isolation_provider.base import IsolationProvider
from dangerzone.isolation_provider.qubes import Qubes, running_on_qubes

# XXX Fixtures used in abstract Test class need to be imported regardless
from .. import pdf_11k_pages, sanitized_text, uncommon_text
from .. import (
pdf_11k_pages,
sample_bad_height,
sample_bad_width,
sample_doc,
sanitized_text,
uncommon_text,
)
from .base import TestIsolationProvider


Expand All @@ -12,5 +23,34 @@ def provider() -> Qubes:
return Qubes()


@pytest.mark.skipif(not running_on_qubes(), reason="Not on a Qubes system")
class TestQubes(TestIsolationProvider):
pass
def test_max_pages_client_side_enforcement(
self,
sample_doc: str,
provider: Qubes,
mocker: MockerFixture,
):
provider.progress_callback = mocker.MagicMock()
mocker.patch(
"dangerzone.conversion.errors.MAX_PAGES", 1
) # sample_doc has 4 pages > 1
doc = Document(sample_doc)
with pytest.raises(errors.MaxPagesException):
success = provider._convert(doc, ocr_lang=None)
assert not success

def test_max_dimentions(
self,
sample_bad_width: str,
sample_bad_height: str,
provider: Qubes,
mocker: MockerFixture,
):
provider.progress_callback = mocker.MagicMock()
with pytest.raises(errors.MaxPageWidthException):
success = provider._convert(Document(sample_bad_width), ocr_lang=None)
assert not success
with pytest.raises(errors.MaxPageHeightException):
success = provider._convert(Document(sample_bad_height), ocr_lang=None)
assert not success

0 comments on commit d9ffbf0

Please sign in to comment.