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

pkg/detach: fix broken Copy() detach sequence #2302

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Luap99
Copy link
Member

@Luap99 Luap99 commented Jan 23, 2025

The code only could handle the detach sequence when it read one byte at a time. This obviously is not correct and lead to some issues for my automated test in my podman PR[1] where I added some automated tests for detaching and the read part is really undefined and depends on the input side/kernel scheduling on how much we read at once.

This is large rework to make the code check for the key sequence across the entire buffer. That is of course more work but it needs to happen for this to work correctly.

I guess the only reason why this was never noticed is because normally user detach manually by typing and not in an automated way which is much slower and thus likely reads the bytes one by one.

I added new test to actually confirm the behavior. And to ensure this works with various read sizes I made it a fuzz test. I had this running for a while and did not spot any issues there. The old code fails already on the simple test cases.

[1] containers/podman#25083

Copy link
Contributor

openshift-ci bot commented Jan 23, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Luap99

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@@ -11,47 +12,73 @@ var ErrDetach = errors.New("detached from container")

// Copy is similar to io.Copy but support a detach key sequence to break out.
func Copy(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
// if no key sequence we can use the fast std lib implementation
if len(keys) == 0 {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we shouldn't mention this in containers.conf - disabling the detach keys (almost never used) improving performance by a pretty significant bit could be relevant to folks.

Copy link
Member Author

Choose a reason for hiding this comment

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

I would not make any claims without solid numbers. I have not measured this, the main reason I added this was to not have to deal with the case len(keys) == 0. The io.Copy() code has some interface logic to use better methods when available and logically then don't have to compare each byte * number of keys so yes one should assume it is much faster. However is it faster in the context of podman users. Maybe other overhead makes this pretty much not noticeable.

return 0, ErrDetach

// previous key buffer
if len(tmpKeyBuf) > 0 {
Copy link
Member

Choose a reason for hiding this comment

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

Would it be faster to just do a linear search of buf instead of copying into a separate, smaller buffer?

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean like store the index of where we are in the middle of the sequence before the next read is done? That sound like good plan. I was to much into we must keep writing the "buffered" sequence when a later key does not match but in that case we can get the correct bytes just out of the input keys slice instead instead of the tmpKeyBuf.

Copy link
Member

Choose a reason for hiding this comment

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

If you start searching from (index in buffer) - (length of detach sequence) + 1, you should be able to catch the full sequence even if only one character of the sequence was in the most recent block.

The code only could handle the detach sequence when it read one byte at
a time. This obviously is not correct and lead to some issues for my
automated test in my podman PR[1] where I added some automated tests
for detaching and the read part is really undefined and depends on the
input side/kernel scheduling on how much we read at once.

This is large rework to make the code check for the key sequence across
the entire buffer. That is of course more work but it needs to happen
for this to work correctly.

I guess the only reason why this was never noticed is because normally
user detach manually by typing and not in an automated way which is much
slower and thus likely reads the bytes one by one.

I added new test to actually confirm the behavior. And to ensure this
works with various read sizes I made it a fuzz test. I had this running
for a while and did not spot any issues there. The old code fails
already on the simple test cases.

[1] containers/podman#25083

Signed-off-by: Paul Holzinger <[email protected]>
Luap99 added a commit to Luap99/libpod that referenced this pull request Jan 31, 2025
podman exec support detaching early via the detach key sequence. In that
case the podman process should exit successfully but the container exec
process keeps running.

Now I wrote automated test for both podman run and exec detach but this
uncovered several larger issues:
 - detach sequence parsing is broken[1]
 - podman-remote exec detach is broken[2]
 - detach in general seems to be buggy/racy, seeing lot of flakes that
   fail to restore the terminal and get an EIO instead, i.e.
   "Unable to restore terminal: input/output error"

Thus I cannot add tests for now but this commit should at least fix the
obvoius case as reported by the user so I like to get this in regardless
and I will work through the other issues once I have more time.

Fixes containers#24895

[1] containers/common#2302
[2] containers#25089

Signed-off-by: Paul Holzinger <[email protected]>
openshift-cherrypick-robot pushed a commit to openshift-cherrypick-robot/podman that referenced this pull request Feb 3, 2025
podman exec support detaching early via the detach key sequence. In that
case the podman process should exit successfully but the container exec
process keeps running.

Now I wrote automated test for both podman run and exec detach but this
uncovered several larger issues:
 - detach sequence parsing is broken[1]
 - podman-remote exec detach is broken[2]
 - detach in general seems to be buggy/racy, seeing lot of flakes that
   fail to restore the terminal and get an EIO instead, i.e.
   "Unable to restore terminal: input/output error"

Thus I cannot add tests for now but this commit should at least fix the
obvoius case as reported by the user so I like to get this in regardless
and I will work through the other issues once I have more time.

Fixes containers#24895

[1] containers/common#2302
[2] containers#25089

Signed-off-by: Paul Holzinger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants