diff options
author | Gaming4JC <g4jc@bulletmail.org> | 2018-09-25 23:03:28 -0400 |
---|---|---|
committer | Gaming4JC <g4jc@bulletmail.org> | 2018-09-25 23:03:28 -0400 |
commit | c5c9445e3adf6b65c98f6810551d7c3d64133134 (patch) | |
tree | cf7aa42302515fe1792fd9c3230c6fd7ae3325fc /netwerk/protocol/http/nsHttpHeaderArray.h | |
parent | e3508f55bed8a463d298021633dbc7d079c9d764 (diff) | |
download | UXP-c5c9445e3adf6b65c98f6810551d7c3d64133134.tar UXP-c5c9445e3adf6b65c98f6810551d7c3d64133134.tar.gz UXP-c5c9445e3adf6b65c98f6810551d7c3d64133134.tar.lz UXP-c5c9445e3adf6b65c98f6810551d7c3d64133134.tar.xz UXP-c5c9445e3adf6b65c98f6810551d7c3d64133134.zip |
backport mozbug 1334776 - CVE-2017-7797 Header name interning leaks across origins
Potential attack: session supercookie.
[Moz Notes](https://bugzilla.mozilla.org/show_bug.cgi?id=1334776#c5):
"The problem is that for unknown header names we store the first one we see and then later we case-insensitively match against that name *globally*. That means you can track if a user agent has already seen a certain header name used (by using a different casing and observing whether it gets normalized). This would allow you to see if a user has used a sensitive service that uses custom header names, or allows you to track a user across sites, by teaching the browser about a certain header case once and then observing if different casings get normalized to that.
What we should do instead is only store the casing for a header name for each header list and not globally. That way it only leaks where it's expected (and necessary) to leak."
[Moz fix note](https://bugzilla.mozilla.org/show_bug.cgi?id=1334776#c8):
"nsHttpAtom now holds the old nsHttpAtom and a string that is case sensitive (only for not standard headers).
So nsHttpAtom holds a pointer to a header name. (header names are store on a static structure). This is how it used to be. I left that part the same but added a nsCString which holds a string that was used to resoled the header name. So when we parse headers we call ResolveHeader with a char*. If it is a new header name the char* will be stored in a HttpHeapAtom, nsHttpAtom::_val will point to HttpHeapAtom::value and the same strings will be stored in mLocalCaseSensitiveHeader. For the first resolve request they will be the same but for the following maybe not. At the end this nsHttpAtom will be stored in nsHttpHeaderArray. For all operation we will used the old char* except when we are returning it to a script using VisitHeaders."
Diffstat (limited to 'netwerk/protocol/http/nsHttpHeaderArray.h')
-rw-r--r-- | netwerk/protocol/http/nsHttpHeaderArray.h | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/netwerk/protocol/http/nsHttpHeaderArray.h b/netwerk/protocol/http/nsHttpHeaderArray.h index 91b91f04a..3ffdfa814 100644 --- a/netwerk/protocol/http/nsHttpHeaderArray.h +++ b/netwerk/protocol/http/nsHttpHeaderArray.h @@ -49,19 +49,30 @@ public: }; // Used by internal setters: to set header from network use SetHeaderFromNet + nsresult SetHeader(const nsACString &headerName, + const nsACString &value, + bool merge, HeaderVariety variety); nsresult SetHeader(nsHttpAtom header, const nsACString &value, bool merge, HeaderVariety variety); + nsresult SetHeader(nsHttpAtom header, + const nsACString &headerName, + const nsACString &value, + bool merge, HeaderVariety variety); // Used by internal setters to set an empty header - nsresult SetEmptyHeader(nsHttpAtom header, HeaderVariety variety); + nsresult SetEmptyHeader(const nsACString &headerName, HeaderVariety variety); // Merges supported headers. For other duplicate values, determines if error // needs to be thrown or 1st value kept. // For the response header we keep the original headers as well. - nsresult SetHeaderFromNet(nsHttpAtom header, const nsACString &value, + nsresult SetHeaderFromNet(nsHttpAtom header, + const nsACString &headerNameOriginal, + const nsACString &value, bool response); - nsresult SetResponseHeaderFromCache(nsHttpAtom header, const nsACString &value, + nsresult SetResponseHeaderFromCache(nsHttpAtom header, + const nsACString &headerNameOriginal, + const nsACString &value, HeaderVariety variety); nsresult GetHeader(nsHttpAtom header, nsACString &value) const; @@ -97,15 +108,17 @@ public: // parse a header line, return the header atom and a pointer to the // header value (the substring of the header line -- do not free). static nsresult ParseHeaderLine(const nsACString& line, - nsHttpAtom *header=nullptr, - nsACString* value=nullptr); + nsHttpAtom *header = nullptr, + nsACString *headerNameOriginal = nullptr, + nsACString *value = nullptr); void Flatten(nsACString &, bool pruneProxyHeaders, bool pruneTransients); void FlattenOriginalHeader(nsACString &); uint32_t Count() const { return mHeaders.Length(); } - const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header) const; + const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header, + nsACString &headerNameOriginal) const; void Clear(); @@ -113,6 +126,7 @@ public: struct nsEntry { nsHttpAtom header; + nsCString headerNameOriginal; nsCString value; HeaderVariety variety = eVarietyUnknown; @@ -140,7 +154,9 @@ private: int32_t LookupEntry(nsHttpAtom header, nsEntry **); nsresult MergeHeader(nsHttpAtom header, nsEntry *entry, const nsACString &value, HeaderVariety variety); - nsresult SetHeader_internal(nsHttpAtom header, const nsACString &value, + nsresult SetHeader_internal(nsHttpAtom header, + const nsACString &headerName, + const nsACString &value, HeaderVariety variety); // Header cannot be merged: only one value possible @@ -257,7 +273,11 @@ nsHttpHeaderArray::MergeHeader(nsHttpAtom header, if (entry->variety == eVarietyResponseNetOriginalAndResponse) { MOZ_ASSERT(variety == eVarietyResponse); entry->variety = eVarietyResponseNetOriginal; - nsresult rv = SetHeader_internal(header, newValue, eVarietyResponse); + // Copy entry->headerNameOriginal because in SetHeader_internal we are going + // to a new one and a realocation can happen. + nsCString headerNameOriginal = entry->headerNameOriginal; + nsresult rv = SetHeader_internal(header, headerNameOriginal, + newValue, eVarietyResponse); if (NS_FAILED(rv)) { return rv; } |