History

fix a fencepost error in pipe_advance()

The logics in pipe_advance() used to release all buffers past the new position failed in cases when the number of buffers to release was equal to pipe->buffers. If that happened, none of them had been released, leaving pipe full. Worse, it was trivial to trigger and we end up with pipe full of uninitialized pages. IOW, it's an infoleak.

Al Viro committed 9 years ago

Commit b9dc6f61 parent 4d22c751 file · +31 −23Browse files

Unified · Split

lib/iov_iter.c+31−23
@@ -730,43 +730,50 @@ size_t iov_iter_copy_from_user_atomic(struct page *page, · 729 unmodified lines
730}730}
731EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);731EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
732 732
733static inline void pipe_truncate(struct iov_iter *i)
734{
735 struct pipe_inode_info *pipe = i->pipe;
736 if (pipe->nrbufs) {
737 size_t off = i->iov_offset;
738 int idx = i->idx;
739 int nrbufs = (idx - pipe->curbuf) & (pipe->buffers - 1);
740 if (off) {
741 pipe->bufs[idx].len = off - pipe->bufs[idx].offset;
742 idx = next_idx(idx, pipe);
743 nrbufs++;
744 }
745 while (pipe->nrbufs > nrbufs) {
746 pipe_buf_release(pipe, &pipe->bufs[idx]);
747 idx = next_idx(idx, pipe);
748 pipe->nrbufs--;
749 }
750 }
751}
752
733static void pipe_advance(struct iov_iter *i, size_t size)753static void pipe_advance(struct iov_iter *i, size_t size)
734{754{
735 struct pipe_inode_info *pipe = i->pipe;755 struct pipe_inode_info *pipe = i->pipe;
736 struct pipe_buffer *buf;
737 int idx = i->idx;
738 size_t off = i->iov_offset, orig_sz;
739
740 if (unlikely(i->count < size))756 if (unlikely(i->count < size))
741 size = i->count;757 size = i->count;
742 orig_sz = size;
743
744 if (size) {758 if (size) {
759 struct pipe_buffer *buf;
760 size_t off = i->iov_offset, left = size;
761 int idx = i->idx;
745 if (off) /* make it relative to the beginning of buffer */762 if (off) /* make it relative to the beginning of buffer */
746 size += off - pipe->bufs[idx].offset;763 left += off - pipe->bufs[idx].offset;
747 while (1) {764 while (1) {
748 buf = &pipe->bufs[idx];765 buf = &pipe->bufs[idx];
749 if (size <= buf->len)766 if (left <= buf->len)
750 break;767 break;
751 size -= buf->len;768 left -= buf->len;
752 idx = next_idx(idx, pipe);769 idx = next_idx(idx, pipe);
753 }770 }
754 buf->len = size;
755 i->idx = idx;771 i->idx = idx;
756 off = i->iov_offset = buf->offset + size;772 i->iov_offset = buf->offset + left;
757 }
758 if (off)
759 idx = next_idx(idx, pipe);
760 if (pipe->nrbufs) {
761 int unused = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
762 /* [curbuf,unused) is in use. Free [idx,unused) */
763 while (idx != unused) {
764 pipe_buf_release(pipe, &pipe->bufs[idx]);
765 idx = next_idx(idx, pipe);
766 pipe->nrbufs--;
767 }
768 }773 }
769 i->count -= orig_sz;774 i->count -= size;
775 /* ... and discard everything past that point */
776 pipe_truncate(i);
770}777}
771 778
772void iov_iter_advance(struct iov_iter *i, size_t size)779void iov_iter_advance(struct iov_iter *i, size_t size)
@@ -826,6 +833,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction, · 53 unmodified lines
826 size_t count)833 size_t count)
827{834{
828 BUG_ON(direction != ITER_PIPE);835 BUG_ON(direction != ITER_PIPE);
836 WARN_ON(pipe->nrbufs == pipe->buffers);
829 i->type = direction;837 i->type = direction;
830 i->pipe = pipe;838 i->pipe = pipe;
831 i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);839 i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t