Closed Bug 1711576 Opened 3 years ago Closed 3 years ago

heap-buffer-overflow in [@ IsCSSWordSpacingSpace]

Categories

(Core :: Layout: Text and Fonts, defect)

defect

Tracking

()

VERIFIED FIXED
90 Branch
Tracking Status
firefox-esr78 90+ fixed
firefox88 --- wontfix
firefox89 --- wontfix
firefox90 + verified

People

(Reporter: tsmith, Assigned: jfkthame)

References

(Blocks 1 open bug)

Details

(4 keywords, Whiteboard: [bugmon:bisected,confirmed][post-critsmash-triage][adv-main90+r][adv-esr78.12+r])

Attachments

(2 files)

Attached file testcase.html

Found while fuzzing m-c 20210512-02aeefba2bce (--enable-address-sanitizer --enable-fuzzing)

==508531==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200009d7fc at pc 0x7fb7cef8f580 bp 0x7ffd78a0c260 sp 0x7ffd78a0c258
READ of size 2 at 0x60200009d7fc thread T0 (Web Content)
    #0 0x7fb7cef8f57f in nsTextFragment::CharAt(int) const /builds/worker/checkouts/gecko/dom/base/nsTextFragment.h:215:27
    #1 0x7fb7d408fdbd in IsCSSWordSpacingSpace /builds/worker/checkouts/gecko/layout/generic/nsTextFrame.cpp:769:24
    #2 0x7fb7d408fdbd in nsTextFrame::PropertyProvider::GetSpacingInternal(gfxTextRun::Range, gfxFont::Spacing*, bool) const /builds/worker/checkouts/gecko/layout/generic/nsTextFrame.cpp:3485:13
    #3 0x7fb7ceba07a3 in GetAdjustedSpacing /builds/worker/checkouts/gecko/gfx/thebes/gfxTextRun.cpp:369:14
    #4 0x7fb7ceba07a3 in gfxTextRun::BreakAndMeasureText(unsigned int, unsigned int, bool, double, gfxTextRun::PropertyProvider*, gfxTextRun::SuppressBreak, double*, bool, gfxFont::RunMetrics*, gfxFont::BoundingBoxType, mozilla::gfx::DrawTarget*, bool*, unsigned int*, bool, bool, gfxBreakPriority*) /builds/worker/checkouts/gecko/gfx/thebes/gfxTextRun.cpp:918:5
    #5 0x7fb7d40c2f4e in nsTextFrame::ReflowText(nsLineLayout&, int, mozilla::gfx::DrawTarget*, mozilla::ReflowOutput&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsTextFrame.cpp:9342:44
    #6 0x7fb7d403a5c8 in nsLineLayout::ReflowFrame(nsIFrame*, nsReflowStatus&, mozilla::ReflowOutput*, bool&) /builds/worker/checkouts/gecko/layout/generic/nsLineLayout.cpp:878:40
    #7 0x7fb7d3e25921 in nsBlockFrame::ReflowInlineFrame(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsIFrame*, LineReflowStatus*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4532:15
    #8 0x7fb7d3e24910 in nsBlockFrame::DoReflowInlineFrames(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsFlowAreaRect&, int&, nsFloatManager::SavedState*, bool*, LineReflowStatus*, bool) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4334:5
    #9 0x7fb7d3e1dace in nsBlockFrame::ReflowInlineFrames(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4219:9
    #10 0x7fb7d3e172f9 in nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:3199:5
    #11 0x7fb7d3e0ef10 in nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:2733:7
    #12 0x7fb7d3e09b25 in nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:1373:3
    #13 0x7fb7d403a7ad in nsLineLayout::ReflowFrame(nsIFrame*, nsReflowStatus&, mozilla::ReflowOutput*, bool&) /builds/worker/checkouts/gecko/layout/generic/nsLineLayout.cpp:875:13
    #14 0x7fb7d3e25921 in nsBlockFrame::ReflowInlineFrame(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsIFrame*, LineReflowStatus*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4532:15
    #15 0x7fb7d3e24910 in nsBlockFrame::DoReflowInlineFrames(mozilla::BlockReflowInput&, nsLineLayout&, nsLineList_iterator, nsFlowAreaRect&, int&, nsFloatManager::SavedState*, bool*, LineReflowStatus*, bool) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4334:5
    #16 0x7fb7d3e1dace in nsBlockFrame::ReflowInlineFrames(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:4219:9
    #17 0x7fb7d3e172f9 in nsBlockFrame::ReflowLine(mozilla::BlockReflowInput&, nsLineList_iterator, bool*) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:3199:5
    #18 0x7fb7d3e0ef10 in nsBlockFrame::ReflowDirtyLines(mozilla::BlockReflowInput&) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:2733:7
    #19 0x7fb7d3e09b25 in nsBlockFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsBlockFrame.cpp:1373:3
    #20 0x7fb7d40f7883 in nsFileControlFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/forms/nsFileControlFrame.cpp:148:19
    #21 0x7fb7d3e00143 in nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame*, nsPresContext*, mozilla::ReflowInput const&, nsRect const&, nsAbsoluteContainingBlock::AbsPosReflowFlags, nsIFrame*, nsReflowStatus&, mozilla::OverflowAreas*) /builds/worker/checkouts/gecko/layout/generic/nsAbsoluteContainingBlock.cpp:812:14
    #22 0x7fb7d3dfdda9 in nsAbsoluteContainingBlock::Reflow(nsContainerFrame*, nsPresContext*, mozilla::ReflowInput const&, nsReflowStatus&, nsRect const&, nsAbsoluteContainingBlock::AbsPosReflowFlags, mozilla::OverflowAreas*) /builds/worker/checkouts/gecko/layout/generic/nsAbsoluteContainingBlock.cpp:220:7
    #23 0x7fb7d3f91dfa in nsIFrame::ReflowAbsoluteFrames(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&, bool) /builds/worker/checkouts/gecko/layout/generic/nsIFrame.cpp:6681:24
    #24 0x7fb7d40493e2 in nsPageContentFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsPageContentFrame.cpp:140:3
    #25 0x7fb7d3e6a636 in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, int, int, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1041:14
    #26 0x7fb7d404d222 in nsPageFrame::ReflowPageContent(nsPresContext*, mozilla::ReflowInput const&) /builds/worker/checkouts/gecko/layout/generic/nsPageFrame.cpp:149:3
    #27 0x7fb7d404d804 in nsPageFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsPageFrame.cpp:176:13
    #28 0x7fb7d3e69eef in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1001:14
    #29 0x7fb7d3dbee28 in mozilla::PrintedSheetFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/PrintedSheetFrame.cpp:132:5
    #30 0x7fb7d3e6a636 in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, int, int, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1041:14
    #31 0x7fb7d4054aef in nsPageSequenceFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsPageSequenceFrame.cpp:354:5
    #32 0x7fb7d3e69eef in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1001:14
    #33 0x7fb7d3e48537 in nsCanvasFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsCanvasFrame.cpp:818:7
    #34 0x7fb7d3e69eef in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, mozilla::WritingMode const&, mozilla::LogicalPoint const&, nsSize const&, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1001:14
    #35 0x7fb7d3edd8f1 in nsHTMLScrollFrame::ReflowScrolledFrame(mozilla::ScrollReflowInput*, bool, bool, mozilla::ReflowOutput*) /builds/worker/checkouts/gecko/layout/generic/nsGfxScrollFrame.cpp:758:3
    #36 0x7fb7d3edf26c in nsHTMLScrollFrame::ReflowContents(mozilla::ScrollReflowInput*, mozilla::ReflowOutput const&) /builds/worker/checkouts/gecko/layout/generic/nsGfxScrollFrame.cpp:881:3
    #37 0x7fb7d3ee555e in nsHTMLScrollFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/nsGfxScrollFrame.cpp:1300:3
    #38 0x7fb7d3e6a636 in nsContainerFrame::ReflowChild(nsIFrame*, nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, int, int, nsIFrame::ReflowChildFlags, nsReflowStatus&, nsOverflowContinuationTracker*) /builds/worker/checkouts/gecko/layout/generic/nsContainerFrame.cpp:1041:14
    #39 0x7fb7d3dfcaad in mozilla::ViewportFrame::Reflow(nsPresContext*, mozilla::ReflowOutput&, mozilla::ReflowInput const&, nsReflowStatus&) /builds/worker/checkouts/gecko/layout/generic/ViewportFrame.cpp:372:7
    #40 0x7fb7d3c43a15 in mozilla::PresShell::DoReflow(nsIFrame*, bool, mozilla::OverflowChangedTracker*) /builds/worker/checkouts/gecko/layout/base/PresShell.cpp:9604:11
    #41 0x7fb7d3c548d7 in mozilla::PresShell::ProcessReflowCommands(bool) /builds/worker/checkouts/gecko/layout/base/PresShell.cpp:9775:24
    #42 0x7fb7d3c531e3 in mozilla::PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush) /builds/worker/checkouts/gecko/layout/base/PresShell.cpp:4246:11
    #43 0x7fb7d450172f in nsPrintJob::ReflowPrintObject(mozilla::UniquePtr<nsPrintObject, mozilla::DefaultDelete<nsPrintObject> > const&) /builds/worker/checkouts/gecko/layout/printing/nsPrintJob.cpp:1869:14
    #44 0x7fb7d450014e in nsPrintJob::ReflowDocList(mozilla::UniquePtr<nsPrintObject, mozilla::DefaultDelete<nsPrintObject> > const&, bool) /builds/worker/checkouts/gecko/layout/printing/nsPrintJob.cpp:1450:3
    #45 0x7fb7d44f8cd1 in nsPrintJob::InitPrintDocConstruction(bool) /builds/worker/checkouts/gecko/layout/printing/nsPrintJob.cpp:1490:5
    #46 0x7fb7d45070b8 in nsPrintJob::Observe(nsISupports*, char const*, char16_t const*) /builds/worker/checkouts/gecko/layout/printing/nsPrintJob.cpp:2693:17
    #47 0x7fb7d78e4739 in mozilla::embedding::PrintProgressDialogChild::RecvDialogOpened() /builds/worker/checkouts/gecko/toolkit/components/printingui/ipc/PrintProgressDialogChild.cpp:37:18
    #48 0x7fb7cd6cff24 in mozilla::embedding::PPrintProgressDialogChild::OnMessageReceived(IPC::Message const&) /builds/worker/workspace/obj-build/ipc/ipdl/PPrintProgressDialogChild.cpp:234:28
    #49 0x7fb7cd2d0393 in mozilla::dom::PContentChild::OnMessageReceived(IPC::Message const&) /builds/worker/workspace/obj-build/ipc/ipdl/PContentChild.cpp:8287:32
    #50 0x7fb7cd05280a in mozilla::ipc::MessageChannel::DispatchAsyncMessage(mozilla::ipc::ActorLifecycleProxy*, IPC::Message const&) /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:2152:25
    #51 0x7fb7cd04ef38 in mozilla::ipc::MessageChannel::DispatchMessage(IPC::Message&&) /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:2076:9
    #52 0x7fb7cd050895 in mozilla::ipc::MessageChannel::RunMessage(mozilla::ipc::MessageChannel::MessageTask&) /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:1924:3
    #53 0x7fb7cd0513fb in mozilla::ipc::MessageChannel::MessageTask::Run() /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:1955:13
    #54 0x7fb7cbeb8c22 in mozilla::RunnableTask::Run() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:482:16
    #55 0x7fb7cbe856b0 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:766:26
    #56 0x7fb7cbe831b7 in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:621:15
    #57 0x7fb7cbe8360d in mozilla::TaskController::ProcessPendingMTTask(bool) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:405:36
    #58 0x7fb7cbec2c84 in operator() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:141:37
    #59 0x7fb7cbec2c84 in mozilla::detail::RunnableFunction<mozilla::TaskController::InitializeInternal()::$_1>::Run() /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:534:5
    #60 0x7fb7cbe9ff98 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1159:16
    #61 0x7fb7cbeaad4c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
    #62 0x7fb7cd059f84 in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:107:5
    #63 0x7fb7ccf621c1 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
    #64 0x7fb7ccf621c1 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
    #65 0x7fb7ccf621c1 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
    #66 0x7fb7d36fc7c7 in nsBaseAppShell::Run() /builds/worker/checkouts/gecko/widget/nsBaseAppShell.cpp:137:27
    #67 0x7fb7d794f97f in XRE_RunAppShell() /builds/worker/checkouts/gecko/toolkit/xre/nsEmbedFunctions.cpp:911:20
    #68 0x7fb7ccf621c1 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
    #69 0x7fb7ccf621c1 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
    #70 0x7fb7ccf621c1 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
    #71 0x7fb7d794f358 in XRE_InitChildProcess(int, char**, XREChildData const*) /builds/worker/checkouts/gecko/toolkit/xre/nsEmbedFunctions.cpp:743:34
    #72 0x564f2579d61d in content_process_main(mozilla::Bootstrap*, int, char**) /builds/worker/checkouts/gecko/browser/app/../../ipc/contentproc/plugin-container.cpp:57:28
    #73 0x564f2579da4d in main /builds/worker/checkouts/gecko/browser/app/nsBrowserApp.cpp:313:18
    #74 0x7fb7ed5000b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #75 0x564f256ee919 in _start (/home/user/workspace/browsers/m-c-20210517094928-fuzzing-asan-opt/firefox+0x5b919)
