* [PATCH] FS: Fixed buffer overflow issue in seq_read() @ 2013-11-19 0:18 Charley (Hao Chuan) Chu 2013-11-19 0:38 ` Linus Torvalds 2013-11-19 1:20 ` Al Viro 0 siblings, 2 replies; 8+ messages in thread From: Charley (Hao Chuan) Chu @ 2013-11-19 0:18 UTC (permalink / raw) To: linux-fsdevel@vger.kernel.org, Alexander Viro Cc: torvalds@linux-foundation.org, linux-kernel@vger.kernel.org The buffer count is not initialized when a new buffer is allocated. It cause kernel crash with "Unable to handle kernel paging request..." error in __copy_to_user_std(). It happens when a memory allocation failure in the while(1)-loop, which left the buffer count (m->count) is larger than buffer size (m->size). This patch is currently against a linux 3.12 kernel Signed-off-by: Charley Chu charley.chu@broadcom.com --- diff --git a/fs/seq_file.c b/fs/seq_file.c index 1cd2388..480a341 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -191,6 +191,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) /* grab buffer if we didn't have one */ if (!m->buf) { + m->count = m->from = 0; m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); if (!m->buf) goto Enomem; ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 0:18 [PATCH] FS: Fixed buffer overflow issue in seq_read() Charley (Hao Chuan) Chu @ 2013-11-19 0:38 ` Linus Torvalds 2013-11-19 1:26 ` Al Viro 2013-11-19 1:20 ` Al Viro 1 sibling, 1 reply; 8+ messages in thread From: Linus Torvalds @ 2013-11-19 0:38 UTC (permalink / raw) To: Charley (Hao Chuan) Chu Cc: linux-fsdevel@vger.kernel.org, Alexander Viro, linux-kernel@vger.kernel.org Hmm.. Al - this looks like a major oversight, but it also looks like the wrong place to initialize count/from in, just because it doesn't follow any sane patterns. My gut feel is that this needs more cleanup and some sane helper function that always initializes those fields when allocating a new buffer. Rather than the "initialize in random places and then miss a few". Afaik, those fields currently get (re-)initialized when: - We do the memset() of the whole seq_file structure at seq_open() time. - at the top of traverse() - count (but not from) gets reinitialized when growing the buffer or after traverse() fails in seq_read() and it really doesn't give me that happy fuzzy feeling of "that all makes sense". Charley's patch seems to fix a missing initialization, but I'd *really* like to have it all make more sense, and feel that we're not missing some *other* initialization. Al? Linus On Mon, Nov 18, 2013 at 4:18 PM, Charley (Hao Chuan) Chu <charley.chu@broadcom.com> wrote: > The buffer count is not initialized when a new buffer is allocated. > > It cause kernel crash with "Unable to handle kernel paging > request..." error in __copy_to_user_std(). It happens when a > memory allocation failure in the while(1)-loop, which left the > buffer count (m->count) is larger than buffer size > (m->size). > > This patch is currently against a linux 3.12 kernel > > Signed-off-by: Charley Chu charley.chu@broadcom.com > --- > diff --git a/fs/seq_file.c b/fs/seq_file.c > index 1cd2388..480a341 100644 > --- a/fs/seq_file.c > +++ b/fs/seq_file.c > @@ -191,6 +191,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) > > /* grab buffer if we didn't have one */ > if (!m->buf) { > + m->count = m->from = 0; > m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); > if (!m->buf) > goto Enomem; > > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 0:38 ` Linus Torvalds @ 2013-11-19 1:26 ` Al Viro 0 siblings, 0 replies; 8+ messages in thread From: Al Viro @ 2013-11-19 1:26 UTC (permalink / raw) To: Linus Torvalds Cc: Charley (Hao Chuan) Chu, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org On Mon, Nov 18, 2013 at 04:38:03PM -0800, Linus Torvalds wrote: > Hmm.. Al - this looks like a major oversight, but it also looks like > the wrong place to initialize count/from in, just because it doesn't > follow any sane patterns. > > My gut feel is that this needs more cleanup and some sane helper > function that always initializes those fields when allocating a new > buffer. Rather than the "initialize in random places and then miss a > few". > > Afaik, those fields currently get (re-)initialized when: > > - We do the memset() of the whole seq_file structure at seq_open() time. > > - at the top of traverse() > > - count (but not from) gets reinitialized when growing the buffer or > after traverse() fails in seq_read() > > and it really doesn't give me that happy fuzzy feeling of "that all > makes sense". Charley's patch seems to fix a missing initialization, > but I'd *really* like to have it all make more sense, and feel that > we're not missing some *other* initialization. > > Al? See upthread. The bug is real, but I would rather go for a different fix; it's not worth helper functions, though - we have exactly two places where free m->buf without freeing m itself, and all we need to do is clearing m->count in those two places. No point delaying that to the next call of seq_read() (and no point cleaning m->from at all), as soon as we free m->buf we obviously lose all the data that might've been in it. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 0:18 [PATCH] FS: Fixed buffer overflow issue in seq_read() Charley (Hao Chuan) Chu 2013-11-19 0:38 ` Linus Torvalds @ 2013-11-19 1:20 ` Al Viro 2013-11-19 3:13 ` Linus Torvalds 1 sibling, 1 reply; 8+ messages in thread From: Al Viro @ 2013-11-19 1:20 UTC (permalink / raw) To: Charley (Hao Chuan) Chu Cc: linux-fsdevel@vger.kernel.org, torvalds@linux-foundation.org, linux-kernel@vger.kernel.org On Tue, Nov 19, 2013 at 12:18:41AM +0000, Charley (Hao Chuan) Chu wrote: > The buffer count is not initialized when a new buffer is allocated. > > It cause kernel crash with "Unable to handle kernel paging > request..." error in __copy_to_user_std(). It happens when a > memory allocation failure in the while(1)-loop, which left the > buffer count (m->count) is larger than buffer size > (m->size). > > This patch is currently against a linux 3.12 kernel The bug is real, but I don't like the fix. First of all, m->from is a red herring - it's not even looked at if m->count is 0. The real bug is that m->count is not cleared when m->buf is freed - at those points we have zero bytes of valid contents reachable via m->buf. What's more, one of those two points (in seq_read()) has cleaning of ->count right after successful kmalloc() following that kfree(), so it just needs to be moved up a bit. The other one (in traverse()) is missing. So how about this: seq_file: always clear m->count when we free m->buf Once we'd freed m->buf, m->count should become zero - we have no valid contents reachable via m->buf. Reported-by: Charley (Hao Chuan) Chu <charley.chu@broadcom.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- diff --git a/fs/seq_file.c b/fs/seq_file.c index 1cd2388..1d641bb 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -136,6 +136,7 @@ static int traverse(struct seq_file *m, loff_t offset) Eoverflow: m->op->stop(m, p); kfree(m->buf); + m->count = 0; m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); return !m->buf ? -ENOMEM : -EAGAIN; } @@ -232,10 +233,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) goto Fill; m->op->stop(m, p); kfree(m->buf); + m->count = 0; m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); if (!m->buf) goto Enomem; - m->count = 0; m->version = 0; pos = m->index; p = m->op->start(m, &pos); ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 1:20 ` Al Viro @ 2013-11-19 3:13 ` Linus Torvalds 2013-11-19 3:28 ` Al Viro 2013-11-19 21:22 ` Charley (Hao Chuan) Chu 0 siblings, 2 replies; 8+ messages in thread From: Linus Torvalds @ 2013-11-19 3:13 UTC (permalink / raw) To: Al Viro Cc: Charley (Hao Chuan) Chu, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org On Tue, 19 Nov 2013, Al Viro wrote: > > seq_file: always clear m->count when we free m->buf Ok, applied. What do you think about then just abstracing out that now common sequence of re-allocating a larger buffer, while clearing m->count? IOW, something like the appended.. Linus --- fs/seq_file.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/seq_file.c b/fs/seq_file.c index 1d641bb108d2..f513e1efa49d 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -82,6 +82,14 @@ int seq_open(struct file *file, const struct seq_operations *op) } EXPORT_SYMBOL(seq_open); +static int grow_seq_buf(struct seq_file *m) +{ + kfree(m->buf); + m->count = 0; + m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); + return m->buf != NULL; +} + static int traverse(struct seq_file *m, loff_t offset) { loff_t pos = 0, index; @@ -135,10 +143,7 @@ static int traverse(struct seq_file *m, loff_t offset) Eoverflow: m->op->stop(m, p); - kfree(m->buf); - m->count = 0; - m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); - return !m->buf ? -ENOMEM : -EAGAIN; + return grow_seq_buf(m) ? -EAGAIN : -ENOMEM; } /** @@ -232,10 +237,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) if (m->count < m->size) goto Fill; m->op->stop(m, p); - kfree(m->buf); - m->count = 0; - m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); - if (!m->buf) + if (!grow_seq_buf(m)) goto Enomem; m->version = 0; pos = m->index; ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 3:13 ` Linus Torvalds @ 2013-11-19 3:28 ` Al Viro 2013-11-19 3:33 ` Linus Torvalds 2013-11-19 21:22 ` Charley (Hao Chuan) Chu 1 sibling, 1 reply; 8+ messages in thread From: Al Viro @ 2013-11-19 3:28 UTC (permalink / raw) To: Linus Torvalds Cc: Charley (Hao Chuan) Chu, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org On Mon, Nov 18, 2013 at 07:13:54PM -0800, Linus Torvalds wrote: > > > On Tue, 19 Nov 2013, Al Viro wrote: > > > > seq_file: always clear m->count when we free m->buf > > Ok, applied. > > What do you think about then just abstracing out that now common sequence > of re-allocating a larger buffer, while clearing m->count? Sure, no problem, but then we really have only 2 places doing that and no visible cause to grow more of them. With this common sequence being that short, I'm not sure that effort to recall the definition of that helper won't be more than that to understand the open-coded variant. Matter of taste, but IMO in this case the helper makes it slightly less readable... BTW, I've several old commits that didn't go into the first pile (e.g. taking read_seqbegin_or_lock() and friends from fs/dcache.c into linux/seqlock.h, where they obviously belong, etc.) and several regression fixes; are you OK with pull request tomorrow? I can post it tonight, but I'd prefer to leave local toruture running overnight... ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 3:28 ` Al Viro @ 2013-11-19 3:33 ` Linus Torvalds 0 siblings, 0 replies; 8+ messages in thread From: Linus Torvalds @ 2013-11-19 3:33 UTC (permalink / raw) To: Al Viro Cc: Charley (Hao Chuan) Chu, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org On Mon, Nov 18, 2013 at 7:28 PM, Al Viro <viro@zeniv.linux.org.uk> wrote: > > BTW, I've several old commits that didn't go into the first pile (e.g. > taking read_seqbegin_or_lock() and friends from fs/dcache.c into > linux/seqlock.h, where they obviously belong, etc.) and several regression > fixes; are you OK with pull request tomorrow? I can post it tonight, > but I'd prefer to leave local toruture running overnight... Tomorrow's fine. Linus ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH] FS: Fixed buffer overflow issue in seq_read() 2013-11-19 3:13 ` Linus Torvalds 2013-11-19 3:28 ` Al Viro @ 2013-11-19 21:22 ` Charley (Hao Chuan) Chu 1 sibling, 0 replies; 8+ messages in thread From: Charley (Hao Chuan) Chu @ 2013-11-19 21:22 UTC (permalink / raw) To: Linus Torvalds, Al Viro Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org > m->from is a red herring - it's not even looked at if m->count is 0. Then, shall the initialization here be removed too? @@ -90,7 +90,7 @@ static int traverse(struct seq_file *m, loff_t offset) m->version = 0; index = 0; - m->count = m->from = 0; + m->count = 0; if (!offset) { m->index = index; return 0; > What do you think about then just abstracing out that now common sequence > of re-allocating a larger buffer, while clearing m->count? Following code is duplicated (slightly different) in both seq_read() and seq_lseek(). It would be nice to have them consolidated in traverse(). while ((err = traverse(m, *ppos)) == -EAGAIN) ; if (err) { /* With prejudice... */ m->read_pos = 0; m->version = 0; m->index = 0; m->count = 0; goto Done; } else { m->read_pos = *ppos; } Thanks, Charley ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-11-19 21:22 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-11-19 0:18 [PATCH] FS: Fixed buffer overflow issue in seq_read() Charley (Hao Chuan) Chu 2013-11-19 0:38 ` Linus Torvalds 2013-11-19 1:26 ` Al Viro 2013-11-19 1:20 ` Al Viro 2013-11-19 3:13 ` Linus Torvalds 2013-11-19 3:28 ` Al Viro 2013-11-19 3:33 ` Linus Torvalds 2013-11-19 21:22 ` Charley (Hao Chuan) Chu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).