/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Initially false to make concurrent consumers acquire the lock and sync. // The plain bool is synchronized with sMutex, the atomic one is for a quick // check w/o the need to acquire the lock on the hot path. staticbool sForbiddenPathsEmpty = false; static Atomic<bool, Relaxed> sForbiddenPathsEmptyQuickCheck{false};
nsString path; if (NS_FAILED(file->GetTarget(path))) { return;
}
// The allowlist makes sense only for UNC paths, because this code is used // to block only UNC paths, hence, no need to add non-UNC directories here // as those would never pass the check. if (!StringBeginsWith(path, u"\\\\"_ns)) { return;
}
StaticMutexAutoLock lock(sMutex);
if (!PathAllowlist().Contains(path)) {
PathAllowlist().AppendElement(path);
}
}
void InitDirectoriesAllowlist() { // NS_GRE_DIR is the installation path where the binary resides.
AllowUNCDirectory(NS_GRE_DIR); // NS_APP_USER_PROFILE_50_DIR and NS_APP_USER_PROFILE_LOCAL_50_DIR are the two // parts of the profile we store permanent and local-specific data.
AllowUNCDirectory(NS_APP_USER_PROFILE_50_DIR);
AllowUNCDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR);
}
namespace { // anon
template <typename TChar> class TNormalizer : public TTokenizer<TChar> { typedef TTokenizer<TChar> base;
// Windows UNC paths begin with double separator (\\) // Linux paths begin with just one separator (/) // If we want to use the normalizer for regular windows paths this code // will need to be updated. #ifdef XP_WIN if (base::Check(mSeparator)) {
aNormalizedFilePath.Append(mSeparator.AsChar());
} #endif
if (base::Check(mSeparator)) {
aNormalizedFilePath.Append(mSeparator.AsChar());
}
while (base::HasInput()) { if (!ConsumeName()) { returnfalse;
}
}
for (autoconst& name : mStack) {
aNormalizedFilePath.Append(name);
}
returntrue;
}
private: bool ConsumeName() { if (base::CheckEOF()) { returntrue;
}
if (CheckCurrentDir()) { returntrue;
}
if (CheckParentDir()) { if (!mStack.Length()) { // This means there are more \.. than valid names returnfalse;
}
mStack.RemoveLastElement(); returntrue;
}
nsTDependentSubstring<TChar> name; if (base::ReadUntil(mSeparator, name, base::INCLUDE_LAST) &&
name.Length() == 1) { // this means an empty name (a lone slash), which is illegal returnfalse;
}
mStack.AppendElement(name);
// After the device path specifier, the rest of file path can be: // - starts with the volume or drive. e.g. \\?\C:\... // - UNCs. e.g. \\?\UNC\Server\Share\Test\Foo.txt // - device UNCs. e.g. \\?\server1\e:\utilities\\filecomparer\... // The first case should not be blocked by IsBlockedUNCPath. if (!StartsWithDiskDesignatorAndBackslash(pathNoPrefix)) { returnfalse;
}
nsAutoString normalized; if (!Normalizer(aFilePath, Normalizer::Token::Char('\\')).Get(normalized)) { // Broken paths are considered invalid and thus inaccessible returntrue;
}
StaticMutexAutoLock lock(sMutex);
for (constauto& allowedPrefix : PathAllowlist()) { if (StringBeginsWith(normalized, allowedPrefix)) { if (normalized.Length() == allowedPrefix.Length()) { returnfalse;
} if (normalized[allowedPrefix.Length()] == L'\\') { returnfalse;
}
// When we are here, the path has a form "\\path\prefixevil" // while we have an allowed prefix of "\\path\prefix". // Note that we don't want to add a slash to the end of a prefix // so that opening the directory (no slash at the end) still works. break;
}
}
// An atomic quick check out of the lock, because this is mostly `true`. if (sForbiddenPathsEmptyQuickCheck) { returntrue;
}
StaticMutexAutoLock lock(sMutex);
if (sForbiddenPathsEmpty) { returntrue;
}
// If sForbidden has been cleared at shutdown, we must avoid calling // ForbiddenPaths() again, as that will recreate the array and we will leak. if (!sForbiddenPaths) { returntrue;
}
nsTAutoString<char_path_t> normalized; if (!Normalizer(aFilePath, Normalizer::Token::Char(kPathSeparator))
.Get(normalized)) { // Broken paths are considered invalid and thus inaccessible returnfalse;
}
for (constauto& prefix : ForbiddenPaths()) { if (StringBeginsWith(normalized, prefix)) { if (normalized.Length() > prefix.Length() &&
normalized[prefix.Length()] != kPathSeparator) { continue;
} returnfalse;
}
}
returntrue;
}
#ifdef XP_WIN bool StartsWithDiskDesignatorAndBackslash(const nsAString& aAbsolutePath) { // aAbsolutePath can only be (in regular expression): // UNC path: ^\\\\.* // A single backslash: ^\\.* // A disk designator with a backslash: ^[A-Za-z]:\\.* return aAbsolutePath.Length() >= 3 && IsAsciiAlpha(aAbsolutePath.CharAt(0)) &&
aAbsolutePath.CharAt(1) == L':' &&
aAbsolutePath.CharAt(2) == kPathSeparator;
} #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.