Bug 1793534 - part 2: Make the accessibility module handle exposable URIs which do not contain user-pass section r=Jamie

We shouldn't expose the user-pass section of document URI to another apps since
it's sensitive data, but non-malicious a11y API users must not need it.

Additionally, `data` and `blob` URI may be too big (e.g., can be some mega
bytes) and they may need to allocate too big string multiple times in the heap
per URI.  Therefore, the accessibility module should stop handling URI as-is if
the document URI is one of them.

Differential Revision: https://phabricator.services.mozilla.com/D158735
This commit is contained in:
Masayuki Nakano 2022-10-06 10:04:45 +00:00
Родитель 31375f07bd
Коммит 6b389daaf1
5 изменённых файлов: 107 добавлений и 13 удалений

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsEventShell.h"
#include "nsIIOService.h"
#include "nsLayoutUtils.h"
#include "nsTextEquivUtils.h"
#include "Pivot.h"
@ -42,6 +43,7 @@
#include "nsTHashSet.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Components.h" // for mozilla::components
#include "mozilla/EditorBase.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/ipc/ProcessChild.h"
@ -341,15 +343,37 @@ already_AddRefed<EditorBase> DocAccessible::GetEditor() const {
// DocAccessible public method
void DocAccessible::URL(nsAString& aURL) const {
aURL.Truncate();
nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(container));
nsAutoCString theURL;
if (webNav) {
nsCOMPtr<nsIURI> pURI;
webNav->GetCurrentURI(getter_AddRefs(pURI));
if (pURI) pURI->GetSpec(theURL);
if (MOZ_UNLIKELY(!webNav)) {
return;
}
nsCOMPtr<nsIURI> uri;
webNav->GetCurrentURI(getter_AddRefs(uri));
if (MOZ_UNLIKELY(!uri)) {
return;
}
// Let's avoid treating too long URI in the main process for avoiding
// memory fragmentation as far as possible.
if (uri->SchemeIs("data") || uri->SchemeIs("blob")) {
return;
}
nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service();
if (NS_WARN_IF(!io)) {
return;
}
nsCOMPtr<nsIURI> exposableURI;
if (NS_FAILED(io->CreateExposableURI(uri, getter_AddRefs(exposableURI))) ||
MOZ_UNLIKELY(!exposableURI)) {
return;
}
nsAutoCString theURL;
if (NS_SUCCEEDED(exposableURI->GetSpec(theURL))) {
CopyUTF8toUTF16(theURL, aURL);
}
CopyUTF8toUTF16(theURL, aURL);
}
void DocAccessible::Title(nsString& aTitle) const {

Просмотреть файл

@ -7,6 +7,7 @@
#include "CachedTableAccessible.h"
#include "DocAccessibleParent.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/Components.h" // for mozilla::components
#include "mozilla/dom/BrowserBridgeParent.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
@ -14,6 +15,7 @@
#include "xpcAccessibleDocument.h"
#include "xpcAccEvents.h"
#include "nsAccUtils.h"
#include "nsIIOService.h"
#include "TextRange.h"
#include "RootAccessible.h"
@ -1290,12 +1292,26 @@ void DocAccessibleParent::URL(nsAString& aURL) const {
if (!mBrowsingContext) {
return;
}
nsAutoCString url;
nsCOMPtr<nsIURI> uri = mBrowsingContext->GetCurrentURI();
if (!uri) {
return;
}
uri->GetSpec(url);
// Let's avoid treating too long URI in the main process for avoiding
// memory fragmentation as far as possible.
if (uri->SchemeIs("data") || uri->SchemeIs("blob")) {
return;
}
nsCOMPtr<nsIIOService> io = mozilla::components::IO::Service();
if (NS_WARN_IF(!io)) {
return;
}
nsCOMPtr<nsIURI> exposableURI;
if (NS_FAILED(io->CreateExposableURI(uri, getter_AddRefs(exposableURI))) ||
MOZ_UNLIKELY(!exposableURI)) {
return;
}
nsAutoCString url;
exposableURI->GetSpec(url);
CopyUTF8toUTF16(url, aURL);
}

Просмотреть файл

@ -36,9 +36,7 @@ addAccessibleTask(`<title>webarea test</title>`, async (browser, accDoc) => {
// document, we'll get one AXLoadComplete event.
let eventPromise = Promise.race([
waitForMacEvent("AXLayoutComplete", (iface, data) => {
return (
iface.getAttributeValue("AXDescription") == "data:text/html,hello world"
);
return iface.getAttributeValue("AXDescription") == "iframe document";
}),
waitForMacEvent("AXLoadComplete", (iface, data) => {
return iface.getAttributeValue("AXDescription") == "webarea test";
@ -46,7 +44,7 @@ addAccessibleTask(`<title>webarea test</title>`, async (browser, accDoc) => {
]);
await SpecialPowers.spawn(browser, [], () => {
const iframe = content.document.createElement("iframe");
iframe.src = "data:text/html,hello world";
iframe.src = "data:text/html,<title>iframe document</title>hello world";
content.document.body.appendChild(iframe);
});
let doc = await eventPromise;
@ -67,7 +65,7 @@ addAccessibleTask(`<title>webarea test</title>`, async (browser, accDoc) => {
is(doc.getAttributeValue("AXTitle"), null, "iframe document has no AXTitle");
is(
doc.getAttributeValue("AXDescription"),
"data:text/html,hello world",
"iframe document",
"test has correct label"
);

Просмотреть файл

@ -12,3 +12,4 @@ skip-if = true || (verify && !debug && (os == 'linux')) #Bug 1445513
[browser_lazy_tabs.js]
[browser_searchbar.js]
[browser_shadowdom.js]
[browser_test_nsIAccessibleDocument_URL.js]

Просмотреть файл

@ -0,0 +1,55 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
async function promiseEventDocumentLoadComplete(expectedURL) {
return new Promise(resolve => {
waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, event => {
try {
if (
event.accessible.QueryInterface(nsIAccessibleDocument).URL ==
expectedURL
) {
resolve(event.accessible.QueryInterface(nsIAccessibleDocument));
return true;
}
return false;
} catch (e) {
return false;
}
});
});
}
add_task(async function testInDataURI() {
const kURL = "data:text/html,Some text";
const waitForDocumentLoadComplete = promiseEventDocumentLoadComplete("");
await BrowserTestUtils.withNewTab(kURL, async browser => {
is(
(await waitForDocumentLoadComplete).URL,
"",
"nsIAccessibleDocument.URL shouldn't return data URI"
);
});
});
add_task(async function testInHTTPSURIContainingPrivateThings() {
await SpecialPowers.pushPrefEnv({
set: [["network.auth.confirmAuth.enabled", false]],
});
const kURL =
"https://username:password@example.com/browser/toolkit/content/tests/browser/file_empty.html?query=some#ref";
const kURLWithoutUserPass =
"https://example.com/browser/toolkit/content/tests/browser/file_empty.html?query=some#ref";
const waitForDocumentLoadComplete = promiseEventDocumentLoadComplete(
kURLWithoutUserPass
);
await BrowserTestUtils.withNewTab(kURL, async browser => {
is(
(await waitForDocumentLoadComplete).URL,
kURLWithoutUserPass,
"nsIAccessibleDocument.URL shouldn't contain user/pass section"
);
});
});