Closed
Bug 649429
Opened 14 years ago
Closed 14 years ago
Undefined behavior in gfxASurface::CheckSurfaceSize -- causes crashes with giant allocations
Categories
(Core :: Graphics, defect)
Tracking
()
RESOLVED
FIXED
People
(Reporter: zwol, Assigned: zwol)
References
Details
(Keywords: crash, Whiteboard: [sg:audit])
Attachments
(2 files, 4 obsolete files)
|
3.39 KB,
patch
|
zwol
:
review+
|
Details | Diff | Splinter Review |
|
3.43 KB,
patch
|
zwol
:
review+
|
Details | Diff | Splinter Review |
gfxASurface::CheckSurfaceSize tries to check for signed 32-bit integer overflow with code of the form
PRInt32 tmp = sz.width * sz.height;
if (tmp && tmp / sz.height != sz.width)
fail;
Unfortunately, signed integer overflow DOES NOT wrap; it's undefined behavior (I can quote chapter and verse if anyone really wants me to :) and some compilers (*cough* GCC >=4.4) will cheerfully go "well, that condition could only be true if undefined behavior had just happened, so in a correct program it can never be true, so I will delete the test entirely". Which causes the function to not do its job.
The right way to check for signed integer overflow is
PRUint32 tmp = PRUint32(sz.width) * sz.height;
if (PRInt32(tmp) <= 0 || tmp / sz.height != PRUint32(sz.width))
fail;
(the first cast to PRUint32 is necessary because C++ will *not* do unsigned multiplication just because the result is assigned to an unsigned variable, and the second cast avoids a warning). Patch shortly.
| Assignee | ||
Comment 1•14 years ago
|
||
I should have mentioned that I caught this because of svg/crashtests/478511-1.svg. Bug 385288 is related - SVG probably should put a limit on its pattern surfaces that's smaller than two gigabytes - but not the same.
| Assignee | ||
Comment 2•14 years ago
|
||
Bug number dyslexia strikes again: I meant bug 385228 (and see also bug 522502).
| Assignee | ||
Comment 3•14 years ago
|
||
The change to nsSVGUtils is not necessary to fix this bug, but made debugging easier, and according to the comments, was meant to happen after we got rid of non-libxul builds anyway. Hence the double review request - joedrew for gfx, dholbert for nsSVGUtils.
Assignee: nobody → zackw
Status: NEW → ASSIGNED
Attachment #525458 -
Flags: review?(joe)
Attachment #525458 -
Flags: review?(dholbert)
Comment 4•14 years ago
|
||
(zwol doesn't have the bits to set this, but asked me to)
Group: core-security
| Assignee | ||
Comment 5•14 years ago
|
||
To make the security implications of this bug a little clearer: SVG pattern surfaces try to allocate (4 * x * y) bytes, where both x and y are directly controllable by web content. CheckSurfaceSize is the only thing that prevents that arithmetic from overflowing and wrapping around to a much smaller size. Allocation overflows of that form have been remote-code-execution exploits in the past. I don't know whether this one is that bad, but it's certainly remote-instant-crash for a 32-bit build and remote-throw-your-computer-into-swap-thrashing for a 64-bit build. (It's probably *not* possible to get a 64-bit build to overflow an allocation, though.)
Comment 6•14 years ago
|
||
Comment on attachment 525458 [details] [diff] [review]
patch
>diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp
>+ PRUint32 allocation = area * 4;
>+ if (PRInt32(area) <= 0 || allocation / 4 != area) {
> NS_WARNING("Surface size too large (would overflow)!");
> return PR_FALSE;
You want "PRInt32(allocation) <= 0" (s/area/allocation/) in the if condition there, I think.
| Assignee | ||
Comment 7•14 years ago
|
||
Doh! Yes, I do want "allocation" there. Thanks for the catch.
Attachment #525458 -
Attachment is obsolete: true
Attachment #525458 -
Flags: review?(joe)
Attachment #525458 -
Flags: review?(dholbert)
Attachment #525469 -
Flags: review?(joe)
Attachment #525469 -
Flags: review?(dholbert)
Comment 8•14 years ago
|
||
Comment on attachment 525469 [details] [diff] [review]
v1.1
Looks good to me! (Thanks for addressing the related XXXdholbert post-libxul-world cleanup - I'd forgotten about that :))
Attachment #525469 -
Flags: review?(dholbert) → review+
| Assignee | ||
Comment 9•14 years ago
|
||
It occurred to me this morning that we'd probably get better code generation (no divides, for one thing) if we just did a widening multiply to PRUint64 and then checked to see if it was bigger than PR_INT32_MAX. And indeed it is so with gcc. Can't say for MSVC.
Attachment #525469 -
Attachment is obsolete: true
Attachment #525469 -
Flags: review?(joe)
Attachment #527560 -
Flags: review?(jmuizelaar)
Comment 10•14 years ago
|
||
I think we should be using CheckedInt instead of checking for overflow manually.
| Assignee | ||
Comment 11•14 years ago
|
||
(In reply to comment #10)
> I think we should be using CheckedInt instead of checking for overflow
> manually.
I didn't know we had that. Here's another revision.
Attachment #527560 -
Attachment is obsolete: true
Attachment #527560 -
Flags: review?(jmuizelaar)
Attachment #527611 -
Flags: review?(jmuizelaar)
Updated•14 years ago
|
Attachment #527611 -
Flags: review+
Comment 12•14 years ago
|
||
Comment on attachment 527611 [details] [diff] [review]
v3
It would be good if the XXXdholbert part was a separate patch, but other than that this looks good.
Attachment #527611 -
Flags: review?(jmuizelaar) → review+
| Assignee | ||
Comment 13•14 years ago
|
||
I can split it for checkin if you would prefer.
Comment 14•14 years ago
|
||
That would be great.
| Assignee | ||
Comment 15•14 years ago
|
||
as will be checked in assuming try is green, 1/2 (gfx part)
Attachment #527611 -
Attachment is obsolete: true
Attachment #528044 -
Flags: review+
| Assignee | ||
Comment 17•14 years ago
|
||
http://hg.mozilla.org/mozilla-central/rev/90934a261fac
http://hg.mozilla.org/mozilla-central/rev/33b198be1aa3
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Updated•10 years ago
|
Group: core-security
You need to log in
before you can comment on or make changes to this bug.
Description
•