Severity: -- → S2
Flags: in-testsuite?
Severity: S2 → --

A Pernosco session is available here: https://pernos.co/debug/bni1E7_a54yoQEHOkQUWYw/index.html

Bugmon Analysis:
Verified bug as reproducible on mozilla-central 20210517212600-50c8711162bd.
The bug appears to have been introduced in the following build range:

Start: a25601920fab8afe0b399e3750c53cf411e3c8ec (20200827201039)
End: ae59b435ba7e86aca38535e07e7b12609bb9a9b1 (20200827225009)
Pushlog: https://hg.mozilla.org/integration/autoland/pushloghtml?fromchange=a25601920fab8afe0b399e3750c53cf411e3c8ec&tochange=ae59b435ba7e86aca38535e07e7b12609bb9a9b1

Whiteboard: [bugmon:bisected,confirmed]

Bug 1493223 made window.printPreview() available in fuzzing builds.

Looks like this is in textframe/text-run code. jfkthame, do you have cycles to take a look?

I poked around in pernosco a bit, and learned the following:

  • This is about some text that's shown in the file-input frame.
  • That text initially says No file selected. (17 characters long), and it changes to u"\x2026" (an ellipsis, as a single UTF character) for some reason (not sure why). This change happens in nsFileControlFrame::Reflow's call to UpdateDisplayedValue.
  • However, some piece of our bookkeeping still thinks we have 17 characters.
  • ...so we get to nsTextFrame::Reflow for this text, and we end in a loop that's expecting to iterate over 17 characters, but in fact we only have 1, so we walk off the end of an array.
  • Specifically: when we crash, GetSpacingInternal is iterating from 0 to aRange.Length() (which is 17), here:
    https://searchfox.org/mozilla-central/rev/98a9257ca2847fad9a19631ac76199474516b31e/layout/generic/nsTextFrame.cpp#3473-3485
    This crashes with the following backtrace, due to reading off the end of its Get2b() buffer:
