Chromium Code Reviews| Index: chrome/common/mac/cfbundle_blocker.mm |
| =================================================================== |
| --- chrome/common/mac/cfbundle_blocker.mm (revision 105162) |
| +++ chrome/common/mac/cfbundle_blocker.mm (working copy) |
| @@ -11,6 +11,7 @@ |
| #include "base/mac/mac_util.h" |
| #include "base/mac/scoped_cftyperef.h" |
| #include "base/mac/scoped_nsautorelease_pool.h" |
| +#import "base/memory/scoped_nsobject.h" |
| #include "base/sys_string_conversions.h" |
| #include "third_party/mach_override/mach_override.h" |
| @@ -60,13 +61,6 @@ |
| // Everything in the suffix list has a trailing slash so as to only block |
| // loading things contained in these directories. |
| NSString* const blocked_suffixes[] = { |
| - // SIMBL - http://code.google.com/p/simbl/source/browse/src/SIMBL.{h,m}. |
| - // It attempts to inject itself via an AppleScript event. |
| - // http://code.google.com/p/simbl/source/browse/SIMBL%20Agent/SIMBLAgent.m |
| - // Blocking input managers and scripting additions may already be enough |
| - // to prevent SIMBL plugins from loading. |
| - @"Application Support/SIMBL/Plugins/", |
| - |
| #if !defined(__LP64__) |
| // Contextual menu manager plug-ins are unavailable to 64-bit processes. |
| // http://developer.apple.com/library/mac/releasenotes/Cocoa/AppKitOlderNotes.html#NSMenu |
| @@ -146,12 +140,6 @@ |
| return false; |
| } |
| -// Returns true if bundle_id identifies a bundle that is allowed to be loaded |
| -// even when found in a blocked directory. |
| -bool IsBundleIDAllowed(NSString* bundle_id) { |
| - return [bundle_id isEqualToString:@"com.google.osax.Google_Authenticator_BT"]; |
| -} |
| - |
| typedef Boolean (*_CFBundleLoadExecutableAndReturnError_Type)(CFBundleRef, |
| Boolean, |
| CFErrorRef*); |
| @@ -169,44 +157,57 @@ |
| DCHECK(g_original_underscore_cfbundle_load_executable_and_return_error); |
| base::mac::ScopedCFTypeRef<CFURLRef> url_cf(CFBundleCopyBundleURL(bundle)); |
| - base::mac::ScopedCFTypeRef<CFStringRef> path_cf( |
| - CFURLCopyFileSystemPath(url_cf, kCFURLPOSIXPathStyle)); |
| - NSString* path_ns = base::mac::CFToNSCast(path_cf); |
| + scoped_nsobject<NSString> path(base::mac::CFToNSCast( |
| + CFURLCopyFileSystemPath(url_cf, kCFURLPOSIXPathStyle))); |
| - CFStringRef identifier_cf = CFBundleGetIdentifier(bundle); |
| - NSString* identifier_ns = base::mac::CFToNSCast(identifier_cf); |
| + NSString* bundle_id = base::mac::CFToNSCast(CFBundleGetIdentifier(bundle)); |
| - if (IsBundlePathBlocked(path_ns) && !IsBundleIDAllowed(identifier_ns)) { |
| - NSString* identifier_ns_print = identifier_ns ? identifier_ns : @"(nil)"; |
| + NSDictionary* bundle_dictionary = |
| + base::mac::CFToNSCast(CFBundleGetInfoDictionary(bundle)); |
| + NSString* version = [bundle_dictionary objectForKey: |
| + base::mac::CFToNSCast(kCFBundleVersionKey)]; |
| + if (![version isKindOfClass:[NSString class]]) { |
| + // Deal with pranksters. |
| + version = nil; |
| + } |
| + if (IsBundlePathBlocked(path) && !IsBundleAllowed(bundle_id, version)) { |
| + NSString* bundle_id_print = bundle_id ? bundle_id : @"(nil)"; |
| + NSString* version_print = version ? version : @"(nil)"; |
| + |
| LOG(INFO) << "Blocking attempt to load bundle " |
| - << [identifier_ns_print UTF8String] |
| + << [bundle_id_print UTF8String] |
| + << " version " |
| + << [version_print UTF8String] |
| << " at " |
| - << [path_ns fileSystemRepresentation]; |
| + << [path fileSystemRepresentation]; |
|
Scott Hess - ex-Googler
2011/10/13 00:05:54
Wonder if this would be cleaner using -[NSString s
Mark Mentovai
2011/10/13 03:23:15
shess wrote:
|
| if (error) { |
| - base::mac::ScopedCFTypeRef<CFStringRef> bundle_id( |
| + base::mac::ScopedCFTypeRef<CFStringRef> app_bundle_id( |
| base::SysUTF8ToCFStringRef(base::mac::BaseBundleID())); |
| // 0xb10c10ad = "block load" |
| const CFIndex kBundleLoadBlocked = 0xb10c10ad; |
| NSMutableDictionary* error_dict = |
| - [NSMutableDictionary dictionaryWithCapacity:3]; |
| - if (identifier_ns) { |
| - [error_dict setObject:identifier_ns forKey:@"identifier"]; |
| + [NSMutableDictionary dictionaryWithCapacity:4]; |
| + if (bundle_id) { |
| + [error_dict setObject:bundle_id forKey:@"bundle_id"]; |
| } |
| - if (path_ns) { |
| - [error_dict setObject:path_ns forKey:@"path"]; |
| + if (version) { |
| + [error_dict setObject:version forKey:@"version"]; |
| } |
| + if (path) { |
| + [error_dict setObject:path forKey:@"path"]; |
| + } |
| NSURL* url_ns = base::mac::CFToNSCast(url_cf); |
| - NSString* url_absolute_string_ns = [url_ns absoluteString]; |
| - if (url_absolute_string_ns) { |
| - [error_dict setObject:url_absolute_string_ns forKey:@"url"]; |
| + NSString* url_absolute_string = [url_ns absoluteString]; |
| + if (url_absolute_string) { |
| + [error_dict setObject:url_absolute_string forKey:@"url"]; |
| } |
| *error = CFErrorCreate(NULL, |
| - bundle_id, |
| + app_bundle_id, |
| kBundleLoadBlocked, |
| base::mac::NSToCFCast(error_dict)); |
| } |
| @@ -233,6 +234,97 @@ |
| } |
| } |
| +namespace { |
| + |
| +struct AllowedBundle { |
| + // The bundle identifier to permit. These are matched with a case-sensitive |
| + // literal comparison. "Children" of the declared bundle ID are permitted: |
| + // if bundle_id here is @"org.chromium", it would match both @"org.chromium" |
| + // and @"org.chromium.Chromium". |
| + NSString* bundle_id; |
| + |
| + // If bundle_id should only be permitted as of a certain minimum version, |
| + // this string defines that version, which will be compared to the bundle's |
| + // version with a numeric comparison. If bundle_id may be permitted at any |
| + // version, set minimum_version to nil. |
| + NSString* minimum_version; |
| +}; |
| + |
| +} // namespace |
| + |
| +bool IsBundleAllowed(NSString* bundle_id, NSString* version) { |
| + // The list of bundles that are allowed to load. Before adding an entry to |
| + // this list, be sure that it's well-behaved. Specifically, anything that |
| + // uses mach_override |
| + // (https://github.com/rentzsch/mach_star/tree/master/mach_override) must |
| + // use version 51ae3d199463fa84548f466d649f0821d579fdaf (July 22, 2011) or |
| + // newer. Products added to the list must not cause crashes. Entries should |
| + // include the name of the product, URL, and the name and e-mail address of |
| + // someone responsible for the product's engineering. To add items to this |
| + // list, file a bug at http://new.crbug.com/ using the "Defect on Mac OS" |
| + // template, and provide the bundle ID (or IDs) and minimum CFBundleVersion |
| + // that's safe for Chrome to load, along with the necessary product and |
| + // contact information. Whitelisted bundles in this list may be removed if |
| + // they are found to cause instability or otherwise behave badly. With |
| + // proper contact information, Chrome developers may try to contact |
| + // maintainers to resolve any problems. |
| + const AllowedBundle kAllowedBundles[] = { |
| + // Google Authenticator BT |
| + // Dave MacLachlan <dmaclach@google.com> |
| + { @"com.google.osax.Google_Authenticator_BT", nil }, |
| + |
| + // Default Folder X, http://www.stclairsoft.com/DefaultFolderX/ |
| + // Jon Gotow <gotow@stclairsoft.com> |
| + { @"com.stclairsoft.DefaultFolderX", @"4.4.3" }, |
| + |
| + // MySpeed, http://www.enounce.com/myspeed |
| + // Edward Bianchi <ejbianchi@enounce.com> |
| + { @"com.enounce.MySpeed.osax", @"1201" }, |
| + |
| + // SIMBL (fork), https://github.com/albertz/simbl |
| + // Albert Zeyer <albzey@googlemail.com> |
| + { @"net.culater.SIMBL", nil }, |
| + |
| + // Smart Scroll, http://marcmoini.com/sx_en.html |
| + // Marc Moini <marc@a9ff.com> |
| + { @"com.marcmoini.SmartScroll", @"3.9" }, |
| + }; |
| + |
| + for (size_t index = 0; index < arraysize(kAllowedBundles); ++index) { |
| + const AllowedBundle& allowed_bundle = kAllowedBundles[index]; |
| + NSString* allowed_bundle_id = allowed_bundle.bundle_id; |
| + NSUInteger allowed_bundle_id_length = [allowed_bundle_id length]; |
| + |
| + // Permit bundle identifiers that are exactly equal to the allowed |
| + // identifier, as well as "children" of the allowed identifier. |
| + if ([bundle_id isEqualToString:allowed_bundle_id] || |
| + ([bundle_id length] > allowed_bundle_id_length && |
| + [bundle_id characterAtIndex:allowed_bundle_id_length] == '.' && |
| + [bundle_id hasPrefix:allowed_bundle_id])) { |
| + NSString* minimum_version = allowed_bundle.minimum_version; |
| + if (!minimum_version) { |
| + // If the rule didn't declare any version requirement, the bundle is |
| + // allowed to load. |
| + return true; |
| + } |
| + |
| + if (!version) { |
| + // If there wasn't any version but one was required, the bundle isn't |
| + // allowed to load. |
| + return false; |
| + } |
| + |
| + // A numeric search is appropriate for comparing version numbers. |
| + NSComparisonResult result = [version compare:minimum_version |
| + options:NSNumericSearch]; |
| + return result != NSOrderedAscending; |
| + } |
| + } |
| + |
| + // Nothing matched. |
| + return false; |
| +} |
| + |
| } // namespace mac |
| } // namespace common |
| } // namespace chrome |