Coordinated Disclosure Timeline
- 2020-07-22 Reported as Chromium Issue 1108299
- 2020-07-29 Origin trial ended and bug has no effect
- 2020-10-06 Fixed in version 86.0.4240.75
Summary
UaF in NFCHost::GetNFC
Product
Chrome
CVE
CVE-2020-15970
Tested Version
Tested on 2 settings:
- Pixel 3a XL emulator on Android 10 with master branch commit 79552e1
- Actual Pixel 3a device on Android 10 with stable version 84.0.4147.89
Details
In the GetNFC method of NFCHost, the NFCHost is passed into a callback as a raw pointer [1]:
// base::Unretained() is safe here because the subscription is canceled when
// this object is destroyed.
subscription_id_ = permission_controller_->SubscribePermissionStatusChange(
PermissionType::NFC, render_frame_host, origin_url,
base::BindRepeating(&NFCHost::OnPermissionStatusChange,
base::Unretained(this)));
As the comment suggested, when NFCHost is destroyed, it will cancel the subscription by calling the Close method:
NFCHost::~NFCHost() {
Close();
}
void NFCHost::Close() {
nfc_provider_.reset();
if (subscription_id_ != 0)
permission_controller_->UnsubscribePermissionStatusChange(subscription_id_);
}
However, this only unsubscribes the callback associated with the current subscription_id_. Every time GetNFC is called, a new subscription with a different subscription_id is created, all of them store the same NFCHost raw pointer in the callback, while subscription_id_ is being replaced. When NFCHost is destroyed, only the most recent subscription is cancelled, which leaves dangling pointers in previously subscribed callbacks. These callbacks will then be triggered when a permission for the website is changed, for example, by changing it in the site settings menu.
Note that although WebNFC is currently an experimental feature, it has an (origin trial that ends on July 29th)(https://developers.chrome.com/origintrials/#/view_trial/236438980436951041), so any website can request an origin trial token to trigger this bug with the default settings.
CVE
- CVE-2020-15970
Reproduction case
This issue requires some user interactions to reproduce, but does not require a compromised renderer. This also seems to only trigger if there is at least one other tab already opened.
First enable the #experimental-web-platform-features flag in chrome://flags and relaunch. As explained before, this is only needed to make testing easier. Any website could trigger this bug without this flag by requesting an origin trial token until the end of the trial period.
Host the attached nfc.html and nfc2.html on localhost and connect the Android device to the host machine.
Impact
Use-after-free in browser. Can be reached directly from a malicious website, but requires non trivial user interactions to trigger.
Credit
This issue was discovered and reported by GHSL team member @m-y-mo (Man Yue Mo).
Contact
You can contact the GHSL team at securitylab@github.com, please include the GHSL-2020-163 in any communication regarding this issue.