#0  nsTextFragment::CharAt (this=0x60c000138768, aIndex=2) at /home/twsmith/code/mozilla-central/dom/base/nsTextFragment.h:214
#1  0x000026ec7f3854a8 in IsCSSWordSpacingSpace (aFrag=0x60c000138768, aPos=2, aFrame=0x625000237c40, aStyleText=0x60f0000600d8) at /home/twsmith/code/mozilla-central/layout/generic/nsTextFrame.cpp:769
#2  0x000026ec7f384920 in nsTextFrame::PropertyProvider::GetSpacingInternal (this=0x7fffffb169a0, aRange=..., aSpacing=0x7fffffb14370, aIgnoreTabs=true) at /home/twsmith/code/mozilla-central/layout/generic/nsTextFrame.cpp:3485
#3  0x000026ec7f383ea5 in nsTextFrame::PropertyProvider::GetSpacing (this=0x7fffffb169a0, aRange=..., aSpacing=0x7fffffb14370) at /home/twsmith/code/mozilla-central/layout/generic/nsTextFrame.cpp:3415
#4  0x000026ec75595d3c in GetAdjustedSpacing (aTextRun=0x60f0000601c0, aRange=..., aProvider=0x7fffffb169a0, aSpacing=0x7fffffb14370) at /home/twsmith/code/mozilla-central/gfx/thebes/gfxTextRun.cpp:369
#5  0x000026ec755a086d in gfxTextRun::BreakAndMeasureText (this=0x60f0000601c0, aStart=0, aMaxLength=17, aLineBreakBefore=true, aWidth=88044, aProvider=0x7fffffb169a0, aSuppressBreak=gfxTextRun::eSuppressInitialBreak, aTrimWhitespace=0x7fffffb16b60, aWhitespaceCanHang=false, aMetrics=0x7fffffb16aa0, aBoundingBoxType=gfxFont::LOOSE_INK_EXTENTS, aRefDrawTarget=0x610000007140, aUsedHyphenation=0x7fffffb16b50, aLastBreak=0x7fffffb16b40, aCanWordWrap=false, aCanWhitespaceWrap=false, aBreakPriority=0x7fffffb16b80) at /home/twsmith/code/mozilla-central/gfx/thebes/gfxTextRun.cpp:918
#6  0x000026ec7f3cdbc7 in nsTextFrame::ReflowText (this=0x625000237c40, aLineLayout=..., aAvailableWidth=88044, aDrawTarget=0x610000007140, aMetrics=..., aStatus=...) at /home/twsmith/code/mozilla-central/layout/generic/nsTextFrame.cpp:9342
#7  0x000026ec7f2fd29e in nsLineLayout::ReflowFrame (this=0x7fffffb19620, aFrame=0x625000237c40, aReflowStatus=..., aMetrics=0x0, aPushedFrame=@0x7fffffb18a10: false) at /home/twsmith/code/mozilla-central/layout/generic/nsLineLayout.cpp:878
#8  0x000026ec7ef35287 in nsBlockFrame::ReflowInlineFrame (this=0x625000237b80, aState=..., aLineLayout=..., aLine=..., aFrame=0x625000237c40, aLineReflowStatus=0x7fffffb18db0) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4532
#9  0x000026ec7ef33ab0 in nsBlockFrame::DoReflowInlineFrames (this=0x625000237b80, aState=..., aLineLayout=..., aLine=..., aFloatAvailableSpace=..., aAvailableSpaceBSize=@0x7fffffb195d0: 0, aFloatStateBeforeLine=0x7fffffb19600, aKeepReflowGoing=0x7fffffb19c80, aLineReflowStatus=0x7fffffb195c0, aAllowPullUp=true) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4334
#10 0x000026ec7ef29c95 in nsBlockFrame::ReflowInlineFrames (this=0x625000237b80, aState=..., aLine=..., aKeepReflowGoing=0x7fffffb19c80) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4219
#11 0x000026ec7ef2073f in nsBlockFrame::ReflowLine (this=0x625000237b80, aState=..., aLine=..., aKeepReflowGoing=0x7fffffb19c80) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:3199
#12 0x000026ec7ef105fc in nsBlockFrame::ReflowDirtyLines (this=0x625000237b80, aState=...) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:2733
#13 0x000026ec7ef08d66 in nsBlockFrame::Reflow (this=0x625000237b80, aPresContext=0x61600000d580, aMetrics=..., aReflowInput=..., aStatus=...) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:1373
#14 0x000026ec7f2fd1be in nsLineLayout::ReflowFrame (this=0x7fffffb1df60, aFrame=0x625000237b80, aReflowStatus=..., aMetrics=0x0, aPushedFrame=@0x7fffffb1d350: false) at /home/twsmith/code/mozilla-central/layout/generic/nsLineLayout.cpp:875
#15 0x000026ec7ef35287 in nsBlockFrame::ReflowInlineFrame (this=0x625000227f00, aState=..., aLineLayout=..., aLine=..., aFrame=0x625000237b80, aLineReflowStatus=0x7fffffb1d6f0) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4532
#16 0x000026ec7ef33ab0 in nsBlockFrame::DoReflowInlineFrames (this=0x625000227f00, aState=..., aLineLayout=..., aLine=..., aFloatAvailableSpace=..., aAvailableSpaceBSize=@0x7fffffb1df10: 0, aFloatStateBeforeLine=0x7fffffb1df40, aKeepReflowGoing=0x7fffffb1e5c0, aLineReflowStatus=0x7fffffb1df00, aAllowPullUp=true) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4334
#17 0x000026ec7ef29c95 in nsBlockFrame::ReflowInlineFrames (this=0x625000227f00, aState=..., aLine=..., aKeepReflowGoing=0x7fffffb1e5c0) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:4219
#18 0x000026ec7ef2073f in nsBlockFrame::ReflowLine (this=0x625000227f00, aState=..., aLine=..., aKeepReflowGoing=0x7fffffb1e5c0) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:3199
#19 0x000026ec7ef105fc in nsBlockFrame::ReflowDirtyLines (this=0x625000227f00, aState=...) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:2733
#20 0x000026ec7ef08d66 in nsBlockFrame::Reflow (this=0x625000227f00, aPresContext=0x61600000d580, aMetrics=..., aReflowInput=..., aStatus=...) at /home/twsmith/code/mozilla-central/layout/generic/nsBlockFrame.cpp:1373
#21 0x000026ec7f43de49 in nsFileControlFrame::Reflow (this=0x625000227f00, aPresContext=0x61600000d580, aMetrics=..., aReflowInput=..., aStatus=...) at /home/twsmith/code/mozilla-central/layout/forms/nsFileControlFrame.cpp:148
#22 0x000026ec7eef8df2 in nsAbsoluteContainingBlock::ReflowAbsoluteFrame (this=0x6020000890d0, aDelegatingFrame=0x625000227cc0, aPresContext=0x61600000d580, aReflowInput=..., aContainingBlock=..., aFlags=7, aKidFrame=0x625000227f00, aStatus=..., aOverflowAreas=0x0) at /home/twsmith/code/mozilla-central/layout/generic/nsAbsoluteContainingBlock.cpp:812
#23 0x000026ec7eef4695 in nsAbsoluteContainingBlock::Reflow (this=0x6020000890d0, aDelegatingFrame=0x625000227cc0, aPresContext=0x61600000d580, aReflowInput=..., aReflowStatus=..., aContainingBlock=..., aFlags=7, aOverflowAreas=0x0) at /home/twsmith/code/mozilla-central/layout/generic/nsAbsoluteContainingBlock.cpp:220
#24 0x000026ec7f173202 in nsIFrame::ReflowAbsoluteFrames (this=0x625000227cc0, aPresContext=0x61600000d580, aDesiredSize=..., aReflowInput=..., aStatus=..., aConstrainBSize=true) at /home/twsmith/code/mozilla-central/layout/generic/nsIFrame.cpp:6681
#25 0x000026ec7f318fa0 in nsPageContentFrame::Reflow (this=0x625000227cc0, aPresContext=0x61600000d580, aReflowOutput=..., aReflowInput=..., aStatus=...) at /home/twsmith/code/mozilla-central/layout/generic/nsPageContentFrame.cpp:140
Flags: needinfo?(jfkthame)

The change of No file selected. to is happening because nsFileControlFrame::Reflow calls nsFileControlFrame::CropTextToWidth[*] to try and fit the displayed filename (or the "No file selected" placeholder value) into the available width (and the control has been given a narrow width here, so none of it actually fits).

So I think we need to look more closely at what UpdateDisplayedValue is doing; it seems to be leaving things in an inconsistent state in some way. Looking at nsFileControlFrame::Reflow, it actually uses it a couple of times: it calls UpdateDisplayedValue with the full filename in order to try reflowing it and see if it fits, and then if it didn't fit (as in this case), it calls CropTextToWidth which will use UpdateDisplayedValue again to reset it to the ellipsized version (or in this case just the lone ellipsis character).

I'm a bit suspicious the code at https://searchfox.org/mozilla-central/rev/443f87caa5fadba920b0382e12874693d6c6133a/layout/forms/nsFileControlFrame.cpp#567-578 might not be fixing everything up correctly, but haven't gone deeper into that yet....

[*] Incidentally, I notice that the measurement that nsFileControlFrame::CropTextToWidth is doing fails to account for the letter-spacing that is in effect, so that an example like

    data:text/html,<input type=file style="letter-spacing:4px; width:200px">

shows the "middle-cropping" happening in quite the wrong place, and the string visually truncated (on macOS, at least; values may need adjusting to show the effect on other platforms, depending on text sizing). But AFAICT, I don't think that's the root of the issue here, it's purely a visual error.

