New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 2 users

Issue metadata

Status: Fixed
Closed: Dec 2012
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 2
Type: Bug-Security

Sign in to add a comment

Issue 155711: Security: forced oom in browser process due to indefinitely growing buffer in chunked decoder

Reported by, Oct 13 2012

Issue description

23.0.1244.0 dev
22.0.1229.94 stable
(+indefinite growing partially affects mozilla
since the code was derived from its codebase)

testing platform: winxp sp2/sp3, 32bit win7

relevant code in: net/http/

description: HttpChunkedDecoder is an object meant to filter incoming chunked data in HttpStreamParser in such a way that it works correctly no matter where the previous tcp transmission delimited. Therefore it maintains an std::string, line_buf_ to handle situations where the \n of a chunk header hasn't arrived yet, it is done with a simple append, the size of line_buf_ is never checked against any constraint. 

An attacker can transmit chunked transfer encoded data containing no newline, leading the accessing browser to run out of memory and crash.

test case: [1] run poc
           [2] navigate to localhost
           [3] observe that do_malloc returns 0, resulting in the
           different route (*)  of execution in the patched malloc
           of chromium, eventually calling the new handler nh*
           pointing to an int3 (**)
dev build: 03506F82   JNZ SHORT chrome_1.03506FE6
release: 01C31688   JNZ SHORT chrome_1.01C316D5)

(**) line 92: (nh*)();
dev build: 03506FE1  CALL ESI
release: 01C316D1   CALL ESI

observations: obviously line_buf_ could easily be limited to
some small number, chunked headers are meant to store an integer sized number in ascii hex and only some small additional stuff. 
talking about integers, the casting of buf_len to int from size_t in chunked_decoder is pretty lame; its passed to StringPiece which takes
size_t, and it could also be possible (but i havent tested it) that
on a largeaddressaware build probably running on 64bit win.
an integer overflow would be possible at line 114
using the above line_buf_ growing approach to get a minus value in buf_len.
1.3 KB View Download

Comment 1 by, Oct 15 2012

Labels: -Pri-0 -Area-Undefined Area-Internals Internals-Network
Would one of the CCs mind taking a look?

Comment 2 by, Oct 15 2012

Adding Wan-Teh too.

The suggestion of a possible integer overflow is worrysome.

Comment 3 by, Oct 15 2012

Labels: -Internals-Network Internals-Network-HTTP
Ew. Matt, if you're around, you've probably taken a look at this more recently than me and should take a look. I'm going to dive in once I get a moment.

Comment 4 by, Oct 15 2012

Status: Assigned
Looking over the code, looks like the bug report is accurate.

I'm unsure exactly what would happen on the integer overflow - we'd end up with a negative buffer length and make a StringPiece with it, which would cast it back to a size_t, I believe.  Looks like this could be pretty bad.

Comment 5 by, Oct 15 2012

Oh, and I'm assigning it to myself and plan to just add some sane limit at which point we return an error.  If anyone else wants to tackle it, or has a better idea, feel free to claim the bug.

Comment 6 by, Oct 15 2012

Yes, this is a bad bug. It looks very easy to trigger an OOM. That said, in my quick skim, I don't see how someone can use this exploit to take over Chromium, even with the integer overflow, so hopefully it's not possible :) I ought to think about it more, but I believe this bug only has crash potential and does not pose a significant security risk. It also can cause bad performance since the std::string requires large chunks of contiguous memory.

Overall, the code is suboptimal and we should fix it. Adding a sane limit is a good first step. Preferably not a CHECK though, since the main problem AFAICT is a server-triggerable crash, so we should gracefully handle it instead.

Comment 7 by, Oct 15 2012

Actually, I think all we'd end up doing is reading through random memory looking for a semicolon until we crash or find one.  Suppose there may be some clever way to figure out if we have semi-colons near a 2^32 byte-boundary relative to the start of the string, but not sure how useful that'd be.  If we don't find a semi-colon, or it's too far after a 2^32 byte boundary, we'll be unable to parse the string as a chunk length.

Comment 8 by, Oct 18 2012

Project Member
The following revision refers to this bug:

r162756 | | 2012-10-18T19:18:00.916065Z

Changed paths:

Fix a crash when a line containing the length of an HTTP
chunk-encoded response is too long.
BUG= 155711 

Review URL:

Comment 9 by, Oct 21 2012

btw, should i notify mozilla? (or it would violate responsible disclosure?)
their (the original; ) 
version has the same logic regarding this header-buffer growing, the only difference is that they use a custom string
 implementation nsCString, which quite remarkably ignores OOM and just doesnt append in that case. No crash
is observable, nevertheless firefox obviously starts to malfunction 
at this point along with a bad performance throughout the system.

Comment 10 by, Oct 23 2012

I think it's a great idea to contact Mozilla about their version of the bug.  However, I think it would be best not to say much (Or anything) about the Chrome bug, just out of general paranoia.  I'm not a security person, and it looks like the worst you can do with this bug is basically a crash, but prefer to err on the side of caution.

Comment 11 by, Nov 2 2012

Do we consider this bug fixed now? I'd like to close this one out if possible.

Some nit-picky thoughts:

* In HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len), buf_len and bytes_consumed should be size_t (get rid of those static_cast<int>s). Casting to different signedness and possibly different width is trouble.

* In theory, the expression line_buf_.length() + buf_len > kMaxLineBufLen could itself be subject to integer overflow, causing the check to falsely pass. But I *think* that would only happen if we had already used up a huge amount of memory and DoS'd ourselves, since buf_len results from StringPiece::find (i.e. it's a count of bytes already allocated). Are you guys sure? I always get a bit anxious when I see overflowish-looking expressions, so I thought I'd mention it.

