зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1634267 - DOS device paths shouldn't be blocked by IsBlockedUNCPath; r=dom-workers-and-storage-reviewers,janv,froydnj
Bug 1536796 introduces "\\?\" prefix (DOS device specifier) to Windows file paths. At the moment, the prefix is only prepended to the file paths that start with a disk designator and a backslash. On the other hands, IsBlockedUNCPath blocks file paths that start with "\\" in Windows and that includes DOS device paths (the cases mentioned above). Thus, this patch prevents DOS device paths from being treating as UNC paths in IsBlockedUNCPath. Differential Revision: https://phabricator.services.mozilla.com/D73621
This commit is contained in:
Родитель
e120487bbb
Коммит
3d101cac5a
|
@ -11,6 +11,7 @@
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/StaticMutex.h"
|
#include "mozilla/StaticMutex.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
|
#include "mozilla/TextUtils.h"
|
||||||
#include "mozilla/Tokenizer.h"
|
#include "mozilla/Tokenizer.h"
|
||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
#include "nsDirectoryServiceDefs.h"
|
#include "nsDirectoryServiceDefs.h"
|
||||||
|
@ -33,6 +34,8 @@ static WinPaths& PathWhitelist() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
const auto kDevicePathSpecifier = NS_LITERAL_STRING("\\\\?\\");
|
||||||
|
|
||||||
typedef char16_t char_path_t;
|
typedef char16_t char_path_t;
|
||||||
#else
|
#else
|
||||||
typedef char char_path_t;
|
typedef char char_path_t;
|
||||||
|
@ -223,6 +226,28 @@ class TNormalizer : public TTokenizer<TChar> {
|
||||||
nsTArray<nsTDependentSubstring<TChar>> mStack;
|
nsTArray<nsTDependentSubstring<TChar>> mStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
bool IsDOSDevicePathWithDrive(const nsAString& aFilePath) {
|
||||||
|
if (!StringBeginsWith(aFilePath, kDevicePathSpecifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pathNoPrefix =
|
||||||
|
nsDependentSubstring(aFilePath, kDevicePathSpecifier.Length());
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool IsBlockedUNCPath(const nsAString& aFilePath) {
|
bool IsBlockedUNCPath(const nsAString& aFilePath) {
|
||||||
|
@ -235,6 +260,15 @@ bool IsBlockedUNCPath(const nsAString& aFilePath) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
// ToDo: We don't need to check this once we can check if there is a valid
|
||||||
|
// server or host name that is prefaced by "\\".
|
||||||
|
// https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
|
||||||
|
if (IsDOSDevicePathWithDrive(aFilePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
nsAutoString normalized;
|
nsAutoString normalized;
|
||||||
if (!Normalizer(aFilePath, Normalizer::Token::Char('\\')).Get(normalized)) {
|
if (!Normalizer(aFilePath, Normalizer::Token::Char('\\')).Get(normalized)) {
|
||||||
// Broken paths are considered invalid and thus inaccessible
|
// Broken paths are considered invalid and thus inaccessible
|
||||||
|
@ -309,6 +343,18 @@ bool IsAllowedPath(const nsTSubstring<char_path_t>& aFilePath) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
void testing::SetBlockUNCPaths(bool aBlock) { sBlockUNCPaths = aBlock; }
|
void testing::SetBlockUNCPaths(bool aBlock) { sBlockUNCPaths = aBlock; }
|
||||||
|
|
||||||
void testing::AddDirectoryToWhitelist(nsAString const& aPath) {
|
void testing::AddDirectoryToWhitelist(nsAString const& aPath) {
|
||||||
|
|
|
@ -19,7 +19,14 @@ bool IsAllowedPath(const nsAString& aFilePath);
|
||||||
bool IsAllowedPath(const nsACString& aFilePath);
|
bool IsAllowedPath(const nsACString& aFilePath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
bool StartsWithDiskDesignatorAndBackslash(const nsAString& aAbsolutePath);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern const char kPathSeparator;
|
extern const char kPathSeparator;
|
||||||
|
#ifdef XP_WIN
|
||||||
|
extern const nsLiteralString kDevicePathSpecifier;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/TextUtils.h"
|
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
#include "mozilla/Utf8.h"
|
#include "mozilla/Utf8.h"
|
||||||
|
|
||||||
|
@ -60,6 +59,7 @@
|
||||||
#include "mozilla/WidgetUtils.h"
|
#include "mozilla/WidgetUtils.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
using mozilla::FilePreferences::kDevicePathSpecifier;
|
||||||
using mozilla::FilePreferences::kPathSeparator;
|
using mozilla::FilePreferences::kPathSeparator;
|
||||||
|
|
||||||
#define CHECK_mWorkingPath() \
|
#define CHECK_mWorkingPath() \
|
||||||
|
@ -80,20 +80,8 @@ using mozilla::FilePreferences::kPathSeparator;
|
||||||
# define DRIVE_REMOTE 4
|
# define DRIVE_REMOTE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr auto kDevicePathSpecifier = NS_LITERAL_STRING("\\\\?\\");
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult NewLocalFile(const nsAString& aPath, bool aFollowLinks,
|
nsresult NewLocalFile(const nsAString& aPath, bool aFollowLinks,
|
||||||
bool aUseDOSDevicePathSyntax, nsIFile** aResult) {
|
bool aUseDOSDevicePathSyntax, nsIFile** aResult) {
|
||||||
RefPtr<nsLocalFile> file = new nsLocalFile();
|
RefPtr<nsLocalFile> file = new nsLocalFile();
|
||||||
|
@ -990,7 +978,7 @@ nsLocalFile::InitWithPath(const nsAString& aFilePath) {
|
||||||
// Prepend the "\\?\" prefix if the useDOSDevicePathSyntax is set and the path
|
// Prepend the "\\?\" prefix if the useDOSDevicePathSyntax is set and the path
|
||||||
// starts with a disk designator and backslash.
|
// starts with a disk designator and backslash.
|
||||||
if (mUseDOSDevicePathSyntax &&
|
if (mUseDOSDevicePathSyntax &&
|
||||||
StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
FilePreferences::StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
||||||
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1525,8 +1513,9 @@ nsLocalFile::SetLeafName(const nsAString& aLeafName) {
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsLocalFile::GetPath(nsAString& aResult) {
|
nsLocalFile::GetPath(nsAString& aResult) {
|
||||||
MOZ_ASSERT_IF(mUseDOSDevicePathSyntax,
|
MOZ_ASSERT_IF(
|
||||||
!StartsWithDiskDesignatorAndBackslash(mWorkingPath));
|
mUseDOSDevicePathSyntax,
|
||||||
|
!FilePreferences::StartsWithDiskDesignatorAndBackslash(mWorkingPath));
|
||||||
aResult = mWorkingPath;
|
aResult = mWorkingPath;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -2952,8 +2941,9 @@ nsLocalFile::GetTarget(nsAString& aResult) {
|
||||||
aResult.Truncate();
|
aResult.Truncate();
|
||||||
Resolve();
|
Resolve();
|
||||||
|
|
||||||
MOZ_ASSERT_IF(mUseDOSDevicePathSyntax,
|
MOZ_ASSERT_IF(
|
||||||
!StartsWithDiskDesignatorAndBackslash(mResolvedPath));
|
mUseDOSDevicePathSyntax,
|
||||||
|
!FilePreferences::StartsWithDiskDesignatorAndBackslash(mResolvedPath));
|
||||||
|
|
||||||
aResult = mResolvedPath;
|
aResult = mResolvedPath;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -3075,7 +3065,7 @@ nsLocalFile::SetUseDOSDevicePathSyntax(bool aUseDOSDevicePathSyntax) {
|
||||||
mWorkingPath = Substring(mWorkingPath, kDevicePathSpecifier.Length());
|
mWorkingPath = Substring(mWorkingPath, kDevicePathSpecifier.Length());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
if (FilePreferences::StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
||||||
MakeDirty();
|
MakeDirty();
|
||||||
// Prepend the prefix
|
// Prepend the prefix
|
||||||
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
||||||
|
|
|
@ -140,3 +140,65 @@ TEST(FilePreferencesWin, AccessUNC)
|
||||||
rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\..\\evil\\share"));
|
rv = lf->InitWithPath(NS_LITERAL_STRING("\\\\nice\\..\\evil\\share"));
|
||||||
ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
|
ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FilePreferencesWin, AccessDOSDevicePath)
|
||||||
|
{
|
||||||
|
const auto devicePathSpecifier = NS_LITERAL_STRING("\\\\?\\");
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> lf = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
mozilla::FilePreferences::testing::SetBlockUNCPaths(true);
|
||||||
|
|
||||||
|
rv = lf->InitWithPath(devicePathSpecifier +
|
||||||
|
NS_LITERAL_STRING("evil\\z:\\share"));
|
||||||
|
ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
|
||||||
|
|
||||||
|
rv = lf->InitWithPath(devicePathSpecifier +
|
||||||
|
NS_LITERAL_STRING("UNC\\evil\\share"));
|
||||||
|
ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
|
||||||
|
|
||||||
|
rv = lf->InitWithPath(devicePathSpecifier + NS_LITERAL_STRING("C:\\"));
|
||||||
|
ASSERT_EQ(rv, NS_OK);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> base;
|
||||||
|
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(base));
|
||||||
|
ASSERT_EQ(rv, NS_OK);
|
||||||
|
|
||||||
|
nsAutoString path;
|
||||||
|
rv = base->GetPath(path);
|
||||||
|
ASSERT_EQ(rv, NS_OK);
|
||||||
|
|
||||||
|
rv = lf->InitWithPath(devicePathSpecifier + path);
|
||||||
|
ASSERT_EQ(rv, NS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FilePreferencesWin, StartsWithDiskDesignatorAndBackslash)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("\\\\UNC\\path"));
|
||||||
|
ASSERT_FALSE(result);
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("\\single\\backslash"));
|
||||||
|
ASSERT_FALSE(result);
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("C:relative"));
|
||||||
|
ASSERT_FALSE(result);
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("\\\\?\\C:\\"));
|
||||||
|
ASSERT_FALSE(result);
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("C:\\"));
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
|
||||||
|
result = mozilla::FilePreferences::StartsWithDiskDesignatorAndBackslash(
|
||||||
|
NS_LITERAL_STRING("c:\\"));
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче