Commit message: None
CVE: CVE-2018-18337
CWE: CWE-416
Vulnerability description: Incorrect handling of stylesheets leading to a use after free in Blink in Google Chrome prior to 71.0.3578.80 allowed a remote attacker to potentially exploit heap corruption via a crafted HTML page.

Project: Chrome

bool HTMLLinkElement::Async() const {
  return FastHasAttribute(HTMLNames::asyncAttr);
}

Project: Chrome

HTMLLinkElement* HTMLLinkElement::Create(Document& document,
                                         const CreateElementFlags flags) {
  return new HTMLLinkElement(document, flags);
}

Project: Chrome

void HTMLLinkElement::DidSendDOMContentLoadedForLinkPrerender() {
  DispatchEvent(
      *Event::Create(EventTypeNames::webkitprerenderdomcontentloaded));
}

Project: Chrome

void HTMLLinkElement::DidSendLoadForLinkPrerender() {
  DispatchEvent(*Event::Create(EventTypeNames::webkitprerenderload));
}

Project: Chrome

void HTMLLinkElement::DidStartLinkPrerender() {
  DispatchEvent(*Event::Create(EventTypeNames::webkitprerenderstart));
}

Project: Chrome

void HTMLLinkElement::DidStopLinkPrerender() {
  DispatchEvent(*Event::Create(EventTypeNames::webkitprerenderstop));
}

Project: Chrome

void HTMLLinkElement::FinishParsingChildren() {
  created_by_parser_ = false;
  HTMLElement::FinishParsingChildren();
}

Project: Chrome

const HashSet<AtomicString>& HTMLLinkElement::GetCheckedAttributeNames() const {
  DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set, ({"href"}));
  return attribute_set;
}

Project: Chrome

IconType HTMLLinkElement::GetIconType() const {
  return rel_attribute_.GetIconType();
}

Project: Chrome

LinkImport* HTMLLinkElement::GetLinkImport() const {
  if (!link_ || link_->GetType() != LinkResource::kImport)
    return nullptr;
  return static_cast<LinkImport*>(link_.Get());
}

Project: Chrome

LinkStyle* HTMLLinkElement::GetLinkStyle() const {
  if (!link_ || link_->GetType() != LinkResource::kStyle)
    return nullptr;
  return static_cast<LinkStyle*>(link_.Get());
}

Project: Chrome

HTMLLinkElement::GetLoadingTaskRunner() {
  return GetDocument().GetTaskRunner(TaskType::kNetworking);
}

Project: Chrome

const AtomicString& HTMLLinkElement::GetType() const {
  return getAttribute(typeAttr);
}

Project: Chrome

inline HTMLLinkElement::HTMLLinkElement(Document& document,
                                        const CreateElementFlags flags)
    : HTMLElement(linkTag, document),
      link_loader_(LinkLoader::Create(this)),
      referrer_policy_(kReferrerPolicyDefault),
      sizes_(DOMTokenList::Create(*this, HTMLNames::sizesAttr)),
      rel_list_(RelList::Create(this)),
      created_by_parser_(flags.IsCreatedByParser()) {}

Project: Chrome

bool HTMLLinkElement::HasLegalLinkAttribute(const QualifiedName& name) const {
  return name == hrefAttr || HTMLElement::HasLegalLinkAttribute(name);
}

Project: Chrome

KURL HTMLLinkElement::Href() const {
  const String& url = getAttribute(hrefAttr);
  if (url.IsEmpty())
    return KURL();
  return GetDocument().CompleteURL(url);
}

Project: Chrome

const Vector<IntSize>& HTMLLinkElement::IconSizes() const {
  return icon_sizes_;
}

Project: Chrome

bool HTMLLinkElement::IsLinkCreatedByParser() {
  return IsCreatedByParser();
}

Project: Chrome

bool HTMLLinkElement::IsURLAttribute(const Attribute& attribute) const {
  return attribute.GetName().LocalName() == hrefAttr ||
         HTMLElement::IsURLAttribute(attribute);
}

Project: Chrome

void HTMLLinkElement::LinkLoaded() {
  DispatchEvent(*Event::Create(EventTypeNames::load));
}

Project: Chrome

void HTMLLinkElement::LinkLoadingErrored() {
  DispatchEvent(*Event::Create(EventTypeNames::error));
}

Project: Chrome

LinkResource* HTMLLinkElement::LinkResourceToProcess() {
  if (!ShouldLoadLink()) {
    if (GetLinkStyle() && GetLinkStyle()->HasSheet())
      return GetLinkStyle();
    return nullptr;
  }

  if (!link_) {
    if (rel_attribute_.IsImport() &&
        RuntimeEnabledFeatures::HTMLImportsEnabled()) {
      link_ = LinkImport::Create(this);
    } else if (rel_attribute_.IsManifest()) {
      link_ = LinkManifest::Create(this);
    } else {
      LinkStyle* link = LinkStyle::Create(this);
      if (FastHasAttribute(disabledAttr)) {
        UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
        link->SetDisabledState(true);
      }
      link_ = link;
    }
  }

  return link_.Get();
}

Project: Chrome

bool HTMLLinkElement::LoadLink(const LinkLoadParameters& params) {
  return link_loader_->LoadLink(params, GetDocument(),
                                NetworkHintsInterfaceImpl());
}

Project: Chrome

void HTMLLinkElement::LoadStylesheet(const LinkLoadParameters& params,
                                     const WTF::TextEncoding& charset,
                                     FetchParameters::DeferOption defer_option,
                                     ResourceClient* link_client) {
  return link_loader_->LoadStylesheet(params, localName(), charset,
                                      defer_option, GetDocument(), link_client);
}

Project: Chrome

void HTMLLinkElement::NotifyLoadedSheetAndAllCriticalSubresources(
    LoadedSheetErrorStatus error_status) {
  DCHECK(GetLinkStyle());
  GetLinkStyle()->NotifyLoadedSheetAndAllCriticalSubresources(error_status);
}

Project: Chrome

void HTMLLinkElement::ParseAttribute(
    const AttributeModificationParams& params) {
  const QualifiedName& name = params.name;
  const AtomicString& value = params.new_value;
  if (name == relAttr) {
    rel_attribute_ = LinkRelAttribute(value);
    if (rel_attribute_.IsImport()) {
      Deprecation::CountDeprecation(GetDocument(), WebFeature::kHTMLImports);
    }
    rel_list_->DidUpdateAttributeValue(params.old_value, value);
    Process();
  } else if (name == hrefAttr) {
    LogUpdateAttributeIfIsolatedWorldAndInDocument("link", params);
    Process();
  } else if (name == typeAttr) {
    type_ = value;
    Process();
  } else if (name == asAttr) {
    as_ = value;
    Process();
  } else if (name == referrerpolicyAttr) {
    if (!value.IsNull()) {
      SecurityPolicy::ReferrerPolicyFromString(
          value, kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy_);
      UseCounter::Count(GetDocument(),
                        WebFeature::kHTMLLinkElementReferrerPolicyAttribute);
    }
  } else if (name == sizesAttr) {
    sizes_->DidUpdateAttributeValue(params.old_value, value);
    WebVector<WebSize> web_icon_sizes =
        WebIconSizesParser::ParseIconSizes(value);
    icon_sizes_.resize(SafeCast<wtf_size_t>(web_icon_sizes.size()));
    for (wtf_size_t i = 0; i < icon_sizes_.size(); ++i)
      icon_sizes_[i] = web_icon_sizes[i];
    Process();
  } else if (name == mediaAttr) {
    media_ = value.DeprecatedLower();
    Process();
  } else if (name == scopeAttr) {
    scope_ = value;
    Process();
  } else if (name == integrityAttr) {
    integrity_ = value;
  } else if (name == importanceAttr &&
             RuntimeEnabledFeatures::PriorityHintsEnabled()) {
    importance_ = value;
  } else if (name == disabledAttr) {
    UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled);
    if (params.reason == AttributeModificationReason::kByParser)
      UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabledByParser);
    if (LinkStyle* link = GetLinkStyle())
      link->SetDisabledState(!value.IsNull());
  } else {
    if (name == titleAttr) {
      if (LinkStyle* link = GetLinkStyle())
        link->SetSheetTitle(value);
    }

    HTMLElement::ParseAttribute(params);
  }
}

Project: Chrome

void HTMLLinkElement::Process() {
  if (LinkResource* link = LinkResourceToProcess())
    link->Process();
}

Project: Chrome

const AtomicString& HTMLLinkElement::Rel() const {
  return getAttribute(relAttr);
}

Project: Chrome

void HTMLLinkElement::ScheduleEvent() {
  GetDocument()
      .GetTaskRunner(TaskType::kDOMManipulation)
      ->PostTask(FROM_HERE,
                 WTF::Bind(&HTMLLinkElement::DispatchPendingEvent,
                           WrapPersistent(this),
                           WTF::Passed(IncrementLoadEventDelayCount::Create(
                               GetDocument()))));
}

Project: Chrome

bool HTMLLinkElement::SheetLoaded() {
  DCHECK(GetLinkStyle());
  return GetLinkStyle()->SheetLoaded();
}

Project: Chrome

bool HTMLLinkElement::ShouldLoadLink() {
  const KURL& href = GetNonEmptyURLAttribute(hrefAttr);
  return (IsInDocumentTree() ||
          (isConnected() && rel_attribute_.IsStyleSheet())) &&
         !href.PotentiallyDanglingMarkup();
}

Project: Chrome

bool HTMLLinkElement::StyleSheetIsLoading() const {
  return GetLinkStyle() && GetLinkStyle()->StyleSheetIsLoading();
}

Project: Chrome

const QualifiedName& HTMLLinkElement::SubResourceAttributeName() const {
  if (DeprecatedEqualIgnoringCase(getAttribute(typeAttr), "text/css")) {
    return hrefAttr;
  }
  return HTMLElement::SubResourceAttributeName();
}

Project: Chrome

void HTMLLinkElement::Trace(blink::Visitor* visitor) {
  visitor->Trace(link_);
  visitor->Trace(sizes_);
  visitor->Trace(link_loader_);
  visitor->Trace(rel_list_);
  HTMLElement::Trace(visitor);
  LinkLoaderClient::Trace(visitor);
}

Project: Chrome

Document* HTMLLinkElement::import() const {
  if (LinkImport* link = GetLinkImport())
    return link->ImportedDocument();
  return nullptr;
}

Project: Chrome

DOMTokenList* HTMLLinkElement::sizes() const {
  return sizes_.Get();
}