Comment 12 by, Nov 2 2012

Labels: OS-All Pri-2 SecImpacts-Stable SecImpacts-Beta SecSeverity-Low Merge-Requested Mstone-23
The patch does stop the attack from working (I get net::ERR_INVALID_CHUNKED_ENCODING as expected).

We should merge this patch into 23.

Fixing flags.

Comment 13 by, Nov 2 2012

I think you're right to be concerned about mixing size_t's and ints.

That having been said, I consider it fixed - rightly or wrongly, our network stack uses negative return codes to indicate an error, so we can't use size_t's across our entire network stack, and therefore, I think we should minimize their scope.  It's relatively easy to reason about their interactions if size_t's are generally only used in a single file or function.

line_buf_.length() is at most kMaxLineBufLen.  buf_len is at most MAX_INT (And since it comes from a single socket read, it's actually much, much smaller, in general).  Adding them is therefore less than MAX_INT + kMaxLineBufLen, which fits well within the unsigned size_t you get from adding the two.

We could ditch the use of a string, and just use a GrowableIOBuffer instead (Or a scoped_ptr_malloc<char>, along with an int length, which is what GrowableIOBuffer does).  It's a bit more complicated, but avoids any use of size_t's at all.  Of course, then I suppose you could theoretically have overflow in that length check.

Comment 14 by, Nov 3 2012

Status: Fixed
Ok, I understand. Thank you!

I'll mark this Fixed then, and we'll get it into 23.

Comment 15 by, Nov 5 2012

i assume this can wait until stable 2? we've passed the train for stable 1.

Comment 16 by, Nov 5 2012

Yes, I think so. Thank you, Karen.

Comment 17 by, Nov 12 2012

Labels: -Restrict-View-SecurityTeam -Merge-Requested Restrict-View-SecurityNotify Merge-Approved
Status: FixUnreleased

Comment 18 by, Nov 12 2012

"notifier: Merge Approved Improperly(cr): 155711".  I assume it just doesn't think much of scarybeasts setting Merge-Approved.  I'll plan to go ahead merge to M23 this evening, assuming I don't hear otherwise.

Comment 19 by, Nov 12 2012

I'll do it for you now. Not sure why the bot got upset. I set the flag all the time.

Comment 20 by, Nov 12 2012

Ok, thanks!

Maybe it's just that no one actually pays attention to the notifier.  :)

Comment 21 by, Nov 12 2012

Project Member
Labels: -Merge-Approved merge-merged-1271
The following revision refers to this bug:

r167233 | | 2012-11-12T20:54:06.667838Z

Changed paths:

Merge 162756 - Fix a crash when a line containing the length of an HTTP
chunk-encoded response is too long.
BUG= 155711 

Review URL:
Review URL:

Comment 22 by, Nov 12 2012 would you like us to credit you by name? If so, what name?

Also, as you can see, we've gone for "Low" severity. We'd be happy to revise upwards if there's any way to demo the integer issues causing a bad write before hitting OOM.

Comment 23 by, Nov 14 2012

@scarybeasts: Yeah, it would be great, thanks. My name is Attila Szász.

I'd also be happy too, if i could ;) but the mention of the integer overflow only as a sidenote had good reason; I couldn't find anything harmful building on it.
This is quite a buggy looking code mainly due to its Cish sorta state machinery;
achieves a good performance at the expense of being subject to some first doubts
about its possible execution paths,
nevertheless i believe these size_t castbacks, the check on parsed_number, bytes_consumed, and the fact that the mainloop's buf_len is seperated from the affected parsing
make it impossible to do nasty things around memmove. 

The worst thing you can do imo, and the one that hasnt been mentioned yet is
a very weak kind of outofbounds read at  
   185 while (len && start[len - 1] == ' ') 
buf_len this time is implicitly int (and also minus when the position of ';' is still after the 2gig boundary - correct me if im wrong) so i guess
nothing stops you from figuring out the number of consecutive spaces somewhere before your string at this point. hurray! :DD

Comment 24 by, Dec 20 2012

Status: Fixed

Comment 25 by, Mar 10 2013

Project Member
Labels: -Type-Security -Area-Internals -Internals-Network-HTTP -SecImpacts-Stable -SecImpacts-Beta -SecSeverity-Low -Mstone-23 Security-Severity-Low Security-Impact-Stable Security-Impact-Beta Cr-Internals-Network-HTTP Cr-Internals M-23 Type-Bug-Security

Comment 26 by, Mar 21 2013

Labels: -Restrict-View-SecurityNotify

Comment 27 by, Mar 21 2013

Project Member
Labels: -Security-Severity-Low Security_Severity-Low

Comment 28 by, Mar 21 2013

Project Member
Labels: -Security-Impact-Stable Security_Impact-Stable

Comment 29 by, Mar 21 2013

Project Member
Labels: -Security-Impact-Beta Security_Impact-Beta

Comment 30 by, Jun 14 2016

Project Member
Labels: -security_impact-beta

Comment 31 by, Oct 1 2016

Project Member
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit - Your friendly Sheriffbot

Comment 32 by, Oct 2 2016

Project Member
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit - Your friendly Sheriffbot

Comment 33 by, Oct 2 2016

Labels: allpublic

Comment 34 by, Jul 6 2018

Components: Internals>Network

Comment 35 by, Jul 6 2018

Components: -Internals>Network>HTTP

Sign in to add a comment