From 3887f79378a9445118ca2750b1093250df92aab1 Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Fri, 2 Feb 2024 18:48:47 +0000 Subject: [PATCH] Foxhound: propagate taint through atom attributes (e.g. id) --- dom/base/nsAttrValue.cpp | 19 +++++++++--- dom/base/nsAttrValue.h | 4 +++ dom/base/nsAttrValueInlines.h | 5 +-- taint/test/mochitest/test_dom.html | 50 ++++++++++++++++++++++++++---- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp index f8a87bb44f816..1051bcd5d4662 100644 --- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -246,7 +246,7 @@ void MiscContainer::Evict() { nsTArray* nsAttrValue::sEnumTableArray = nullptr; -nsAttrValue::nsAttrValue() : mBits(0) {} +nsAttrValue::nsAttrValue() : mBits(0), mTaint() {} nsAttrValue::nsAttrValue(const nsAttrValue& aOther) : mBits(0) { SetTo(aOther); @@ -306,7 +306,6 @@ void nsAttrValue::Reset() { case eAtomBase: { nsAtom* atom = GetAtomValue(); NS_RELEASE(atom); - break; } case eIntegerBase: { @@ -315,6 +314,7 @@ void nsAttrValue::Reset() { } mBits = 0; + mTaint.clear(); } void nsAttrValue::SetTo(const nsAttrValue& aOther) { @@ -340,6 +340,7 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) { nsAtom* atom = aOther.GetAtomValue(); NS_ADDREF(atom); SetPtrValueAndType(atom, eAtomBase); + mTaint = aOther.mTaint; return; } case eIntegerBase: { @@ -570,6 +571,10 @@ void nsAttrValue::SwapValueWith(nsAttrValue& aOther) { uintptr_t tmp = aOther.mBits; aOther.mBits = mBits; mBits = tmp; + // Swap Taint + SafeStringTaint taint = aOther.mTaint; + aOther.mTaint = mTaint; + mTaint = taint; } void nsAttrValue::RemoveDuplicatesFromAtomArray() { @@ -630,6 +635,7 @@ void nsAttrValue::ToString(nsAString& aResult) const { case eString: { nsStringBuffer* str = static_cast(GetPtr()); if (str) { + // Taint information propagated here automatically str->ToString(str->StorageSize() / sizeof(char16_t) - 1, aResult); } else { aResult.Truncate(); @@ -639,7 +645,7 @@ void nsAttrValue::ToString(nsAString& aResult) const { case eAtom: { nsAtom* atom = static_cast(GetPtr()); atom->ToString(aResult); - + aResult.AssignTaint(mTaint); break; } case eInteger: { @@ -1341,6 +1347,10 @@ void nsAttrValue::ParseAtom(const nsAString& aValue) { RefPtr atom = NS_Atomize(aValue); if (atom) { SetPtrValueAndType(atom.forget().take(), eAtomBase); + // Set Taint + if (aValue.Taint()) { + mTaint = aValue.Taint(); + } } } @@ -2130,8 +2140,9 @@ already_AddRefed nsAttrValue::GetStringBuffer( data[len] = char16_t(0); // TaintFox: propagate taint. - if (aValue.isTainted()) + if (aValue.isTainted()) { buf->AssignTaint(aValue.Taint()); + } return buf.forget(); } diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h index 4ef63c287f6a8..9b4e278a0ff58 100644 --- a/dom/base/nsAttrValue.h +++ b/dom/base/nsAttrValue.h @@ -556,6 +556,10 @@ class nsAttrValue { bool DoParseHTMLDimension(const nsAString& aInput, bool aEnsureNonzero); uintptr_t mBits; + + // This is used to track the taint labels of atoms and other types. + // For String attributes, the taint information is saved with the StringBuffer directly + StringTaint mTaint; }; inline const nsAttrValue& nsAttrValue::operator=(const nsAttrValue& aOther) { diff --git a/dom/base/nsAttrValueInlines.h b/dom/base/nsAttrValueInlines.h index b963b1922c4f4..f9c7382da800c 100644 --- a/dom/base/nsAttrValueInlines.h +++ b/dom/base/nsAttrValueInlines.h @@ -249,10 +249,9 @@ inline void nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const { case eString: { nsStringBuffer* str = static_cast(GetPtr()); if (str) { + // Taint information should be propagated here aResult.SetKnownLiveStringBuffer( str, str->StorageSize() / sizeof(char16_t) - 1); - // Propagate Taint Information - str->AssignTaint(aResult.Taint()); } // else aResult is already empty return; @@ -260,6 +259,8 @@ inline void nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const { case eAtom: { nsAtom* atom = static_cast(GetPtr()); aResult.SetKnownLiveAtom(atom, mozilla::dom::DOMString::eNullNotExpected); + // Propagate Taint information + aResult.AssignTaint(mTaint); break; } default: { diff --git a/taint/test/mochitest/test_dom.html b/taint/test/mochitest/test_dom.html index 6057c6fb8569b..ac1ea1e104c22 100644 --- a/taint/test/mochitest/test_dom.html +++ b/taint/test/mochitest/test_dom.html @@ -78,6 +78,33 @@ check_taint_source(tainted, "manual taint source"); }); + add_task(async function test_element_id_no_selector() { + var d = document.createElement("div"); + d.setAttribute("id", "div_31415"); + var tainted = d.getAttribute("id"); + + check_tainted(tainted); + check_taint_source(tainted, "element.attribute"); + }); + + add_task(async function test_element_id_no_selector_tainted() { + var d = document.createElement("div"); + d.setAttribute("id", String.tainted("hello_264376")); + var tainted = d.getAttribute("id"); + + check_tainted(tainted); + check_taint_source(tainted, "manual taint source"); + }); + + add_task(async function test_element_id_direct_no_selector_tainted() { + var d = document.createElement("div"); + d.setAttribute("id", String.tainted("hello_264376")); + var tainted = d.id; + + check_tainted(tainted); + check_taint_source(tainted, "manual taint source"); + }); + add_task(async function test_div_innerhtml_tainted() { var d = document.createElement("div"); d.innerHTML = String.tainted("
Content Here
"); @@ -87,12 +114,22 @@ check_taint_source(tainted, "manual taint source"); }); - add_task(async function test_div_by_id() { - var element = document.getElementById("content_by_id"); - var tainted = element.getAttribute("test"); + add_task(async function test_div_innerhtml_id_tainted() { + var d = document.createElement("div"); + d.innerHTML = String.tainted("
Content Here
"); + + var tainted = d.children[0].getAttribute("id"); check_tainted(tainted); - check_taint_source(tainted, "document.getElementById"); + check_taint_source(tainted, "manual taint source"); + }); + + add_task(async function test_div_by_id() { + var element = document.getElementById("content_by_id"); + var tainted = element.getAttribute("test"); + + check_tainted(tainted); + check_taint_source(tainted, "document.getElementById"); }); add_task(async function test_div_by_id_already_tainted() { @@ -153,8 +190,7 @@ let p = document.createElement("p"); container.appendChild(p); let span = document.createElement("span"); - span.innerHTML = String.tainted("
Content Here
"); - + span.innerHTML = String.tainted("
Content Here
"); p.after(span); check_tainted(container.outerHTML); @@ -172,6 +208,8 @@ check_tainted(container.outerHTML); check_taint_source(container.outerHTML, "manual taint source"); + + });