mirror of
https://github.com/minio/minio.git
synced 2025-11-07 21:02:58 -05:00
Fix CreateFile shared buffer corruption. (#18652)
`(*xlStorageDiskIDCheck).CreateFile` wraps the incoming reader in `xioutil.NewDeadlineReader`. The wrapped reader is handed to `(*xlStorage).CreateFile`. This performs a Read call via `writeAllDirect`, which reads into an `ODirectPool` buffer. `(*DeadlineReader).Read` spawns an async read into the buffer. If a timeout is hit while reading, the read operation returns to `writeAllDirect`. The operation returns an error and the buffer is reused. However, if the async `Read` call unblocks, it will write to the now recycled buffer. Fix: Remove the `DeadlineReader` - it is inherently unsafe. Instead, rely on the network timeouts. This is not a disk timeout, anyway. Regression in https://github.com/minio/minio/pull/17745
This commit is contained in:
@@ -104,53 +104,6 @@ type ioret struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// DeadlineReader deadline reader with timeout
|
||||
type DeadlineReader struct {
|
||||
io.ReadCloser
|
||||
timeout time.Duration
|
||||
err error
|
||||
}
|
||||
|
||||
// NewDeadlineReader wraps a writer to make it respect given deadline
|
||||
// value per Write(). If there is a blocking write, the returned Reader
|
||||
// will return whenever the timer hits (the return values are n=0
|
||||
// and err=context.DeadlineExceeded.)
|
||||
func NewDeadlineReader(r io.ReadCloser, timeout time.Duration) io.ReadCloser {
|
||||
return &DeadlineReader{ReadCloser: r, timeout: timeout}
|
||||
}
|
||||
|
||||
func (r *DeadlineReader) Read(buf []byte) (int, error) {
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
}
|
||||
|
||||
c := make(chan ioret, 1)
|
||||
t := time.NewTimer(r.timeout)
|
||||
go func() {
|
||||
n, err := r.ReadCloser.Read(buf)
|
||||
c <- ioret{n, err}
|
||||
close(c)
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-c:
|
||||
if !t.Stop() {
|
||||
<-t.C
|
||||
}
|
||||
r.err = res.err
|
||||
return res.n, res.err
|
||||
case <-t.C:
|
||||
r.ReadCloser.Close()
|
||||
r.err = context.DeadlineExceeded
|
||||
return 0, context.DeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
// Close closer interface to close the underlying closer
|
||||
func (r *DeadlineReader) Close() error {
|
||||
return r.ReadCloser.Close()
|
||||
}
|
||||
|
||||
// DeadlineWriter deadline writer with timeout
|
||||
type DeadlineWriter struct {
|
||||
io.WriteCloser
|
||||
|
||||
Reference in New Issue
Block a user