Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: chrome/common/sandbox_mac_diraccess_unittest.mm

Issue 4380001: Mac Sandbox: Clean up forward declaration of internal sandbox functions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cleanup Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 #include <dirent.h> 6 #include <dirent.h>
7 7
8 extern "C" { 8 extern "C" {
9 #include <sandbox.h> 9 #include <sandbox.h>
10 } 10 }
11 11
12 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/file_path.h" 13 #include "base/file_path.h"
14 #include "base/hash_tables.h"
15 #include "base/test/multiprocess_test.h" 14 #include "base/test/multiprocess_test.h"
16 #include "base/sys_string_conversions.h" 15 #include "base/sys_string_conversions.h"
17 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
18 #include "chrome/common/sandbox_mac.h" 17 #include "chrome/common/sandbox_mac.h"
19 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/multiprocess_func_list.h" 19 #include "testing/multiprocess_func_list.h"
21 20
22 // Tests to exercise directory-access-related restrictions of Mac sandbox.
23
24 namespace sandbox {
25
26 typedef base::hash_map<std::string, SandboxSubstring>
27 SandboxVariableSubstitions;
28
29 bool QuotePlainString(const std::string& str_utf8, std::string* dst);
30 bool QuoteStringForRegex(const std::string& str_utf8, std::string* dst);
31 NSString* BuildAllowDirectoryAccessSandboxString(
32 const FilePath& allowed_dir,
33 SandboxVariableSubstitions* substitutions);
34 bool PostProcessSandboxProfile(NSString* in_sandbox_data,
35 NSArray* comments_to_remove,
36 SandboxVariableSubstitions& substitutions,
37 std::string *final_sandbox_profile_str);
38
39 } // namespace sandbox
40
41 namespace { 21 namespace {
42 22
43 static const char* kSandboxAccessPathKey = "sandbox_dir"; 23 static const char* kSandboxAccessPathKey = "sandbox_dir";
44 static const char* kDeniedSuffix = "_denied"; 24 static const char* kDeniedSuffix = "_denied";
45 25
26 } // namespace
27
28 // Tests need to be in the same namespace as the sandbox::Sandbox class to be
29 // useable with FRIEND_TEST() declaration.
30 namespace sandbox {
31
46 class MacDirAccessSandboxTest : public base::MultiProcessTest { 32 class MacDirAccessSandboxTest : public base::MultiProcessTest {
47 public: 33 public:
48 bool CheckSandbox(const std::string& directory_to_try) { 34 bool CheckSandbox(const std::string& directory_to_try) {
49 setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1); 35 setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1);
50 base::ProcessHandle child_process = SpawnChild("mac_sandbox_path_access", 36 base::ProcessHandle child_process = SpawnChild("mac_sandbox_path_access",
51 false); 37 false);
52 int code = -1; 38 int code = -1;
53 if (!base::WaitForExitCode(child_process, &code)) { 39 if (!base::WaitForExitCode(child_process, &code)) {
54 LOG(WARNING) << "base::WaitForExitCode failed"; 40 LOG(WARNING) << "base::WaitForExitCode failed";
55 return false; 41 return false;
56 } 42 }
57 return code == 0; 43 return code == 0;
58 } 44 }
59 }; 45 };
60 46
61 TEST_F(MacDirAccessSandboxTest, StringEscape) { 47 TEST_F(MacDirAccessSandboxTest, StringEscape) {
62 using sandbox::QuotePlainString;
63
64 const struct string_escape_test_data { 48 const struct string_escape_test_data {
65 const char* to_escape; 49 const char* to_escape;
66 const char* escaped; 50 const char* escaped;
67 } string_escape_cases[] = { 51 } string_escape_cases[] = {
68 {"", ""}, 52 {"", ""},
69 {"\b\f\n\r\t\\\"", "\\b\\f\\n\\r\\t\\\\\\\""}, 53 {"\b\f\n\r\t\\\"", "\\b\\f\\n\\r\\t\\\\\\\""},
70 {"/'", "/'"}, 54 {"/'", "/'"},
71 {"sandwich", "sandwich"}, 55 {"sandwich", "sandwich"},
72 {"(sandwich)", "(sandwich)"}, 56 {"(sandwich)", "(sandwich)"},
73 {"^\u2135.\u2136$", "^\\u2135.\\u2136$"}, 57 {"^\u2135.\u2136$", "^\\u2135.\\u2136$"},
74 }; 58 };
75 59
76 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(string_escape_cases); ++i) { 60 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(string_escape_cases); ++i) {
77 std::string out; 61 std::string out;
78 std::string in(string_escape_cases[i].to_escape); 62 std::string in(string_escape_cases[i].to_escape);
79 EXPECT_TRUE(QuotePlainString(in, &out)); 63 EXPECT_TRUE(Sandbox::QuotePlainString(in, &out));
80 EXPECT_EQ(string_escape_cases[i].escaped, out); 64 EXPECT_EQ(string_escape_cases[i].escaped, out);
81 } 65 }
82 } 66 }
83 67
84 TEST_F(MacDirAccessSandboxTest, RegexEscape) { 68 TEST_F(MacDirAccessSandboxTest, RegexEscape) {
85 using sandbox::QuoteStringForRegex;
86
87 const std::string kSandboxEscapeSuffix("(/|$)"); 69 const std::string kSandboxEscapeSuffix("(/|$)");
88 const struct regex_test_data { 70 const struct regex_test_data {
89 const wchar_t *to_escape; 71 const wchar_t *to_escape;
90 const char* escaped; 72 const char* escaped;
91 } regex_cases[] = { 73 } regex_cases[] = {
92 {L"", ""}, 74 {L"", ""},
93 {L"/'", "/'"}, // / & ' characters don't need escaping. 75 {L"/'", "/'"}, // / & ' characters don't need escaping.
94 {L"sandwich", "sandwich"}, 76 {L"sandwich", "sandwich"},
95 {L"(sandwich)", "\\(sandwich\\)"}, 77 {L"(sandwich)", "\\(sandwich\\)"},
96 }; 78 };
97 79
98 // Check that all characters whose values are smaller than 32 [1F] are 80 // Check that all characters whose values are smaller than 32 [1F] are
99 // rejected by the regex escaping code. 81 // rejected by the regex escaping code.
100 { 82 {
101 std::string out; 83 std::string out;
102 char fail_string[] = {31, 0}; 84 char fail_string[] = {31, 0};
103 char ok_string[] = {32, 0}; 85 char ok_string[] = {32, 0};
104 EXPECT_FALSE(QuoteStringForRegex(fail_string, &out)); 86 EXPECT_FALSE(Sandbox::QuoteStringForRegex(fail_string, &out));
105 EXPECT_TRUE(QuoteStringForRegex(ok_string, &out)); 87 EXPECT_TRUE(Sandbox::QuoteStringForRegex(ok_string, &out));
106 } 88 }
107 89
108 // Check that all characters whose values are larger than 126 [7E] are 90 // Check that all characters whose values are larger than 126 [7E] are
109 // rejected by the regex escaping code. 91 // rejected by the regex escaping code.
110 { 92 {
111 std::string out; 93 std::string out;
112 EXPECT_TRUE(QuoteStringForRegex("}", &out)); // } == 0x7D == 125 94 EXPECT_TRUE(Sandbox::QuoteStringForRegex("}", &out)); // } == 0x7D == 125
113 EXPECT_FALSE(QuoteStringForRegex("~", &out)); // ~ == 0x7E == 126 95 EXPECT_FALSE(Sandbox::QuoteStringForRegex("~", &out)); // ~ == 0x7E == 126
114 EXPECT_FALSE(QuoteStringForRegex(WideToUTF8(L"^\u2135.\u2136$"), &out)); 96 EXPECT_FALSE(
97 Sandbox::QuoteStringForRegex(WideToUTF8(L"^\u2135.\u2136$"), &out));
115 } 98 }
116 99
117 { 100 {
118 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(regex_cases); ++i) { 101 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(regex_cases); ++i) {
119 std::string out; 102 std::string out;
120 std::string in = WideToUTF8(regex_cases[i].to_escape); 103 std::string in = WideToUTF8(regex_cases[i].to_escape);
121 EXPECT_TRUE(QuoteStringForRegex(in, &out)); 104 EXPECT_TRUE(Sandbox::QuoteStringForRegex(in, &out));
122 std::string expected("^"); 105 std::string expected("^");
123 expected.append(regex_cases[i].escaped); 106 expected.append(regex_cases[i].escaped);
124 expected.append(kSandboxEscapeSuffix); 107 expected.append(kSandboxEscapeSuffix);
125 EXPECT_EQ(expected, out); 108 EXPECT_EQ(expected, out);
126 } 109 }
127 } 110 }
128 111
129 { 112 {
130 std::string in_utf8("\\^.$|()[]*+?{}"); 113 std::string in_utf8("\\^.$|()[]*+?{}");
131 std::string expected; 114 std::string expected;
132 expected.push_back('^'); 115 expected.push_back('^');
133 for (size_t i = 0; i < in_utf8.length(); ++i) { 116 for (size_t i = 0; i < in_utf8.length(); ++i) {
134 expected.push_back('\\'); 117 expected.push_back('\\');
135 expected.push_back(in_utf8[i]); 118 expected.push_back(in_utf8[i]);
136 } 119 }
137 expected.append(kSandboxEscapeSuffix); 120 expected.append(kSandboxEscapeSuffix);
138 121
139 std::string out; 122 std::string out;
140 EXPECT_TRUE(QuoteStringForRegex(in_utf8, &out)); 123 EXPECT_TRUE(Sandbox::QuoteStringForRegex(in_utf8, &out));
141 EXPECT_EQ(expected, out); 124 EXPECT_EQ(expected, out);
142 125
143 } 126 }
144 } 127 }
145 128
146 // A class to handle auto-deleting a directory. 129 // A class to handle auto-deleting a directory.
147 class ScopedDirectoryDelete { 130 class ScopedDirectoryDelete {
148 public: 131 public:
149 inline void operator()(FilePath* x) const { 132 inline void operator()(FilePath* x) const {
150 if (x) { 133 if (x) {
151 file_util::Delete(*x, true); 134 file_util::Delete(*x, true);
152 } 135 }
153 } 136 }
154 }; 137 };
155 138
156 typedef scoped_ptr_malloc<FilePath, ScopedDirectoryDelete> ScopedDirectory; 139 typedef scoped_ptr_malloc<FilePath, ScopedDirectoryDelete> ScopedDirectory;
157 140
158 TEST_F(MacDirAccessSandboxTest, SandboxAccess) { 141 TEST_F(MacDirAccessSandboxTest, SandboxAccess) {
159 using file_util::CreateDirectory; 142 using file_util::CreateDirectory;
160 143
161 FilePath tmp_dir; 144 FilePath tmp_dir;
162 ASSERT_TRUE(file_util::CreateNewTempDirectory("", &tmp_dir)); 145 ASSERT_TRUE(file_util::CreateNewTempDirectory("", &tmp_dir));
163 // This step is important on OS X since the sandbox only understands "real" 146 // This step is important on OS X since the sandbox only understands "real"
164 // paths and the paths CreateNewTempDirectory() returns are empirically in 147 // paths and the paths CreateNewTempDirectory() returns are empirically in
165 // /var which is a symlink to /private/var . 148 // /var which is a symlink to /private/var .
166 sandbox::GetCanonicalSandboxPath(&tmp_dir); 149 Sandbox::GetCanonicalSandboxPath(&tmp_dir);
167 ScopedDirectory cleanup(&tmp_dir); 150 ScopedDirectory cleanup(&tmp_dir);
168 151
169 const char* sandbox_dir_cases[] = { 152 const char* sandbox_dir_cases[] = {
170 "simple_dir_name", 153 "simple_dir_name",
171 "^hello++ $", // Regex. 154 "^hello++ $", // Regex.
172 "\\^.$|()[]*+?{}", // All regex characters. 155 "\\^.$|()[]*+?{}", // All regex characters.
173 }; 156 };
174 157
175 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(sandbox_dir_cases); ++i) { 158 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(sandbox_dir_cases); ++i) {
176 const char* sandbox_dir_name = sandbox_dir_cases[i]; 159 const char* sandbox_dir_name = sandbox_dir_cases[i];
(...skipping 21 matching lines...) Expand all
198 181
199 // Build up a sandbox profile that only allows access to a single directory. 182 // Build up a sandbox profile that only allows access to a single directory.
200 NSString *sandbox_profile = 183 NSString *sandbox_profile =
201 @"(version 1)" \ 184 @"(version 1)" \
202 "(deny default)" \ 185 "(deny default)" \
203 "(allow signal (target self))" \ 186 "(allow signal (target self))" \
204 "(allow sysctl-read)" \ 187 "(allow sysctl-read)" \
205 ";ENABLE_DIRECTORY_ACCESS"; 188 ";ENABLE_DIRECTORY_ACCESS";
206 189
207 std::string allowed_dir(sandbox_allowed_dir); 190 std::string allowed_dir(sandbox_allowed_dir);
208 sandbox::SandboxVariableSubstitions substitutions; 191 Sandbox::SandboxVariableSubstitions substitutions;
209 NSString* allow_dir_sandbox_code = 192 NSString* allow_dir_sandbox_code =
210 sandbox::BuildAllowDirectoryAccessSandboxString( 193 Sandbox::BuildAllowDirectoryAccessSandboxString(
211 FilePath(sandbox_allowed_dir), 194 FilePath(sandbox_allowed_dir),
212 &substitutions); 195 &substitutions);
213 sandbox_profile = [sandbox_profile 196 sandbox_profile = [sandbox_profile
214 stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" 197 stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS"
215 withString:allow_dir_sandbox_code]; 198 withString:allow_dir_sandbox_code];
216 199
217 std::string final_sandbox_profile_str; 200 std::string final_sandbox_profile_str;
218 if (!PostProcessSandboxProfile(sandbox_profile, 201 if (!Sandbox::PostProcessSandboxProfile(sandbox_profile,
219 [NSArray array], 202 [NSArray array],
220 substitutions, 203 substitutions,
221 &final_sandbox_profile_str)) { 204 &final_sandbox_profile_str)) {
222 LOG(ERROR) << "Call to PostProcessSandboxProfile() failed"; 205 LOG(ERROR) << "Call to PostProcessSandboxProfile() failed";
223 return -1; 206 return -1;
224 } 207 }
225 208
226
227 // Enable Sandbox. 209 // Enable Sandbox.
228 char* error_buff = NULL; 210 char* error_buff = NULL;
229 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); 211 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff);
230 if (error == -1) { 212 if (error == -1) {
231 LOG(ERROR) << "Failed to Initialize Sandbox: " << error_buff; 213 LOG(ERROR) << "Failed to Initialize Sandbox: " << error_buff;
232 return -1; 214 return -1;
233 } 215 }
234 sandbox_free_error(error_buff); 216 sandbox_free_error(error_buff);
235 217
236 // Test Sandbox. 218 // Test Sandbox.
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 if (open(denied_file2.value().c_str(), O_WRONLY | O_CREAT) > 0) { 294 if (open(denied_file2.value().c_str(), O_WRONLY | O_CREAT) > 0) {
313 PLOG(ERROR) << "Sandbox breach: was able to write (" 295 PLOG(ERROR) << "Sandbox breach: was able to write ("
314 << denied_file2.value() 296 << denied_file2.value()
315 << ")"; 297 << ")";
316 return -1; 298 return -1;
317 } 299 }
318 300
319 return 0; 301 return 0;
320 } 302 }
321 303
322 } // namespace 304 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698