diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-07-31 13:49:43 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-05 09:06:37 +0000 |
commit | 989a5679948742873fa248c70f1b3fa85c9f5027 (patch) | |
tree | 56c0d1f62e443cf6245ddbf64fcbeba30fa57666 /chromium/third_party | |
parent | 687e6c44d85e93f8e789e5378779baa624900ba5 (diff) | |
download | qtwebengine-chromium-989a5679948742873fa248c70f1b3fa85c9f5027.tar.gz |
[Backport] Critical security issue 977057
[Merge to 76] Check AX cache if labelled before fetching labels
HTML labelable elements can cause extreme slowness while loading in some
cases. We should only call html_element->labels() if the current element
is known to have labels (we can check our relationship cache).
(cherry picked from commit b90d7299cdc96191d94e1ecfe1a4f82a625531f8)
Bug: 977057, 976849
Change-Id: Ia5e0e312b3a5e1d2d2d4cfdc5249f6a58b38147c
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: Nektarios Paisios <nektar@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#672099}
Reviewed-by: Katie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/branch-heads/3809@{#899}
Cr-Branched-From: d82dec1a818f378c464ba307ddd9c92133eac355-refs/heads/master@{#665002}
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/third_party')
5 files changed, 48 insertions, 5 deletions
diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 6f67e81f0b9..9399d5ee150 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc @@ -2631,7 +2631,9 @@ String AXNodeObject::NativeTextAlternative( name_sources->back().native_source = kAXTextFromNativeHTMLLabel; } - LabelsNodeList* labels = html_element->labels(); + LabelsNodeList* labels = nullptr; + if (AXObjectCache().MayHaveHTMLLabel(*html_element)) + labels = html_element->labels(); if (labels && labels->length() > 0) { HeapVector<Member<Element>> label_elements; for (unsigned label_index = 0; label_index < labels->length(); diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 1606304ac1c..1dd58539faa 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc @@ -894,6 +894,19 @@ void AXObjectCacheImpl::UpdateAriaOwns( relation_cache_->UpdateAriaOwns(owner, id_vector, owned_children); } +bool AXObjectCacheImpl::MayHaveHTMLLabel(const HTMLElement& elem) { + // Return false if this type of element will not accept a <label for> label. + if (!elem.IsLabelable()) + return false; + + // Return true if a <label for> pointed to this element at some point. + if (relation_cache_->MayHaveHTMLLabelViaForAttribute(elem)) + return true; + + // Return true if any amcestor is a label, as in <label><input></label>. + return Traversal<HTMLLabelElement>::FirstAncestor(elem); +} + void AXObjectCacheImpl::CheckedStateChanged(Node* node) { PostNotification(node, ax::mojom::Event::kCheckedStateChanged); } @@ -1191,7 +1204,8 @@ void AXObjectCacheImpl::HandleValidationMessageVisibilityChanged( } void AXObjectCacheImpl::LabelChanged(Element* element) { - TextChanged(ToHTMLLabelElement(element)->control()); + // Will call back to TextChanged() when done updating relation cache. + relation_cache_->LabelChanged(element); } void AXObjectCacheImpl::InlineTextBoxesUpdated( diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index 684b1f4713c..58c7639c3fd 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h @@ -221,6 +221,8 @@ class MODULES_EXPORT AXObjectCacheImpl const Vector<String>& id_vector, HeapVector<Member<AXObject>>& owned_children); + bool MayHaveHTMLLabel(const HTMLElement& elem); + // Synchronously returns whether or not we currently have permission to // call AOM event listeners. bool CanCallAOMEventListeners() const; diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index c587778440b..5c77eb092c3 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc @@ -9,6 +9,8 @@ namespace blink { +using namespace html_names; + AXRelationCache::AXRelationCache(AXObjectCacheImpl* object_cache) : object_cache_(object_cache) {} @@ -163,6 +165,14 @@ void AXRelationCache::UpdateAriaOwns( validated_owned_child_axids); } +bool AXRelationCache::MayHaveHTMLLabelViaForAttribute( + const HTMLElement& labelable) { + const AtomicString& id = labelable.GetIdAttribute(); + if (id.IsEmpty()) + return false; + return all_previously_seen_label_target_ids_.Contains(id); +} + // Fill source_objects with AXObjects for relations pointing to target. void AXRelationCache::GetReverseRelated( Node* target, @@ -257,8 +267,12 @@ void AXRelationCache::TextChanged(AXObject* object) { } void AXRelationCache::LabelChanged(Node* node) { - if (HTMLElement* control = ToHTMLLabelElement(node)->control()) - TextChanged(Get(control)); + const AtomicString& id = ToHTMLElement(node)->FastGetAttribute(kForAttr); + if (!id.IsEmpty()) { + all_previously_seen_label_target_ids_.insert(id); + if (HTMLElement* control = ToHTMLLabelElement(node)->control()) + TextChanged(Get(control)); + } } } // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h index 6c3af3d9bc4..c843dfe1d5e 100644 --- a/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h +++ b/chromium/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h @@ -35,6 +35,9 @@ class AXRelationCache { const Vector<String>& id_vector, HeapVector<Member<AXObject>>& owned_children); + // Return true if any label ever pointed to the element via the for attribute. + bool MayHaveHTMLLabelViaForAttribute(const HTMLElement&); + // Given an element in the DOM tree that was either just added or whose id // just changed, check to see if another object wants to be its parent due to // aria-owns. If so, update the tree by calling childrenChanged() on the @@ -51,6 +54,8 @@ class AXRelationCache { void UpdateReverseRelations(const AXObject* relation_source, const Vector<String>& target_ids); + void LabelChanged(Node*); + private: // If any object is related to this object via <label for>, aria-owns, // aria-describedby or aria-labeledby, update the text for the related object. @@ -87,13 +92,19 @@ class AXRelationCache { // and fire the appropriate change events. HashMap<String, HashSet<AXID>> id_attr_to_related_mapping_; + // HTML id attributes that at one time havehad a <label for> pointing to it. + // IDs are not necessarily removed from this set. It is not necessary to + // remove IDs as false positives are ok. Being able to determine that a + // labelable element has never had an associated label allows the accessible + // name calculation to be optimized. + HashSet<AtomicString> all_previously_seen_label_target_ids_; + // Helpers that call back into object cache AXObject* ObjectFromAXID(AXID) const; AXObject* GetOrCreate(Node*); AXObject* Get(Node*); void ChildrenChanged(AXObject*); void TextChanged(AXObject*); - void LabelChanged(Node*); DISALLOW_COPY_AND_ASSIGN(AXRelationCache); }; |