Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect if we received EOF due to a command that failed #551

Merged
merged 3 commits into from
Sep 26, 2023

Conversation

apyrgio
Copy link
Contributor

@apyrgio apyrgio commented Sep 25, 2023

Handle incomplete reads due to EOF by checking if the underlying command has exited. If so, raise the corresponding exception.

Refs #430

@deeplow deeplow mentioned this pull request Sep 25, 2023
@apyrgio apyrgio changed the title WIP: Detect if we received EOF due to a command that failed Detect if we received EOF due to a command that failed Sep 25, 2023
@apyrgio apyrgio marked this pull request as ready for review September 25, 2023 17:47
@apyrgio apyrgio force-pushed the 2023-09-check-exit-codes branch 2 times, most recently from 72a88ac to eeb3760 Compare September 25, 2023 17:48
@apyrgio
Copy link
Contributor Author

apyrgio commented Sep 25, 2023

@deeplow I checked this PR against your PR for error handling, and it seems to work ok, so I promoted it as ready for review. Feel free to give it a look.

Copy link
Contributor

@deeplow deeplow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only added a note on the fact that we have now two args and one (p.stdout) can be accessed from the other (p).

Other than that it looks good. The only extra thing is that this essentially removes the need for the InterruptedConversion exception from #546 as this will catch the exit code before it detects that it received less data than it expected. But I think that's OK.

dangerzone/isolation_provider/qubes.py Outdated Show resolved Hide resolved
@deeplow
Copy link
Contributor

deeplow commented Sep 26, 2023

This also has issues with the test_out_of_ram but I already have a fix for that which we can add to #430 once it gets rebased on top of this.

It basically becomes a race condition when the test manages to pipe the input file into the process before it exits 126. So we need to add some delay so that it closes before then:

diff --git a/tests/isolation_provider/test_qubes.py b/tests/isolation_provider/test_qubes.py
index 70d57463..b3f1ddad 100644
--- a/tests/isolation_provider/test_qubes.py
+++ b/tests/isolation_provider/test_qubes.py
@@ -79,6 +79,7 @@ class TestQubes(TestIsolationProvider):
                 stderr=subprocess.PIPE,
                 shell=True,
             )
+            time.sleep(0.2)
             return p
 

Otherwise it will fail when trying to read stdout, which is different than when a real qrexec call would fail.

@apyrgio
Copy link
Contributor Author

apyrgio commented Sep 26, 2023

Regarding your p and p.stdout concerns, you are correct. I don't like it as well. I have a radically different plan in mind, which I wanted to trigger only if you felt the same as well. I'll send a fix soon.

Regarding the test_out_of_ram issue, you're correct again. I think I've seen it fail some times, but other times it passed. I didn't know what was the reason for this, I thought I had changed something. Your explanation makes more sense, although I'm a bit hesitant about fixing races with time.sleep(). We'll see more in the #430 PR.

@apyrgio
Copy link
Contributor Author

apyrgio commented Sep 26, 2023

I have reworked the PR to catch errors caused by EOF in a separate place. I think this should address your concerns about our helpers and the InterruptedConversion exception. Tell me if you're ok with it.

Copy link
Contributor

@deeplow deeplow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah, we're now two levels deep into the __convert. I guess we're just going to have to live with it until we handle #443. That issue being delayed in particular is creating a lot of technical.

So I'll just approve this but when we tackle #443 we'll have lots of stuff to address.

Store, in an instance attribute, the process that we have started for
the spawned disposable qube. In subsequent commits, we will use it from
other places as well, aside from the `_convert` method.

Note that this commit does not alter the conversion logic, and only does
the following:
1. Renames `p.` to `self.proc.`
2. Adds an `__init__` method to the Qubes isolation provider, and
   initializes the `self.proc` attribute to `None`.
3. Adds an assert that `self.proc` is not `None` after it's spawned, to
   placate Mypy.
Add an error for interrupted conversions, in order to better
differentiate this scenario from other ValueErrors that may be raised
throughout the code's lifetime.
If a conversion has been interrupted (usually due to an EOF), figure out
why this happened by checking the exit code of the spawned process.
@apyrgio apyrgio merged commit 18b73d9 into main Sep 26, 2023
10 of 12 checks passed
@@ -41,7 +41,7 @@ def read_bytes(f: IO[bytes], size: int, timeout: float, exact: bool = True) -> b
"""Read bytes from a file-like object."""
buf = nonblocking_read(f, size, timeout)
if exact and len(buf) != size:
raise ValueError("Did not receive exact number of bytes")
raise errors.InterruptedConversion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this here, but I'll catch it in #546.

Suggested change
raise errors.InterruptedConversion
raise errors.InterruptedConversion()

@apyrgio apyrgio deleted the 2023-09-check-exit-codes branch October 2, 2023 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants