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