diff options
-rw-r--r-- | dom/base/nsContentUtils.cpp | 117 | ||||
-rw-r--r-- | dom/base/nsContentUtils.h | 35 | ||||
-rw-r--r-- | dom/fetch/InternalHeaders.cpp | 193 | ||||
-rw-r--r-- | dom/fetch/InternalHeaders.h | 18 | ||||
-rw-r--r-- | dom/xhr/XMLHttpRequestMainThread.cpp | 7 | ||||
-rw-r--r-- | netwerk/base/nsNetUtil.cpp | 6 | ||||
-rw-r--r-- | netwerk/base/nsNetUtil.h | 5 | ||||
-rw-r--r-- | netwerk/protocol/http/nsHttp.cpp | 12 | ||||
-rw-r--r-- | netwerk/protocol/http/nsHttp.h | 4 | ||||
-rw-r--r-- | netwerk/protocol/websocket/WebSocketChannel.cpp | 10 | ||||
-rw-r--r-- | netwerk/system/mac/nsNetworkLinkService.mm | 6 | ||||
-rw-r--r-- | xpcom/io/nsLocalFileUnix.cpp | 14 |
12 files changed, 390 insertions, 37 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index fa8ba6d97d..55bcf473e0 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7056,16 +7056,26 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent) // static bool -nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader) +nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader, + const nsACString& aValue) { if (IsForbiddenSystemRequestHeader(aHeader)) { return true; } + + if ((nsContentUtils::IsOverrideMethodHeader(aHeader) && + nsContentUtils::ContainsForbiddenMethod(aValue))) { + return true; + } - return StringBeginsWith(aHeader, NS_LITERAL_CSTRING("proxy-"), - nsCaseInsensitiveCStringComparator()) || - StringBeginsWith(aHeader, NS_LITERAL_CSTRING("sec-"), - nsCaseInsensitiveCStringComparator()); + if (StringBeginsWith(aHeader, NS_LITERAL_CSTRING("proxy-"), + nsCaseInsensitiveCStringComparator()) || + StringBeginsWith(aHeader, NS_LITERAL_CSTRING("sec-"), + nsCaseInsensitiveCStringComparator())) { + return true; + } + + return false; } // static @@ -7094,6 +7104,64 @@ nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) aHeader.LowerCaseEqualsASCII("set-cookie2")); } +// static +bool +nsContentUtils::IsOverrideMethodHeader(const nsACString& headerName) { + return headerName.LowerCaseEqualsASCII("x-http-method-override") || + headerName.LowerCaseEqualsASCII("x-http-method") || + headerName.LowerCaseEqualsASCII("x-method-override"); +} + +// static +bool +nsContentUtils::ContainsForbiddenMethod(const nsACString& headerValue) { + bool hasInsecureMethod = false; + nsCCharSeparatedTokenizer tokenizer(headerValue, ','); + + while (tokenizer.hasMoreTokens()) { + const nsDependentCSubstring& value = tokenizer.nextToken(); + + if (value.LowerCaseEqualsASCII("connect") || + value.LowerCaseEqualsASCII("trace") || + value.LowerCaseEqualsASCII("track")) { + hasInsecureMethod = true; + break; + } + } + + return hasInsecureMethod; +} + +// static +bool nsContentUtils::IsCorsUnsafeRequestHeaderValue( + const nsACString& aHeaderValue) { + const char* cur = aHeaderValue.BeginReading(); + const char* end = aHeaderValue.EndReading(); + + while (cur != end) { + // Implementation of + // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less + // than a space but not a horizontal tab + if ((*cur < ' ' && *cur != '\t') || *cur == '"' || *cur == '(' || + *cur == ')' || *cur == ':' || *cur == '<' || *cur == '>' || + *cur == '?' || *cur == '@' || *cur == '[' || *cur == '\\' || + *cur == ']' || *cur == '{' || *cur == '}' || + *cur == 0x7F) { // 0x75 is DEL + return true; + } + cur++; + } + return false; +} + +// static +bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString& aHeaderValue) { + if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) { + return false; + } + return true; +} + // static bool nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue) @@ -7101,6 +7169,10 @@ nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue) nsAutoCString contentType; nsAutoCString unused; + if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) { + return false; + } + nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused); if (NS_FAILED(rv)) { return false; @@ -7111,6 +7183,41 @@ nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue) contentType.LowerCaseEqualsLiteral("multipart/form-data"); } +// static +bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString& aHeaderValue) { + const char* cur = aHeaderValue.BeginReading(); + const char* end = aHeaderValue.EndReading(); + + while (cur != end) { + if ((*cur >= '0' && *cur <= '9') || (*cur >= 'A' && *cur <= 'Z') || + (*cur >= 'a' && *cur <= 'z') || *cur == ' ' || *cur == '*' || + *cur == ',' || *cur == '-' || *cur == '.' || *cur == ';' || + *cur == '=') { + cur++; + continue; + } + return false; + } + return true; +} + +// static +bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString& aName, + const nsACString& aValue) { + // See https://fetch.spec.whatwg.org/#cors-safelisted-request-header + if (aValue.Length() > 128) { + return false; + } + return (aName.LowerCaseEqualsLiteral("accept") && + nsContentUtils::IsAllowedNonCorsAccept(aValue)) || + (aName.LowerCaseEqualsLiteral("accept-language") && + nsContentUtils::IsAllowedNonCorsLanguage(aValue)) || + (aName.LowerCaseEqualsLiteral("content-language") && + nsContentUtils::IsAllowedNonCorsLanguage(aValue)) || + (aName.LowerCaseEqualsLiteral("content-type") && + nsContentUtils::IsAllowedNonCorsContentType(aValue)); +} + bool nsContentUtils::DOMWindowDumpEnabled() { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 5c9d12a684..3393a30c5c 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2425,7 +2425,8 @@ public: * Returns whether a given header is forbidden for an XHR or fetch * request. */ - static bool IsForbiddenRequestHeader(const nsACString& aHeader); + static bool IsForbiddenRequestHeader(const nsACString& aHeader, + const nsACString& aValue); /** * Returns whether a given header is forbidden for a system XHR @@ -2434,18 +2435,50 @@ public: static bool IsForbiddenSystemRequestHeader(const nsACString& aHeader); /** + * Returns whether a given header has characters that aren't permitted + */ + static bool IsCorsUnsafeRequestHeaderValue(const nsACString& aHeaderValue); + + /** + * Returns whether a given Accept header value is allowed + * for a non-CORS XHR or fetch request. + */ + static bool IsAllowedNonCorsAccept(const nsACString& aHeaderValue); + + /** * Returns whether a given Content-Type header value is allowed * for a non-CORS XHR or fetch request. */ static bool IsAllowedNonCorsContentType(const nsACString& aHeaderValue); /** + * Returns whether a given Content-Language or accept-language header value is + * allowed for a non-CORS XHR or fetch request. + */ + static bool IsAllowedNonCorsLanguage(const nsACString& aHeaderValue); + + /** + * Returns whether a given header and value is a CORS-safelisted request + * header per https://fetch.spec.whatwg.org/#cors-safelisted-request-header + */ + static bool IsCORSSafelistedRequestHeader(const nsACString& aName, + const nsACString& aValue); + + /** * Returns whether a given header is forbidden for an XHR or fetch * response. */ static bool IsForbiddenResponseHeader(const nsACString& aHeader); /** + * Checks whether the header overrides any http methods + */ + static bool IsOverrideMethodHeader(const nsACString& headerName); + /** + * Checks whether the header value contains any forbidden method + */ + static bool ContainsForbiddenMethod(const nsACString& headerValue); + /** * Returns the inner window ID for the window associated with a request, */ static uint64_t GetInnerWindowID(nsIRequest* aRequest); diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp index 0448d84731..f4851b7064 100644 --- a/dom/fetch/InternalHeaders.cpp +++ b/dom/fetch/InternalHeaders.cpp @@ -5,6 +5,7 @@ #include "mozilla/dom/InternalHeaders.h" +#include "FetchUtil.h" #include "mozilla/dom/FetchTypes.h" #include "mozilla/ErrorResult.h" @@ -46,20 +47,112 @@ InternalHeaders::ToIPC(nsTArray<HeadersEntry>& aIPCHeaders, } } +bool +InternalHeaders::IsValidHeaderValue(const nsCString& aLowerName, + const nsCString& aNormalizedValue, + ErrorResult& aRv) { + // Steps 2 to 6 for ::Set() and ::Append() in the spec. + + // Step 2 + if (IsInvalidName(aLowerName, aRv) || IsInvalidValue(aNormalizedValue, aRv)) { + return false; + } + + // Step 3 + if (IsImmutable(aRv)) { + return false; + } + + // Step 4 + if (mGuard == HeadersGuardEnum::Request) { + if (IsForbiddenRequestHeader(aLowerName, aNormalizedValue)) { + return false; + } + } + + // Step 5 + if (mGuard == HeadersGuardEnum::Request_no_cors) { + nsAutoCString tempValue; + Get(aLowerName, tempValue, aRv); + + if (tempValue.IsVoid()) { + tempValue = aNormalizedValue; + } else { + tempValue.Append(", "); + tempValue.Append(aNormalizedValue); + } + + if (!nsContentUtils::IsCORSSafelistedRequestHeader(aLowerName, tempValue)) { + return false; + } + } + + // Step 6 + else if (IsForbiddenResponseHeader(aLowerName)) { + return false; + } + + return true; +} + void InternalHeaders::Append(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) { + // Step 1 + nsAutoCString trimValue; + NS_TrimHTTPWhitespace(aValue, trimValue); + + // Steps 2 to 6 nsAutoCString lowerName; ToLowerCase(aName, lowerName); - - if (IsInvalidMutableHeader(lowerName, aValue, aRv)) { + if (!IsValidHeaderValue(lowerName, trimValue, aRv)) { return; } + // Step 7 SetListDirty(); - mList.AppendElement(Entry(lowerName, aValue)); + + // Step 8 + if (mGuard == HeadersGuardEnum::Request_no_cors) { + RemovePrivilegedNoCorsRequestHeaders(); + } +} + +void InternalHeaders::RemovePrivilegedNoCorsRequestHeaders() { + bool dirty = false; + + // remove in reverse order to minimize copying + for (int32_t i = mList.Length() - 1; i >= 0; --i) { + if (IsPrivilegedNoCorsRequestHeaderName(mList[i].mName)) { + mList.RemoveElementAt(i); + dirty = true; + } + } + + if (dirty) { + SetListDirty(); + } +} + +bool InternalHeaders::DeleteInternal(const nsCString& aLowerName, + ErrorResult& aRv) { + bool dirty = false; + + // remove in reverse order to minimize copying + for (int32_t i = mList.Length() - 1; i >= 0; --i) { + if (mList[i].mName.EqualsIgnoreCase(aLowerName.get())) { + mList.RemoveElementAt(i); + dirty = true; + } + } + + if (dirty) { + SetListDirty(); + } + + return dirty; } void @@ -68,17 +161,43 @@ InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv) nsAutoCString lowerName; ToLowerCase(aName, lowerName); - if (IsInvalidMutableHeader(lowerName, aRv)) { + // Step 1 + if (IsInvalidName(lowerName, aRv)) { return; } - SetListDirty(); + // Step 2 + if (IsImmutable(aRv)) { + return; + } - // remove in reverse order to minimize copying - for (int32_t i = mList.Length() - 1; i >= 0; --i) { - if (lowerName == mList[i].mName) { - mList.RemoveElementAt(i); - } + // Step 3 + nsAutoCString value; + GetInternal(lowerName, value, aRv); + if (IsForbiddenRequestHeader(lowerName, value)) { + return; + } + + // Step 4 + if (mGuard == HeadersGuardEnum::Request_no_cors && + !IsNoCorsSafelistedRequestHeaderName(lowerName) && + !IsPrivilegedNoCorsRequestHeaderName(lowerName)) { + return; + } + + // Step 5 + if (IsForbiddenResponseHeader(lowerName)) { + return; + } + + // Steps 6 and 7 + if (!DeleteInternal(lowerName, aRv)) { + return; + } + + // Step 8 + if (mGuard == HeadersGuardEnum::Request_no_cors) { + RemovePrivilegedNoCorsRequestHeaders(); } } @@ -91,12 +210,18 @@ InternalHeaders::Get(const nsACString& aName, nsACString& aValue, ErrorResult& a if (IsInvalidName(lowerName, aRv)) { return; } + GetInternal(lowerName, aValue, aRv); +} +void +InternalHeaders::GetInternal(const nsCString& aLowerName, + nsACString& aValue, + ErrorResult& aRv) const { const char* delimiter = ","; bool firstValueFound = false; for (uint32_t i = 0; i < mList.Length(); ++i) { - if (lowerName == mList[i].mName) { + if (aLowerName == mList[i].mName) { if (firstValueFound) { aValue += delimiter; } @@ -153,13 +278,18 @@ InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const void InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) { + // Step 1 + nsAutoCString trimValue; + NS_TrimHTTPWhitespace(aValue, trimValue); + + // Steps 2 to 6 nsAutoCString lowerName; ToLowerCase(aName, lowerName); - - if (IsInvalidMutableHeader(lowerName, aValue, aRv)) { + if (!IsValidHeaderValue(lowerName, trimValue, aRv)) { return; } + // Step 7 SetListDirty(); int32_t firstIndex = INT32_MAX; @@ -179,6 +309,11 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes } else { mList.AppendElement(Entry(lowerName, aValue)); } + + // Step 8 + if (mGuard == HeadersGuardEnum::Request_no_cors) { + RemovePrivilegedNoCorsRequestHeaders(); + } } void @@ -202,14 +337,33 @@ InternalHeaders::~InternalHeaders() // static bool +InternalHeaders::IsNoCorsSafelistedRequestHeaderName(const nsCString& aName) { + return aName.EqualsIgnoreCase("accept") || + aName.EqualsIgnoreCase("accept-language") || + aName.EqualsIgnoreCase("content-language") || + aName.EqualsIgnoreCase("content-type"); +} + +// static +bool +InternalHeaders::IsPrivilegedNoCorsRequestHeaderName( + const nsCString& aName) { + return aName.EqualsIgnoreCase("range"); +} + +// static +bool InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue) { // Note, we must allow a null content-type value here to support // get("content-type"), but the IsInvalidValue() check will prevent null // from being set or appended. - return aName.EqualsLiteral("accept") || - aName.EqualsLiteral("accept-language") || - aName.EqualsLiteral("content-language") || + return (aName.EqualsLiteral("accept") && + nsContentUtils::IsAllowedNonCorsAccept(aValue)) || + (aName.EqualsLiteral("accept-language") && + nsContentUtils::IsAllowedNonCorsLanguage(aValue))|| + (aName.EqualsLiteral("content-language") && + nsContentUtils::IsAllowedNonCorsLanguage(aValue))|| (aName.EqualsLiteral("content-type") && nsContentUtils::IsAllowedNonCorsContentType(aValue)); } @@ -261,10 +415,11 @@ InternalHeaders::IsImmutable(ErrorResult& aRv) const } bool -InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const +InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName, + const nsACString& aValue) const { return mGuard == HeadersGuardEnum::Request && - nsContentUtils::IsForbiddenRequestHeader(aName); + nsContentUtils::IsForbiddenRequestHeader(aName, aValue); } bool @@ -370,7 +525,7 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders, RequestCredentials aCred ErrorResult result; nsAutoCString acExposedNames; - aHeaders->GetFirst(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result); + aHeaders->Get(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result); MOZ_ASSERT(!result.Failed()); bool allowAllHeaders = false; diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h index ae9f2811a2..0a6996ab38 100644 --- a/dom/fetch/InternalHeaders.h +++ b/dom/fetch/InternalHeaders.h @@ -136,8 +136,11 @@ private: static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv); static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv); + bool IsValidHeaderValue(const nsCString& aLowerName, + const nsCString& aNormalizedValue, ErrorResult& aRv); bool IsImmutable(ErrorResult& aRv) const; - bool IsForbiddenRequestHeader(const nsACString& aName) const; + bool IsForbiddenRequestHeader(const nsACString& aName, + const nsACString& aValue) const; bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const; bool IsForbiddenRequestNoCorsHeader(const nsACString& aName, const nsACString& aValue) const; @@ -156,11 +159,22 @@ private: return IsInvalidName(aName, aRv) || IsInvalidValue(aValue, aRv) || IsImmutable(aRv) || - IsForbiddenRequestHeader(aName) || + IsForbiddenRequestHeader(aName, aValue) || IsForbiddenRequestNoCorsHeader(aName, aValue) || IsForbiddenResponseHeader(aName); } + void RemovePrivilegedNoCorsRequestHeaders(); + + void GetInternal(const nsCString& aLowerName, nsACString& aValue, + ErrorResult& aRv) const; + + bool DeleteInternal(const nsCString& aLowerName, ErrorResult& aRv); + + static bool IsNoCorsSafelistedRequestHeaderName(const nsCString& aName); + + static bool IsPrivilegedNoCorsRequestHeaderName(const nsCString& aName); + static bool IsSimpleHeader(const nsACString& aName, const nsACString& aValue); diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index d99747e2b7..80875383a9 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -3070,9 +3070,8 @@ XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName, } // Step 3 - nsAutoCString value(aValue); - static const char kHTTPWhitespace[] = "\n\t\r "; - value.Trim(kHTTPWhitespace); + nsAutoCString value; + NS_TrimHTTPWhitespace(aValue, value); // Step 4 if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) { @@ -3081,7 +3080,7 @@ XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName, // Step 5 bool isPrivilegedCaller = IsSystemXHR(); - bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName); + bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName, aValue); if (!isPrivilegedCaller && isForbiddenHeader) { NS_ConvertUTF8toUTF16 name(aName); const char16_t* params[] = { name.get() }; diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index ac6f620336..b9ec64ef84 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -520,6 +520,12 @@ bool NS_IsValidHTTPToken(const nsACString &aToken) return mozilla::net::nsHttp::IsValidToken(aToken); } +void +NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) +{ + mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest); +} + nsresult NS_NewLoadGroup(nsILoadGroup **aResult, nsIPrincipal *aPrincipal) { diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index bd89ca8aeb..385f2c968e 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -960,6 +960,11 @@ bool NS_IsReasonableHTTPHeaderValue(const nsACString &aValue); bool NS_IsValidHTTPToken(const nsACString &aToken); /** + * Strip the leading or trailing HTTP whitespace per fetch spec section 2.2. + */ +void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest); + +/** * Return true if the given request must be upgraded to HTTPS. */ nsresult NS_ShouldSecureUpgrade(nsIURI* aURI, diff --git a/netwerk/protocol/http/nsHttp.cpp b/netwerk/protocol/http/nsHttp.cpp index faf9e21ffd..88022835e3 100644 --- a/netwerk/protocol/http/nsHttp.cpp +++ b/netwerk/protocol/http/nsHttp.cpp @@ -246,6 +246,18 @@ nsHttp::GetProtocolVersion(uint32_t pv) } // static +void +nsHttp::TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest) +{ + nsAutoCString str(aSource); + + // HTTP whitespace 0x09: '\t', 0x0A: '\n', 0x0D: '\r', 0x20: ' ' + static const char kHTTPWhitespace[] = "\t\n\r "; + str.Trim(kHTTPWhitespace); + aDest.Assign(str); +} + +// static bool nsHttp::IsReasonableHeaderValue(const nsACString &s) { diff --git a/netwerk/protocol/http/nsHttp.h b/netwerk/protocol/http/nsHttp.h index a20637808a..b8fee97079 100644 --- a/netwerk/protocol/http/nsHttp.h +++ b/netwerk/protocol/http/nsHttp.h @@ -148,6 +148,10 @@ struct nsHttp static inline bool IsValidToken(const nsACString &s) { return IsValidToken(s.BeginReading(), s.EndReading()); } + + // Strip the leading or trailing HTTP whitespace per fetch spec section 2.2. + static void TrimHTTPWhitespace(const nsACString& aSource, + nsACString& aDest); // Returns true if the specified value is reasonable given the defintion // in RFC 2616 section 4.2. Full strict validation is not performed diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index f94c1d9ca9..679252500f 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -2313,6 +2313,16 @@ WebSocketChannel::CleanupConnection() { LOG(("WebSocketChannel::CleanupConnection() %p", this)); + // This should run on the Socket Thread to prevent potential races. + bool onSocketThread; + nsresult rv = mSocketThread->IsOnCurrentThread(&onSocketThread); + if (NS_SUCCEEDED(rv) && !onSocketThread) { + mSocketThread->Dispatch( + NewRunnableMethod(this, &WebSocketChannel::CleanupConnection), + NS_DISPATCH_NORMAL); + return; + } + if (mLingeringCloseTimer) { mLingeringCloseTimer->Cancel(); mLingeringCloseTimer = nullptr; diff --git a/netwerk/system/mac/nsNetworkLinkService.mm b/netwerk/system/mac/nsNetworkLinkService.mm index 5b2d7575ac..30942331d1 100644 --- a/netwerk/system/mac/nsNetworkLinkService.mm +++ b/netwerk/system/mac/nsNetworkLinkService.mm @@ -181,11 +181,13 @@ static bool scanArp(char *ip, char *mac, size_t maclen) if (st == 0 || errno != ENOMEM) { break; } - needed += needed / 8; + size_t increased = needed; + increased += increased / 8; - auto tmp = MakeUnique<char[]>(needed); + auto tmp = MakeUnique<char[]>(increased); memcpy(&tmp[0], &buf[0], needed); buf = Move(tmp); + needed = increased; } if (st == -1) { return false; diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 8aa5ae433b..a092d4c26a 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -1720,11 +1720,14 @@ nsLocalFile::GetNativeTarget(nsACString& aResult) return NS_ERROR_OUT_OF_MEMORY; } - if (readlink(mPath.get(), target, (size_t)size) < 0) { + ssize_t written = readlink(mPath.get(), target.BeginWriting(), size_t(size)); + if (written < 0) { free(target); return NSRESULT_FOR_ERRNO(); } - target[size] = '\0'; + // Target might have changed since the lstat call, or lstat might lie, see bug + // 1791029. + target.Truncate(written); nsresult rv = NS_OK; nsCOMPtr<nsIFile> self(this); @@ -1775,12 +1778,15 @@ nsLocalFile::GetNativeTarget(nsACString& aResult) size = newSize; } - int32_t linkLen = readlink(flatRetval.get(), target, size); + ssize_t linkLen = readlink(flatRetval.get(), target, size); if (linkLen == -1) { rv = NSRESULT_FOR_ERRNO(); break; } - target[linkLen] = '\0'; + // Target might have changed since the lstat call, or lstat might lie, see bug + // 1791029. + newTarget.Truncate(linkLen); + target = newTarget; } free(target); |