diff options
author | Kevin Krakauer <krakauer@google.com> | 2019-04-03 11:48:33 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-03 11:49:55 -0700 |
commit | c79e81bd27cd9cccddb0cece30bf47efbfca41b7 (patch) | |
tree | af8b10e74e60b71a2100b66cbb557b8b63941262 /pkg/sentry/fs/tty/queue.go | |
parent | 77f01ee3c7f947a3be569e49e248187b2663607f (diff) |
Addresses data race in tty implementation.
Also makes the safemem reading and writing inline, as it makes it easier to see
what locks are held.
PiperOrigin-RevId: 241775201
Change-Id: Ib1072f246773ef2d08b5b9a042eb7e9e0284175c
Diffstat (limited to 'pkg/sentry/fs/tty/queue.go')
-rw-r--r-- | pkg/sentry/fs/tty/queue.go | 87 |
1 files changed, 42 insertions, 45 deletions
diff --git a/pkg/sentry/fs/tty/queue.go b/pkg/sentry/fs/tty/queue.go index f39f47941..5e88d84d9 100644 --- a/pkg/sentry/fs/tty/queue.go +++ b/pkg/sentry/fs/tty/queue.go @@ -63,49 +63,6 @@ type queue struct { transformer } -// ReadToBlocks implements safemem.Reader.ReadToBlocks. -func (q *queue) ReadToBlocks(dst safemem.BlockSeq) (uint64, error) { - src := safemem.BlockSeqOf(safemem.BlockFromSafeSlice(q.readBuf)) - n, err := safemem.CopySeq(dst, src) - if err != nil { - return 0, err - } - q.readBuf = q.readBuf[n:] - - // If we read everything, this queue is no longer readable. - if len(q.readBuf) == 0 { - q.readable = false - } - - return n, nil -} - -// WriteFromBlocks implements safemem.Writer.WriteFromBlocks. -func (q *queue) WriteFromBlocks(src safemem.BlockSeq) (uint64, error) { - copyLen := src.NumBytes() - room := waitBufMaxBytes - q.waitBufLen - // If out of room, return EAGAIN. - if room == 0 && copyLen > 0 { - return 0, syserror.ErrWouldBlock - } - // Cap the size of the wait buffer. - if copyLen > room { - copyLen = room - src = src.TakeFirst64(room) - } - buf := make([]byte, copyLen) - - // Copy the data into the wait buffer. - dst := safemem.BlockSeqOf(safemem.BlockFromSafeSlice(buf)) - n, err := safemem.CopySeq(dst, src) - if err != nil { - return 0, err - } - q.waitBufAppend(buf) - - return n, nil -} - // readReadiness returns whether q is ready to be read from. func (q *queue) readReadiness(t *linux.KernelTermios) waiter.EventMask { q.mu.Lock() @@ -118,6 +75,8 @@ func (q *queue) readReadiness(t *linux.KernelTermios) waiter.EventMask { // writeReadiness returns whether q is ready to be written to. func (q *queue) writeReadiness(t *linux.KernelTermios) waiter.EventMask { + q.mu.Lock() + defer q.mu.Unlock() if q.waitBufLen < waitBufMaxBytes { return waiter.EventOut } @@ -158,7 +117,21 @@ func (q *queue) read(ctx context.Context, dst usermem.IOSequence, l *lineDiscipl dst = dst.TakeFirst(canonMaxBytes) } - n, err := dst.CopyOutFrom(ctx, q) + n, err := dst.CopyOutFrom(ctx, safemem.ReaderFunc(func(dst safemem.BlockSeq) (uint64, error) { + src := safemem.BlockSeqOf(safemem.BlockFromSafeSlice(q.readBuf)) + n, err := safemem.CopySeq(dst, src) + if err != nil { + return 0, err + } + q.readBuf = q.readBuf[n:] + + // If we read everything, this queue is no longer readable. + if len(q.readBuf) == 0 { + q.readable = false + } + + return n, nil + })) if err != nil { return 0, false, err } @@ -178,7 +151,30 @@ func (q *queue) write(ctx context.Context, src usermem.IOSequence, l *lineDiscip defer q.mu.Unlock() // Copy data into the wait buffer. - n, err := src.CopyInTo(ctx, q) + n, err := src.CopyInTo(ctx, safemem.WriterFunc(func(src safemem.BlockSeq) (uint64, error) { + copyLen := src.NumBytes() + room := waitBufMaxBytes - q.waitBufLen + // If out of room, return EAGAIN. + if room == 0 && copyLen > 0 { + return 0, syserror.ErrWouldBlock + } + // Cap the size of the wait buffer. + if copyLen > room { + copyLen = room + src = src.TakeFirst64(room) + } + buf := make([]byte, copyLen) + + // Copy the data into the wait buffer. + dst := safemem.BlockSeqOf(safemem.BlockFromSafeSlice(buf)) + n, err := safemem.CopySeq(dst, src) + if err != nil { + return 0, err + } + q.waitBufAppend(buf) + + return n, nil + })) if err != nil { return 0, err } @@ -241,6 +237,7 @@ func (q *queue) pushWaitBufLocked(l *lineDiscipline) int { return total } +// Precondition: q.mu must be locked. func (q *queue) waitBufAppend(b []byte) { q.waitBuf = append(q.waitBuf, b) q.waitBufLen += uint64(len(b)) |