Flags: needinfo?(jfkthame)

The top stack frame is the same as in bug 1705228. I don't know if this is the same issue or not.

See Also: → 1705228

The issue here seems to arise because when we're reflowing the paginated preview, we use nsCSSFrameConstructor::ReplicateFixedFrames to replicate fixed-position frames that need to appear on the current page; within that function, we set the mCreatingExtraFrames flag on the constructor state. This prevents ConstructTextFrame calling SetPrimaryFrame on the content.

However, in the case of the (native anonymous) content of the file-control label, this leaves us with the content not having any reference to its primary frame, and therefore the code in nsFileControlFrame::UpdateDisplayValue that is supposed to tell the textframe about the change (which would flush its textrun) doesn't find the frame to notify. Then when we get to reflowing that textframe, it still has a textrun that supposedly covers 17 characters, but its content only has one. Boom.

So we need ConstructTextFrame to check if we're in native-anon content, and if so it should go ahead and call SetPrimaryFrame if the content doesn't yet have one, regardless of the mCreatingExtraFrames flag. That's taken care of for other frames in ConstructFrameFromItemInternal, but the textframe case doesn't go through there.

(In reply to Andrew McCreight [:mccr8] from comment #6)

The top stack frame is the same as in bug 1705228. I don't know if this is the same issue or not.

Yes, I expect that's the same: the stack there includes nsPageContentFrame::Reflow ... nsFileControlFrame::Reflow ... nsTextFrame::ReflowText, which looks like exactly the same scenario.

Assignee: nobody → jfkthame
Status: NEW → ASSIGNED

In my testing, the above patch fixes the crash for both the testcase here and the one in bug 1705228.

Comment on attachment 9222686 [details]
Bug 1711576 - Ensure we set the primary frame for native anon content where needed. r=dholbert

Beta/Release Uplift Approval Request

  • User impact if declined: Potential crash due to out-of-bounds access during print-preview of a page with specific types of content, or possibly minor mis-rendering if it doesn't crash.
  • Is this code covered by automated tests?: No
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: Yes
  • If yes, steps to reproduce: With print.tab_modal.enabled set to false, open the attached testcase on Linux and choose File/Print Preview. (May require an ASAN build to reliably crash.)
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Minimal patch that affects only very specific content scenario (file-input control, or other element that generates anonymous content including a text frame) within an out-of-flow element when document is being paginated.
  • String changes made/needed: n/a

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: Fixes a potential content-process crash issue
  • User impact if declined: Potential for crash during print-preview with very specific page content
  • Fix Landed on Version: 90
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): see above
  • String or UUID changes made by this patch:
Attachment #9222686 - Flags: approval-mozilla-esr78?
Attachment #9222686 - Flags: approval-mozilla-beta?
Flags: qe-verify+

:jfkthame, since this bug contains a bisection range, could you fill (if possible) the regressed_by field?
For more information, please visit auto_nag documentation.

Flags: needinfo?(jfkthame)

Ensure we set the primary frame for native anon content where needed. r=dholbert
https://hg.mozilla.org/integration/autoland/rev/d5cddd2fecd121067cd054d497921ab7fbca4bcb

(In reply to Release mgmt bot [:sylvestre / :calixte / :marco for bugbug] from comment #13)

:jfkthame, since this bug contains a bisection range, could you fill (if possible) the regressed_by field?
For more information, please visit auto_nag documentation.

I don't believe this is a regression; it was simply an obscure but longstanding bug. Per comment 3, the bisection just pointed to when the fuzzer gained the ability to reach this particular case.

Flags: needinfo?(jfkthame)
Group: layout-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 90 Branch

Comment on attachment 9222686 [details]
Bug 1711576 - Ensure we set the primary frame for native anon content where needed. r=dholbert

This is a sec-moderate and we are out of betas, I think this can ride the 90/78.12esr train, thanks.

Attachment #9222686 - Flags: approval-mozilla-esr78?
Attachment #9222686 - Flags: approval-mozilla-esr78-
Attachment #9222686 - Flags: approval-mozilla-beta?
Attachment #9222686 - Flags: approval-mozilla-beta-
Attachment #9222686 - Flags: approval-mozilla-esr78- → approval-mozilla-esr78?
Whiteboard: [bugmon:bisected,confirmed] → [bugmon:bisected,confirmed][post-critsmash-triage]

Bugmon Analysis:
Verified bug as fixed on rev mozilla-central 20210521095754-9d30cff8f9d4.
Removing bugmon keyword as no further action possible.
Please review the bug and re-add the keyword for further analysis.

Status: RESOLVED → VERIFIED
Keywords: bugmon

Removing the qe-verify+ flag, based on Comment 18.

Flags: qe-verify+

Comment on attachment 9222686 [details]
Bug 1711576 - Ensure we set the primary frame for native anon content where needed. r=dholbert

Approved for 78.12esr.

Attachment #9222686 - Flags: approval-mozilla-esr78? → approval-mozilla-esr78+
Whiteboard: [bugmon:bisected,confirmed][post-critsmash-triage] → [bugmon:bisected,confirmed][post-critsmash-triage][adv-main90+r]
Whiteboard: [bugmon:bisected,confirmed][post-critsmash-triage][adv-main90+r] → [bugmon:bisected,confirmed][post-critsmash-triage][adv-main90+r][adv-esr78.12+r]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: