1 #include "gtest/gtest.h"
2 
3 #include "mozilla/FilePreferences.h"
4 
5 #include "nsDirectoryServiceDefs.h"
6 #include "nsDirectoryServiceUtils.h"
7 #include "mozilla/Preferences.h"
8 #include "mozilla/ScopeExit.h"
9 #include "nsIDirectoryEnumerator.h"
10 
11 using namespace mozilla;
12 
13 const char kForbiddenPathsPref[] = "network.file.path_blacklist";
14 
TEST(TestFilePreferencesUnix,Parsing)15 TEST(TestFilePreferencesUnix, Parsing)
16 {
17 #define kForbidden "/tmp/forbidden"
18 #define kForbiddenDir "/tmp/forbidden/"
19 #define kForbiddenFile "/tmp/forbidden/file"
20 #define kOther "/tmp/other"
21 #define kOtherDir "/tmp/other/"
22 #define kOtherFile "/tmp/other/file"
23 #define kAllowed "/tmp/allowed"
24 
25   // This is run on exit of this function to make sure we clear the pref
26   // and that behaviour with the pref cleared is correct.
27   auto cleanup = MakeScopeExit([&] {
28     nsresult rv = Preferences::ClearUser(kForbiddenPathsPref);
29     ASSERT_EQ(rv, NS_OK);
30     FilePreferences::InitPrefs();
31     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbidden)),
32               true);
33     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbiddenDir)),
34               true);
35     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbiddenFile)),
36               true);
37     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kAllowed)), true);
38   });
39 
40   auto CheckPrefs = [](const nsACString& aPaths) {
41     nsresult rv;
42     rv = Preferences::SetCString(kForbiddenPathsPref, aPaths);
43     ASSERT_EQ(rv, NS_OK);
44     FilePreferences::InitPrefs();
45     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbiddenDir)),
46               false);
47     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbiddenDir)),
48               false);
49     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbiddenFile)),
50               false);
51     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kForbidden)),
52               false);
53     ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kAllowed)), true);
54   };
55 
56   CheckPrefs(nsLiteralCString(kForbidden));
57   CheckPrefs(nsLiteralCString(kForbidden "," kOther));
58   ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kOtherFile)),
59             false);
60   CheckPrefs(nsLiteralCString(kForbidden "," kOther ","));
61   ASSERT_EQ(FilePreferences::IsAllowedPath(nsLiteralCString(kOtherFile)),
62             false);
63 }
64 
TEST(TestFilePreferencesUnix,Simple)65 TEST(TestFilePreferencesUnix, Simple)
66 {
67   nsAutoCString tempPath;
68 
69   // This is the directory we will forbid
70   nsCOMPtr<nsIFile> forbiddenDir;
71   nsresult rv =
72       NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(forbiddenDir));
73   ASSERT_EQ(rv, NS_OK);
74   rv = forbiddenDir->GetNativePath(tempPath);
75   ASSERT_EQ(rv, NS_OK);
76   rv = forbiddenDir->AppendNative("forbidden_dir"_ns);
77   ASSERT_EQ(rv, NS_OK);
78 
79   // This is executed at exit to clean up after ourselves.
80   auto cleanup = MakeScopeExit([&] {
81     nsresult rv = Preferences::ClearUser(kForbiddenPathsPref);
82     ASSERT_EQ(rv, NS_OK);
83     FilePreferences::InitPrefs();
84 
85     rv = forbiddenDir->Remove(true);
86     ASSERT_EQ(rv, NS_OK);
87   });
88 
89   // Create the directory
90   rv = forbiddenDir->Create(nsIFile::DIRECTORY_TYPE, 0666);
91   ASSERT_EQ(rv, NS_OK);
92 
93   // This is the file we will try to access
94   nsCOMPtr<nsIFile> forbiddenFile;
95   rv = forbiddenDir->Clone(getter_AddRefs(forbiddenFile));
96   ASSERT_EQ(rv, NS_OK);
97   rv = forbiddenFile->AppendNative("test_file"_ns);
98 
99   // Create the file
100   ASSERT_EQ(rv, NS_OK);
101   rv = forbiddenFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
102 
103   // Get the forbidden path
104   nsAutoCString forbiddenPath;
105   rv = forbiddenDir->GetNativePath(forbiddenPath);
106   ASSERT_EQ(rv, NS_OK);
107 
108   // Set the pref and make sure it is enforced
109   rv = Preferences::SetCString(kForbiddenPathsPref, forbiddenPath);
110   ASSERT_EQ(rv, NS_OK);
111   FilePreferences::InitPrefs();
112 
113   // Check that we can't access some of the file attributes
114   int64_t size;
115   rv = forbiddenFile->GetFileSize(&size);
116   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
117 
118   bool exists;
119   rv = forbiddenFile->Exists(&exists);
120   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
121 
122   // Check that we can't enumerate the directory
123   nsCOMPtr<nsIDirectoryEnumerator> dirEnumerator;
124   rv = forbiddenDir->GetDirectoryEntries(getter_AddRefs(dirEnumerator));
125   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
126 
127   nsCOMPtr<nsIFile> newPath;
128   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
129   ASSERT_EQ(rv, NS_OK);
130   rv = newPath->AppendNative("."_ns);
131   ASSERT_EQ(rv, NS_OK);
132   rv = newPath->AppendNative("forbidden_dir"_ns);
133   ASSERT_EQ(rv, NS_OK);
134   rv = newPath->Exists(&exists);
135   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
136 
137   rv = newPath->AppendNative("test_file"_ns);
138   ASSERT_EQ(rv, NS_OK);
139   rv = newPath->Exists(&exists);
140   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
141 
142   // Check that ./ does not bypass the filter
143   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
144   ASSERT_EQ(rv, NS_OK);
145   rv = newPath->AppendRelativeNativePath("./forbidden_dir/file"_ns);
146   ASSERT_EQ(rv, NS_OK);
147   rv = newPath->Exists(&exists);
148   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
149 
150   // Check that ..  does not bypass the filter
151   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
152   ASSERT_EQ(rv, NS_OK);
153   rv = newPath->AppendRelativeNativePath("allowed/../forbidden_dir/file"_ns);
154   ASSERT_EQ(rv, NS_OK);
155   rv = newPath->Exists(&exists);
156   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
157 
158   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(newPath));
159   ASSERT_EQ(rv, NS_OK);
160   rv = newPath->AppendNative("allowed"_ns);
161   ASSERT_EQ(rv, NS_OK);
162   rv = newPath->AppendNative(".."_ns);
163   ASSERT_EQ(rv, NS_OK);
164   rv = newPath->AppendNative("forbidden_dir"_ns);
165   ASSERT_EQ(rv, NS_OK);
166   rv = newPath->Exists(&exists);
167   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
168 
169   nsAutoCString trickyPath(tempPath);
170   trickyPath.AppendLiteral("/allowed/../forbidden_dir/file");
171   rv = newPath->InitWithNativePath(trickyPath);
172   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
173 
174   // Check that we can't construct a path that is functionally the same
175   // as the forbidden one and bypasses the filter.
176   trickyPath = tempPath;
177   trickyPath.AppendLiteral("/./forbidden_dir/file");
178   rv = newPath->InitWithNativePath(trickyPath);
179   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
180 
181   trickyPath = tempPath;
182   trickyPath.AppendLiteral("//forbidden_dir/file");
183   rv = newPath->InitWithNativePath(trickyPath);
184   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
185 
186   trickyPath.Truncate();
187   trickyPath.AppendLiteral("//");
188   trickyPath.Append(tempPath);
189   trickyPath.AppendLiteral("/forbidden_dir/file");
190   rv = newPath->InitWithNativePath(trickyPath);
191   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
192 
193   trickyPath.Truncate();
194   trickyPath.AppendLiteral("//");
195   trickyPath.Append(tempPath);
196   trickyPath.AppendLiteral("//forbidden_dir/file");
197   rv = newPath->InitWithNativePath(trickyPath);
198   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
199 
200   // Check that if the forbidden string is a directory, we only block access
201   // to subresources, not the directory itself.
202   nsAutoCString forbiddenDirPath(forbiddenPath);
203   forbiddenDirPath.Append("/");
204   rv = Preferences::SetCString(kForbiddenPathsPref, forbiddenDirPath);
205   ASSERT_EQ(rv, NS_OK);
206   FilePreferences::InitPrefs();
207 
208   // This should work, since we only block subresources
209   rv = forbiddenDir->Exists(&exists);
210   ASSERT_EQ(rv, NS_OK);
211 
212   rv = forbiddenDir->GetDirectoryEntries(getter_AddRefs(dirEnumerator));
213   ASSERT_EQ(rv, NS_ERROR_FILE_ACCESS_DENIED);
214 }
215