Closed Bug 1868901 (CVE-2023-6863) Opened 7 months ago Closed 7 months ago

Undefined behavior in ShutdownObserver()

Categories

(Core :: Graphics, defect)

defect

Tracking

()

RESOLVED FIXED
122 Branch
Tracking Status
firefox-esr115 121+ fixed
firefox120 --- wontfix
firefox121 + fixed
firefox122 + fixed

People

(Reporter: mozillabugs, Assigned: aosmond)

Details

(Keywords: csectype-undefined, reporter-external, sec-low, Whiteboard: [adv-main121+][adv-esr115.6+])

Attachments

(2 files)

ShutdownObserver (widget/GfxInfoBase.cpp) invokes undefined behavior by deleting an object whose static type lacks a virtual destructor, where the object has a derived-class dynamic type. [1]

The issue concerns the three arrays in widget/GfxDriverInfo.h (line numbers are from trunk):

    351: static nsAString* sWindowProtocol[static_cast<size_t>(WindowProtocol::Max)];
    ...
    355: static nsAString* sDeviceVendors[static_cast<size_t>(DeviceVendor::Max)];
    ...
    358: static nsAString* sDriverVendors[static_cast<size_t>(DriverVendor::Max)];

These arrays' elements are assigned nsString* pointers by GfxDriverInfo::GetWindowProtocol(), GfxDriverInfo::GetDeviceVendor(), and GfxDriverInfo::GetDriverVendor(), respectively, e.g. from widget/GfxDriverInfo.cpp:

    602: const nsAString& GfxDriverInfo::GetWindowProtocol(WindowProtocol id) {
    ...
    613:  sWindowProtocol[idx] = new nsString();

and are deleted by ShutdownObserver::Observe() (widget/GfxInfoBase.cpp):

71: NS_IMETHOD Observe(nsISupports* subject, const char* aTopic,
72:                     const char16_t* aData) override {
...
83:    for (auto& windowProtocol : GfxDriverInfo::sWindowProtocol) {
84:      delete windowProtocol;
85:      windowProtocol = nullptr;
86:    }
87:
88:    for (auto& deviceVendor : GfxDriverInfo::sDeviceVendors) {
89:      delete deviceVendor;
90:      deviceVendor = nullptr;
91:    }
92:
93:    for (auto& driverVendor : GfxDriverInfo::sDriverVendors) {
94:      delete driverVendor;
95:      driverVendor = nullptr;
96:    }

But nsString is an alias for nsTString<char16_t>, which isa nsTSubstring<char16_t>. Whereas, nsAString is an alias for nsTSubstring<char16_t>. So the assignment is of a derived class pointer to a base class pointer. But the base class nsTSubstring<char16_t> lacks a virtual destructor, despite the quizzical comment from xpcom/string/nsTSubstring.h:

    325:  // this acts like a virtual destructor
    326:  ~nsTSubstring() { Finalize(); }

[1] See C++ 20 Standard (n4750) s.8.5.2.5(3) : "In a single-object delete expression, if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined."

Flags: sec-bounty?

This code is in the widget/ directory, but it looks like it is all about the graphics blocklist, so I'll move it to graphics.

Group: core-security → gfx-core-security
Component: Widget → Graphics

This seems easily solved by just using the actual type in the static variable declarations.

Assignee: nobody → aosmond
Status: NEW → ASSIGNED

While in general we pass around references to nsAString/nsACString, I don't think we normally store pointers to nsAString/nsACString requiring a delete after. Instead we generally use the nsString/nsCString/nsAutoString/nsAutoCString objects when declaring the actual storage.

Attached file Bug 1868901.

I'm going to assume this isn't particularly dangerous in practice.

Keywords: sec-low

Comment on attachment 9367662 [details]
Bug 1868901.

Beta/Release Uplift Approval Request

  • User impact if declined: Minor shutdown security issue
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): We just change the declaration to use the concrete derived class instead of the base class. Trivial change.
  • String changes made/needed:
  • Is Android affected?: Yes

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: Minor shutdown security issue
  • User impact if declined: Minor shutdown security issue
  • Fix Landed on Version: 122
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): We just change the declaration to use the concrete derived class instead of the base class. Trivial change.
Attachment #9367662 - Flags: approval-mozilla-esr115?
Attachment #9367662 - Flags: approval-mozilla-beta?
Group: gfx-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 7 months ago
Resolution: --- → FIXED
Target Milestone: --- → 122 Branch

Comment on attachment 9367662 [details]
Bug 1868901.

Approved for 121.0rc1 and 115.6esr.

Attachment #9367662 - Flags: approval-mozilla-esr115?
Attachment #9367662 - Flags: approval-mozilla-esr115+
Attachment #9367662 - Flags: approval-mozilla-beta?
Attachment #9367662 - Flags: approval-mozilla-beta+
Whiteboard: [adv-main121+]
Whiteboard: [adv-main121+] → [adv-main121+][adv-esr115.6+]
Attached file advisory.txt
QA Whiteboard: [post-critsmash-triage]
Flags: qe-verify-
Alias: CVE-2023-6863
Flags: sec-bounty? → sec-bounty+

Bulk-unhiding security bugs fixed in Firefox 119-121 (Fall 2023). Use "moo-doctrine-subsidy" to filter

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: