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

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

Issue 434077: Add regex escaping code to Mac sandbox implementation and re-enable the utility process on OS X. (Closed)
Patch Set: Sync to trunk Created 11 years 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
« chrome/common/sandbox_mac.mm ('K') | « chrome/common/sandbox_mac.mm ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import <Cocoa/Cocoa.h>
6 #include <dirent.h>
7
8 extern "C" {
9 #include <sandbox.h>
10 }
11
12 #include "base/file_util.h"
13 #include "base/file_path.h"
14 #include "base/multiprocess_test.h"
15 #include "base/string_util.h"
16 #include "base/sys_string_conversions.h"
17 #include "chrome/common/sandbox_mac.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace sandbox {
21
22 bool QuotePlainString(const std::string& str_utf8, std::string* dst);
23 bool QuoteStringForRegex(const std::string& str_utf8, std::string* dst);
24
25 } // namespace sandbox
26
27 static const char* kSandboxAccessPathKey = "sandbox_dir";
28
29 class MacSandboxTest : public MultiProcessTest {
30 public:
31 bool CheckSandbox(std::string directory_to_try) {
32 setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1);
33 base::ProcessHandle child_process = SpawnChild(L"mac_sandbox_path_access");
34 int code = -1;
35 if (!base::WaitForExitCode(child_process, &code)) {
36 LOG(WARNING) << "base::WaitForExitCode failed";
37 return false;
38 }
39 return code == 0;
40 }
41 };
42
43 TEST_F(MacSandboxTest, StringEscape) {
44 using sandbox::QuotePlainString;
45
46 const struct string_escape_test_data {
47 const char* to_escape;
48 const char* escaped;
49 } string_escape_cases[] = {
50 {"", ""},
51 {"\b\f\n\r\t\\\"", "\\b\\f\\n\\r\\t\\\\\\\""},
52 {"/'", "/'"},
53 {"sandwich", "sandwich"},
54 {"(sandwich)", "(sandwich)"},
55 {"^\u2135.\u2136$", "^\\u2135.\\u2136$"},
56 };
57
58 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(string_escape_cases); ++i) {
59 std::string out;
60 std::string in(string_escape_cases[i].to_escape);
61 EXPECT_TRUE(QuotePlainString(in, &out));
62 EXPECT_EQ(string_escape_cases[i].escaped, out);
63 }
64 }
65
66 TEST_F(MacSandboxTest, RegexEscape) {
67 using sandbox::QuoteStringForRegex;
68
69 const std::string kSandboxEscapeSuffix("(/|$)");
70 const struct regex_test_data {
71 const wchar_t *to_escape;
72 const char* escaped;
73 } regex_cases[] = {
74 {L"", ""},
75 {L"/'", "/'"}, // / & ' characters don't need escaping.
76 {L"sandwich", "sandwich"},
77 {L"(sandwich)", "\\(sandwich\\)"},
78 };
79
80 // Check that all characters whose values are smaller than 32 [1F] are
81 // rejected by the regex escaping code.
82 {
83 std::string out;
84 char fail_string[] = {31, 0};
85 char ok_string[] = {32, 0};
86 EXPECT_FALSE(QuoteStringForRegex(fail_string, &out));
87 EXPECT_TRUE(QuoteStringForRegex(ok_string, &out));
88 }
89
90 // Check that all characters whose values are larger than 126 [7E] are
91 // rejected by the regex escaping code.
92 {
93 std::string out;
94 EXPECT_TRUE(QuoteStringForRegex("}", &out)); // } == 0x7D == 125
95 EXPECT_FALSE(QuoteStringForRegex("~", &out)); // ~ == 0x7E == 126
96 EXPECT_FALSE(QuoteStringForRegex(WideToUTF8(L"^\u2135.\u2136$"), &out));
97 }
98
99 {
100 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(regex_cases); ++i) {
101 std::string out;
102 std::string in = WideToUTF8(regex_cases[i].to_escape);
103 EXPECT_TRUE(QuoteStringForRegex(in, &out));
104 std::string expected("^");
105 expected.append(regex_cases[i].escaped);
106 expected.append(kSandboxEscapeSuffix);
107 EXPECT_EQ(expected, out);
108 }
109 }
110
111 {
112 std::string in_utf8("\\^.$|()[]*+?{}");
113 std::string expected;
114 expected.push_back('^');
115 for (size_t i = 0; i < in_utf8.length(); ++i) {
116 expected.push_back('\\');
117 expected.push_back(in_utf8[i]);
118 }
119 expected.append(kSandboxEscapeSuffix);
120
121 std::string out;
122 EXPECT_TRUE(QuoteStringForRegex(in_utf8, &out));
123 EXPECT_EQ(expected, out);
124
125 }
126 }
127
128 // A class to handle auto-deleting a directory.
129 class ScopedDirectoryDelete {
130 public:
131 inline void operator()(FilePath* x) const {
132 if (x) {
133 file_util::Delete(*x, true);
134 }
135 }
136 };
137
138 typedef scoped_ptr_malloc<FilePath, ScopedDirectoryDelete> ScopedDirectory;
139
140 TEST_F(MacSandboxTest, SandboxAccess) {
141 FilePath tmp_dir;
142 ASSERT_TRUE(file_util::CreateNewTempDirectory("", &tmp_dir));
143 // This step is important on OS X since the sandbox only understands "real"
144 // paths and the paths CreateNewTempDirectory() returns are empirically in
145 // /var which is a symlink to /private/var .
146 ASSERT_TRUE(file_util::AbsolutePath(&tmp_dir));
147 ScopedDirectory cleanup(&tmp_dir);
148
149 const char* sandbox_dir_cases[] = {
150 "simple_dir_name",
151 "^hello++ $", // Regex.
152 "\\^.$|()[]*+?{}", // All regex characters.
153 };
154
155 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(sandbox_dir_cases); ++i) {
156 const char* sandbox_dir_name = sandbox_dir_cases[i];
157 FilePath sandbox_dir = tmp_dir.Append(sandbox_dir_name);
158 ASSERT_TRUE(file_util::CreateDirectory(sandbox_dir));
159 ScopedDirectory cleanup_sandbox(&sandbox_dir);
160 EXPECT_TRUE(CheckSandbox(sandbox_dir.value()));
161 }
162 }
163
164 MULTIPROCESS_TEST_MAIN(mac_sandbox_path_access) {
165 char *sandbox_allowed_dir = getenv(kSandboxAccessPathKey);
166 if (!sandbox_allowed_dir)
167 return -1;
168
169 // Build up a sandbox profile that only allows access to DIR_TO_ALLOW_ACCESS.
170 NSString *sandbox_profile =
171 @"(version 1)" \
172 "(deny default)" \
173 "(allow signal (target self))" \
174 "(allow sysctl-read)" \
175 "(allow file-read-metadata)" \
176 "(allow file-read* file-write* (regex #\"DIR_TO_ALLOW_ACCESS\"))";
177
178 std::string allowed_dir(sandbox_allowed_dir);
179 std::string allowed_dir_escaped;
180 if (!sandbox::QuoteStringForRegex(allowed_dir, &allowed_dir_escaped)) {
181 LOG(ERROR) << "Regex string quoting failed " << allowed_dir;
182 return -1;
183 }
184 NSString* allowed_dir_escaped_ns = base::SysUTF8ToNSString(
185 allowed_dir_escaped.c_str());
186 sandbox_profile = [sandbox_profile
187 stringByReplacingOccurrencesOfString:@"DIR_TO_ALLOW_ACCESS"
188 withString:allowed_dir_escaped_ns];
189 // Enable Sandbox.
190 char* error_buff = NULL;
191 int error = sandbox_init([sandbox_profile UTF8String], 0, &error_buff);
192 if (error == -1) {
193 LOG(ERROR) << "Failed to Initialize Sandbox: " << error_buff;
194 return -1;
195 }
196 sandbox_free_error(error_buff);
197
198 // Test Sandbox.
199
200 // We should be able to list the contents of the sandboxed directory.
201 DIR *file_list = NULL;
202 file_list = opendir(sandbox_allowed_dir);
203 if (!file_list) {
204 PLOG(ERROR) << "Sandbox overly restrictive: call to opendir("
205 << sandbox_allowed_dir
206 << ") failed";
207 return -1;
208 }
209 closedir(file_list);
210
211 // Test restrictions on accessing files.
212 FilePath allowed_dir_path(sandbox_allowed_dir);
213 FilePath allowed_file = allowed_dir_path.Append("ok_to_write");
214 FilePath denied_file1 = allowed_dir_path.DirName().Append("cant_access");
215
216 // Try to write a file who's name has the same prefix as the directory we
217 // allow access to.
218 FilePath basename = allowed_dir_path.BaseName();
219 std::string tricky_filename = basename.value() + "123";
220 FilePath denied_file2 = allowed_dir_path.DirName().Append(tricky_filename);
221
222 if (open(allowed_file.value().c_str(), O_WRONLY | O_CREAT) <= 0) {
223 PLOG(ERROR) << "Sandbox overly restrictive: failed to write ("
224 << allowed_file.value()
225 << ")";
226 return -1;
227 }
228
229 if (open(denied_file1.value().c_str(), O_WRONLY | O_CREAT) > 0) {
230 PLOG(ERROR) << "Sandbox breach: was able to write ("
231 << denied_file1.value()
232 << ")";
233 return -1;
234 }
235
236 if (open(denied_file2.value().c_str(), O_WRONLY | O_CREAT) > 0) {
237 PLOG(ERROR) << "Sandbox breach: was able to write ("
238 << denied_file2.value()
239 << ")";
240 return -1;
241 }
242
243 return 0;
244 }
OLDNEW
« chrome/common/sandbox_mac.mm ('K') | « chrome/common/sandbox_mac.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698