xpcom/tests/gtest/TestFilePreferencesUnix.cpp
author Sylvestre Ledru <sledru@mozilla.com>
Thu, 04 Apr 2019 20:12:23 +0000
changeset 468068 389b6bbd76dbdf3357453f0989bbe9595751b7ae
parent 450760 09c71a7cf75aeaf2963050e315276fb9a866fd62
child 468070 9e48fefcf1aca74fd97036121180907de52756e8
permissions -rw-r--r--
Bug 1519636 - clang-format-8: Reformat recent changes to the Google coding style r=Ehsan clang-format-8 upstream had some improvements wrt macros See: https://reviews.llvm.org/D33440 This is why the diff is bigger than usual # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D26098

#include "gtest/gtest.h"

#include "mozilla/FilePreferences.h"

#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/ScopeExit.h"
#include "nsIDirectoryEnumerator.h"

using namespace mozilla;

TEST(TestFilePreferencesUnix, Parsing)
{
#define kBlacklisted "/tmp/blacklisted"
#define kBlacklistedDir "/tmp/blacklisted/"
#define kBlacklistedFile "/tmp/blacklisted/file"
#define kOther "/tmp/other"
#define kOtherDir "/tmp/other/"
#define kOtherFile "/tmp/other/file"
#define kAllowed "/tmp/allowed"

  // This is run on exit of this function to make sure we clear the pref
  // and that behaviour with the pref cleared is correct.
  auto cleanup = MakeScopeExit([&] {
    nsresult rv = Preferences::ClearUser("network.file.path_blacklist");
    ASSERT_EQ(rv, NS_OK);
    FilePreferences::InitPrefs();
    ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklisted)),
              true);
    ASSERT_EQ(
        FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklistedDir)),
        true);
    ASSERT_EQ(
        FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklistedFile)),
        true);
    ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kAllowed)),
              true);
  });

  auto CheckPrefs = [](const nsACString& aPaths) {
    nsresult rv;
    rv = Preferences::SetCString("network.file.path_blacklist", aPaths);
    ASSERT_EQ(rv, NS_OK);
    FilePreferences::InitPrefs();
    ASSERT_EQ(
        FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklistedDir)),
        false);
    ASSERT_EQ(
        FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklistedDir)),
        false);
    ASSERT_EQ(
        FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklistedFile)),
        false);
    ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kBlacklisted)),
              false);
    ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kAllowed)),
              true);
  };

  CheckPrefs(NS_LITERAL_CSTRING(kBlacklisted));
  CheckPrefs(NS_LITERAL_CSTRING(kBlacklisted "," kOther));
  ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kOtherFile)),
            false);
  CheckPrefs(NS_LITERAL_CSTRING(kBlacklisted "," kOther ","));
  ASSERT_EQ(FilePreferences::IsAllowedPath(NS_LITERAL_CSTRING(kOtherFile)),
            false);
}

TEST(TestFilePreferencesUnix, Simple)
{
  nsAutoCString tempPath;

  // This is the directory we will blacklist
  nsCOMPtr<nsIFile> blacklistedDir;
  nsresult rv =
      NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(blacklistedDir));
  ASSERT_EQ(rv, NS_OK);
  rv = blacklistedDir->GetNativePath(tempPath);
  ASSERT_EQ(rv, NS_OK);
  rv = blacklistedDir->AppendNative(NS_LITERAL_CSTRING("blacklisted_dir"));
  ASSERT_EQ(rv, NS_OK);

  // This is executed at exit to clean up after ourselves.
  auto cleanup = MakeScopeExit([&] {
    nsresult rv = Preferences::ClearUser("network.file.path_blacklist");
    ASSERT_EQ(rv, NS_OK);
    FilePreferences::InitPrefs();

    rv = blacklistedDir->Remove(true);
    ASSERT_EQ(rv, NS_OK);
  });

  // Create the directory
  rv = blacklistedDir->Create(nsIFile::DIRECTORY_TYPE, 0666);
  ASSERT_EQ(rv, NS_OK);

  // This is the file we will try to access
  nsCOMPtr<nsIFile> blacklistedFile;
  rv = blacklistedDir->Clone(getter_AddRefs(blacklistedFile));
  ASSERT_EQ(rv, NS_OK);
  rv = blacklistedFile->AppendNative(NS_LITERAL_CSTRING("test_file"));

  // Create the file
  ASSERT_EQ(rv, NS_OK);
  rv = blacklistedFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);

  // Get the path for the blacklist
  nsAutoCString blackListPath;
  rv = blacklistedDir->GetNativePath(blackListPath);
  ASSERT_EQ(rv, NS_OK);

  // Set the pref and make sure it is enforced
  rv = Preferences::SetCString("network.file.path_blacklist", blackListPath);
  ASSERT_EQ(rv, NS_OK);
  FilePreferences::InitPrefs();

  // Check that we can't access some of the file attributes
  int64_t size;
  rv = blacklistedFile->GetFileSize(&size);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  bool exists;
  rv = blacklistedFile->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  // Check that we can't enumerate the directory
  nsCOMPtr<nsIDirectoryEnumerator> dirEnumerator;
  rv = blacklistedDir->GetDirectoryEntries(getter_AddRefs(dirEnumerator));
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  nsCOMPtr<nsIFile> newPath;
  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendNative(NS_LITERAL_CSTRING("."));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendNative(NS_LITERAL_CSTRING("blacklisted_dir"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  rv = newPath->AppendNative(NS_LITERAL_CSTRING("test_file"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  // Check that ./ does not bypass the filter
  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendRelativeNativePath(
      NS_LITERAL_CSTRING("./blacklisted_dir/file"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  // Check that ..  does not bypass the filter
  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendRelativeNativePath(
      NS_LITERAL_CSTRING("allowed/../blacklisted_dir/file"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendNative(NS_LITERAL_CSTRING("allowed"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendNative(NS_LITERAL_CSTRING(".."));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->AppendNative(NS_LITERAL_CSTRING("blacklisted_dir"));
  ASSERT_EQ(rv, NS_OK);
  rv = newPath->Exists(&exists);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  nsAutoCString trickyPath(tempPath);
  trickyPath.AppendLiteral("/allowed/../blacklisted_dir/file");
  rv = newPath->InitWithNativePath(trickyPath);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  // Check that we can't construct a path that is functionally the same
  // as the blacklisted one and bypasses the filter.
  trickyPath = tempPath;
  trickyPath.AppendLiteral("/./blacklisted_dir/file");
  rv = newPath->InitWithNativePath(trickyPath);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  trickyPath = tempPath;
  trickyPath.AppendLiteral("//blacklisted_dir/file");
  rv = newPath->InitWithNativePath(trickyPath);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  trickyPath.Truncate();
  trickyPath.AppendLiteral("//");
  trickyPath.Append(tempPath);
  trickyPath.AppendLiteral("/blacklisted_dir/file");
  rv = newPath->InitWithNativePath(trickyPath);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  trickyPath.Truncate();
  trickyPath.AppendLiteral("//");
  trickyPath.Append(tempPath);
  trickyPath.AppendLiteral("//blacklisted_dir/file");
  rv = newPath->InitWithNativePath(trickyPath);
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);

  // Check that if the blacklisted string is a directory, we only block access
  // to subresources, not the directory itself.
  nsAutoCString blacklistDirPath(blackListPath);
  blacklistDirPath.Append("/");
  rv = Preferences::SetCString("network.file.path_blacklist", blacklistDirPath);
  ASSERT_EQ(rv, NS_OK);
  FilePreferences::InitPrefs();

  // This should work, since we only block subresources
  rv = blacklistedDir->Exists(&exists);
  ASSERT_EQ(rv, NS_OK);

  rv = blacklistedDir->GetDirectoryEntries(getter_AddRefs(dirEnumerator));
  ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
}