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

Side by Side Diff: chrome/common/mac/cfbundle_blocker.mm

Issue 8226026: Allow whitelisted bundles to load in Chrome (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months 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
« no previous file with comments | « no previous file | 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "chrome/common/mac/cfbundle_blocker.h" 5 #include "chrome/common/mac/cfbundle_blocker.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 #import <Foundation/Foundation.h> 8 #import <Foundation/Foundation.h>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 NSArray* blocked_prefixes = 53 NSArray* blocked_prefixes =
54 NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, 54 NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
55 NSUserDomainMask | 55 NSUserDomainMask |
56 NSLocalDomainMask | 56 NSLocalDomainMask |
57 NSNetworkDomainMask, 57 NSNetworkDomainMask,
58 YES); 58 YES);
59 59
60 // Everything in the suffix list has a trailing slash so as to only block 60 // Everything in the suffix list has a trailing slash so as to only block
61 // loading things contained in these directories. 61 // loading things contained in these directories.
62 NSString* const blocked_suffixes[] = { 62 NSString* const blocked_suffixes[] = {
63 // SIMBL - http://code.google.com/p/simbl/source/browse/src/SIMBL.{h,m}.
64 // It attempts to inject itself via an AppleScript event.
65 // http://code.google.com/p/simbl/source/browse/SIMBL%20Agent/SIMBLAgent.m
66 // Blocking input managers and scripting additions may already be enough
67 // to prevent SIMBL plugins from loading.
68 @"Application Support/SIMBL/Plugins/",
69
70 #if !defined(__LP64__) 63 #if !defined(__LP64__)
71 // Contextual menu manager plug-ins are unavailable to 64-bit processes. 64 // Contextual menu manager plug-ins are unavailable to 64-bit processes.
72 // http://developer.apple.com/library/mac/releasenotes/Cocoa/AppKitOlderNo tes.html#NSMenu 65 // http://developer.apple.com/library/mac/releasenotes/Cocoa/AppKitOlderNo tes.html#NSMenu
73 // Contextual menu plug-ins are loaded when a contextual menu is opened, 66 // Contextual menu plug-ins are loaded when a contextual menu is opened,
74 // for example, from within 67 // for example, from within
75 // +[NSMenu popUpContextMenu:withEvent:forView:]. 68 // +[NSMenu popUpContextMenu:withEvent:forView:].
76 @"Contextual Menu Items/", 69 @"Contextual Menu Items/",
77 70
78 // Input managers are deprecated, would only be loaded under specific 71 // Input managers are deprecated, would only be loaded under specific
79 // circumstances, and are entirely unavailable to 64-bit processes. 72 // circumstances, and are entirely unavailable to 64-bit processes.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 // If bundle_path is inside blocked_path (it has blocked_path as a 132 // If bundle_path is inside blocked_path (it has blocked_path as a
140 // prefix), refuse to load it. 133 // prefix), refuse to load it.
141 return true; 134 return true;
142 } 135 }
143 } 136 }
144 137
145 // bundle_path is not inside any blocked_path from blocked_paths. 138 // bundle_path is not inside any blocked_path from blocked_paths.
146 return false; 139 return false;
147 } 140 }
148 141
149 // Returns true if bundle_id identifies a bundle that is allowed to be loaded 142 struct AllowedBundle {
143 // The bundle identifier to permit. These are matched with a case-sensitive
144 // literal comparison. "Children" of the declared bundle ID are permitted:
145 // if bundle_id here is @"org.chromium", it would match both @"org.chromium"
146 // and @"org.chromium.Chromium".
147 NSString* bundle_id;
148
149 // If bundle_id should only be permitted as of a certain minimum version,
150 // this string defines that version, which will be compared to the bundle's
151 // version with a numeric comparison. If bundle_id may be permitted at any
152 // version, set minimum_version to nil.
153 NSString* minimum_version;
154 };
155
156 // Returns true if |bundle| identifies a bundle that is allowed to be loaded
150 // even when found in a blocked directory. 157 // even when found in a blocked directory.
151 bool IsBundleIDAllowed(NSString* bundle_id) { 158 bool IsBundleAllowed(CFBundleRef bundle) {
152 return [bundle_id isEqualToString:@"com.google.osax.Google_Authenticator_BT"]; 159 // The list of bundles that are allowed to load. Before adding an entry to
160 // this list, be sure that it's well-behaved. Specifically, anything that
161 // uses mach_override
162 // (https://github.com/rentzsch/mach_star/tree/master/mach_override) must
163 // use version 51ae3d199463fa84548f466d649f0821d579fdaf (July 22, 2011) or
164 // newer. Entries should include the name of the product, URL, and the name
165 // and e-mail address of someone responsible for the product's engineering.
166 // To add items to this list, file a bug at http://new.crbug.com/ using the
167 // "Defect on Mac OS" template, and provide the bundle ID (or IDs) and
168 // minimum CFBundleVersion that's safe for Chrome to load, along with the
169 // necessary product and contact information. Whitelisted bundles in this
170 // list may be removed if they are found to cause instability or otherwise
171 // behave badly. With proper contact information, Chrome developers may try
172 // to contact maintainers to resolve any problems.
173 const AllowedBundle kAllowedBundles[] = {
174 // Google Authenticator BT
175 // dmaclach
Scott Hess - ex-Googler 2011/10/12 19:34:34 Expanding this like other email addresses won't ki
176 { @"com.google.osax.Google_Authenticator_BT", nil },
177
178 // Default Folder X, http://www.stclairsoft.com/DefaultFolderX/
179 // Jon Gotow <gotow@stclairsoft.com>
180 { @"com.stclairsoft.DefaultFolderX", @"4.4.3" },
181
182 // MySpeed, http://www.enounce.com/myspeed
183 // Edward Bianchi <ejbianchi@enounce.com>
184 { @"com.enounce.MySpeed.osax", @"1201" },
185
186 // SIMBL (fork), https://github.com/albertz/simbl
187 // Albert Zeyer <albzey@googlemail.com>
188 { @"net.culater.SIMBL", nil },
189
190 // Smart Scroll, http://marcmoini.com/sx_en.html
191 // Marc Moini <marc@a9ff.com>
192 { @"com.marcmoini.SmartScroll", @"3.9" },
193 };
194
195 CFStringRef identifier_cf = CFBundleGetIdentifier(bundle);
196 NSString* identifier_ns = base::mac::CFToNSCast(identifier_cf);
Scott Hess - ex-Googler 2011/10/12 19:34:34 It might be worthwhile to pull everything outside
197
198 for (size_t index = 0; index < arraysize(kAllowedBundles); ++index) {
199 const AllowedBundle& allowed_bundle = kAllowedBundles[index];
200 NSString* allowed_bundle_id = allowed_bundle.bundle_id;
201
202 // Try a direct equality test.
203 bool bundle_id_match = [identifier_ns isEqualToString:allowed_bundle_id];
204
205 if (!bundle_id_match) {
206 // Permit bundle identifiers that are "children" of the allowed
207 // identifier.
Scott Hess - ex-Googler 2011/10/12 19:34:34 Would it be reasonable to make "children" be a dif
Mark Mentovai 2011/10/12 23:48:50 shess wrote:
208 NSUInteger bundle_id_length = [identifier_ns length];
209 NSUInteger allowed_bundle_id_length = [allowed_bundle_id length];
210 if (bundle_id_length > allowed_bundle_id_length &&
211 [identifier_ns characterAtIndex:allowed_bundle_id_length] == '.') {
212 NSComparisonResult result =
213 [identifier_ns compare:allowed_bundle_id
214 options:NSLiteralSearch
215 range:NSMakeRange(0, allowed_bundle_id_length)];
Scott Hess - ex-Googler 2011/10/12 19:34:34 -hasPrefix:? Unless NSLiteralSearch implies corre
216 bundle_id_match = result == NSOrderedSame;
217 }
218 }
219
220 if (bundle_id_match) {
221 NSString* minimum_version = allowed_bundle.minimum_version;
222 if (!minimum_version) {
223 // If the rule didn't declare any version requirement, the bundle is
224 // allowed to load.
225 return true;
226 }
227
228 NSDictionary* bundle_dictionary =
229 base::mac::CFToNSCast(CFBundleGetInfoDictionary(bundle));
230 NSString* version = [bundle_dictionary objectForKey:
231 base::mac::CFToNSCast(kCFBundleVersionKey)];
232 if (![version isKindOfClass:[NSString class]]) {
233 // If there wasn't any version but one was required, the bundle isn't
234 // allowed to load.
235 return false;
236 }
237
238 // A numeric search is appropriate for comparing version numbers.
239 NSComparisonResult result = [version compare:minimum_version
240 options:NSNumericSearch];
Scott Hess - ex-Googler 2011/10/12 19:34:34 OMG. I mean, good job, Apple!
Mark Mentovai 2011/10/12 23:48:50 shess wrote:
241 return result != NSOrderedAscending;
242 }
243 }
244
245 // Nothing matched.
246 return false;
153 } 247 }
154 248
155 typedef Boolean (*_CFBundleLoadExecutableAndReturnError_Type)(CFBundleRef, 249 typedef Boolean (*_CFBundleLoadExecutableAndReturnError_Type)(CFBundleRef,
156 Boolean, 250 Boolean,
157 CFErrorRef*); 251 CFErrorRef*);
158 252
159 // Call this to execute the original implementation of 253 // Call this to execute the original implementation of
160 // _CFBundleLoadExecutableAndReturnError. 254 // _CFBundleLoadExecutableAndReturnError.
161 _CFBundleLoadExecutableAndReturnError_Type 255 _CFBundleLoadExecutableAndReturnError_Type
162 g_original_underscore_cfbundle_load_executable_and_return_error; 256 g_original_underscore_cfbundle_load_executable_and_return_error;
163 257
164 Boolean ChromeCFBundleLoadExecutableAndReturnError(CFBundleRef bundle, 258 Boolean ChromeCFBundleLoadExecutableAndReturnError(CFBundleRef bundle,
165 Boolean force_global, 259 Boolean force_global,
166 CFErrorRef* error) { 260 CFErrorRef* error) {
167 base::mac::ScopedNSAutoreleasePool autorelease_pool; 261 base::mac::ScopedNSAutoreleasePool autorelease_pool;
168 262
169 DCHECK(g_original_underscore_cfbundle_load_executable_and_return_error); 263 DCHECK(g_original_underscore_cfbundle_load_executable_and_return_error);
170 264
171 base::mac::ScopedCFTypeRef<CFURLRef> url_cf(CFBundleCopyBundleURL(bundle)); 265 base::mac::ScopedCFTypeRef<CFURLRef> url_cf(CFBundleCopyBundleURL(bundle));
172 base::mac::ScopedCFTypeRef<CFStringRef> path_cf( 266 base::mac::ScopedCFTypeRef<CFStringRef> path_cf(
173 CFURLCopyFileSystemPath(url_cf, kCFURLPOSIXPathStyle)); 267 CFURLCopyFileSystemPath(url_cf, kCFURLPOSIXPathStyle));
174 NSString* path_ns = base::mac::CFToNSCast(path_cf); 268 NSString* path_ns = base::mac::CFToNSCast(path_cf);
175 269
176 CFStringRef identifier_cf = CFBundleGetIdentifier(bundle); 270 CFStringRef identifier_cf = CFBundleGetIdentifier(bundle);
177 NSString* identifier_ns = base::mac::CFToNSCast(identifier_cf); 271 NSString* identifier_ns = base::mac::CFToNSCast(identifier_cf);
178 272
179 if (IsBundlePathBlocked(path_ns) && !IsBundleIDAllowed(identifier_ns)) { 273 if (IsBundlePathBlocked(path_ns) && !IsBundleAllowed(bundle)) {
180 NSString* identifier_ns_print = identifier_ns ? identifier_ns : @"(nil)"; 274 NSString* identifier_ns_print = identifier_ns ? identifier_ns : @"(nil)";
181 275
182 LOG(INFO) << "Blocking attempt to load bundle " 276 LOG(INFO) << "Blocking attempt to load bundle "
183 << [identifier_ns_print UTF8String] 277 << [identifier_ns_print UTF8String]
184 << " at " 278 << " at "
185 << [path_ns fileSystemRepresentation]; 279 << [path_ns fileSystemRepresentation];
186 280
187 if (error) { 281 if (error) {
188 base::mac::ScopedCFTypeRef<CFStringRef> bundle_id( 282 base::mac::ScopedCFTypeRef<CFStringRef> bundle_id(
189 base::SysUTF8ToCFStringRef(base::mac::BaseBundleID())); 283 base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 &g_original_underscore_cfbundle_load_executable_and_return_error)); 323 &g_original_underscore_cfbundle_load_executable_and_return_error));
230 if (err != err_none) { 324 if (err != err_none) {
231 LOG(WARNING) << "mach_override _CFBundleLoadExecutableAndReturnError: " 325 LOG(WARNING) << "mach_override _CFBundleLoadExecutableAndReturnError: "
232 << err; 326 << err;
233 } 327 }
234 } 328 }
235 329
236 } // namespace mac 330 } // namespace mac
237 } // namespace common 331 } // namespace common
238 } // namespace chrome 332 } // namespace chrome
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698