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

Fix EOF (^D) handling in devpts (partially addr #9333) #9336

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions pkg/sentry/fsimpl/devpts/devpts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,54 @@ func TestEchoDeadlock(t *testing.T) {
t.Fatalf("written and read strings do not match: got %q, want %q", outStr, inStr)
}
}

func TestEndOfFileHandling(t *testing.T) {
ctx := contexttest.Context(t)
termios := linux.DefaultReplicaTermios
ld := newLineDiscipline(termios, nil)

// EOF with non-empty read buffer.
inBytes := []byte("hello, tty")
inBytes = append(inBytes, termios.ControlCharacters[linux.VEOF])
outBytes := make([]byte, 32)
dst := usermem.BytesIOSequence(outBytes)
// Write to the input queue.
nw, err := ld.inputQueueWrite(ctx, usermem.BytesIOSequence(inBytes))
if err != nil {
t.Fatalf("error writing to input queue: %v", err)
}
if nw != int64(len(inBytes)) {
t.Fatalf("wrote wrong length: got %d, want %d", nw, len(inBytes))
}

// Read from the input queue.
nr, err := ld.inputQueueRead(ctx, dst)
if err != nil {
t.Fatalf("error reading from input queue: %v", err)
}
if nr != int64(len(inBytes) - 1) {
t.Fatalf("read wrong length: got %d, want %d", nr, len(inBytes) - 1)
}

// EOF with empty read buffer.
inBytes = []byte{termios.ControlCharacters[linux.VEOF]}
outBytes = make([]byte, 32)
dst = usermem.BytesIOSequence(outBytes)
// Write to the input queue.
nw, err = ld.inputQueueWrite(ctx, usermem.BytesIOSequence(inBytes))
if err != nil {
t.Fatalf("error writing to input queue: %v", err)
}
if nw != int64(len(inBytes)) {
t.Fatalf("wrote wrong length: got %d, want %d", nw, len(inBytes))
}

// Read from the input queue.
nr, err = ld.inputQueueRead(ctx, dst)
if err != nil {
t.Fatalf("error reading from input queue: %v", err)
}
if nr != 0 {
t.Fatalf("read length should be zero: got %d", nr)
}
}
8 changes: 7 additions & 1 deletion pkg/sentry/fsimpl/devpts/line_discipline.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ func (l *lineDiscipline) inputQueueReadSize(t *kernel.Task, io usermem.IO, args
func (l *lineDiscipline) inputQueueRead(ctx context.Context, dst usermem.IOSequence) (int64, error) {
l.termiosMu.RLock()
n, pushed, notifyEcho, err := l.inQueue.read(ctx, dst, l)
isCanon := l.termios.LEnabled(linux.ICANON)
l.termiosMu.RUnlock()
if err != nil {
return 0, err
Expand All @@ -212,9 +213,14 @@ func (l *lineDiscipline) inputQueueRead(ctx context.Context, dst usermem.IOSeque
l.replicaWaiter.Notify(waiter.ReadableEvents)
}
return n, nil
} else if notifyEcho {
}
if notifyEcho {
l.masterWaiter.Notify(waiter.ReadableEvents)
}
if !pushed && isCanon {
return 0, nil // EOF
}

return 0, linuxerr.ErrWouldBlock
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/sentry/fsimpl/devpts/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const waitBufMaxBytes = 131072
// full, at which point they are written to the wait buffer. Bytes are
// processed (i.e. undergo termios transformations) as they are added to the
// read buffer. The read buffer is readable when its length is nonzero and
// readable is true.
// readable is true, or when its length is zero and readable is true (EOF).
//
// +stateify savable
type queue struct {
Expand Down