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

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

Issue 7748042: Merge trunk r97497 and its many dependents to the 14.0.835 branch. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/835/src/
Patch Set: Created 9 years, 3 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 | « chrome/common/mac/cfbundle_blocker.h ('k') | third_party/mach_override/README.chromium » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/common/mac/cfbundle_blocker.h"
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #import <Foundation/Foundation.h>
9
10 #include "base/logging.h"
11 #include "base/mac/mac_util.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/mac/scoped_nsautorelease_pool.h"
14 #include "base/sys_string_conversions.h"
15 #include "third_party/mach_override/mach_override.h"
16
17 extern "C" {
18
19 // _CFBundleLoadExecutableAndReturnError is the internal implementation that
20 // results in a dylib being loaded via dlopen. Both CFBundleLoadExecutable and
21 // CFBundleLoadExecutableAndReturnError are funneled into this routine. Other
22 // CFBundle functions may also call directly into here, perhaps due to
23 // inlining their calls to CFBundleLoadExecutable.
24 //
25 // See CF-476.19/CFBundle.c (10.5.8), CF-550.43/CFBundle.c (10.6.8), and
26 // CF-635/Bundle.c (10.7.0) and the disassembly of the shipping object code.
27 //
28 // Because this is a private function not declared by
29 // <CoreFoundation/CoreFoundation.h>, provide a declaration here.
30 Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle,
31 Boolean force_global,
32 CFErrorRef* error);
33
34 } // extern "C"
35
36 namespace chrome {
37 namespace common {
38 namespace mac {
39
40 namespace {
41
42 // Returns an autoreleased array of paths that contain plug-ins that should be
43 // forbidden to load. Each element of the array will be a string containing
44 // an absolute pathname ending in '/'.
45 NSArray* BlockedPaths() {
46 NSMutableArray* blocked_paths;
47
48 {
49 base::mac::ScopedNSAutoreleasePool autorelease_pool;
50
51 // ~/Library, /Library, and /Network/Library. Things in /System/Library
52 // aren't blacklisted.
53 NSArray* blocked_prefixes =
54 NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
55 NSUserDomainMask |
56 NSLocalDomainMask |
57 NSNetworkDomainMask,
58 YES);
59
60 // Everything in the suffix list has a trailing slash so as to only block
61 // loading things contained in these directories.
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__)
71 // Contextual menu manager plug-ins are unavailable to 64-bit processes.
72 // 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,
74 // for example, from within
75 // +[NSMenu popUpContextMenu:withEvent:forView:].
76 @"Contextual Menu Items/",
77
78 // Input managers are deprecated, would only be loaded under specific
79 // circumstances, and are entirely unavailable to 64-bit processes.
80 // http://developer.apple.com/library/mac/releasenotes/Cocoa/AppKitOlderNo tes.html#NSInputManager
81 // Input managers are loaded when the NSInputManager class is
82 // initialized.
83 @"InputManagers/",
84 #endif // __LP64__
85
86 // Don't load third-party scripting additions either. Scripting
87 // additions are loaded by AppleScript from within AEProcessAppleEvent
88 // in response to an Apple Event.
89 @"ScriptingAdditions/"
90
91 // This list is intentionally incomplete. For example, it doesn't block
92 // printer drivers or Internet plug-ins.
93 };
94
95 NSUInteger blocked_paths_count = [blocked_prefixes count] *
96 arraysize(blocked_suffixes);
97
98 // Not autoreleased here, because the enclosing pool is scoped too
99 // narrowly.
100 blocked_paths =
101 [[NSMutableArray alloc] initWithCapacity:blocked_paths_count];
102
103 // Build a flat list by adding each suffix to each prefix.
104 for (NSString* blocked_prefix in blocked_prefixes) {
105 for (size_t blocked_suffix_index = 0;
106 blocked_suffix_index < arraysize(blocked_suffixes);
107 ++blocked_suffix_index) {
108 NSString* blocked_suffix = blocked_suffixes[blocked_suffix_index];
109 NSString* blocked_path =
110 [blocked_prefix stringByAppendingPathComponent:blocked_suffix];
111
112 [blocked_paths addObject:blocked_path];
113 }
114 }
115
116 DCHECK_EQ([blocked_paths count], blocked_paths_count);
117 }
118
119 return [blocked_paths autorelease];
120 }
121
122 // Returns true if bundle_path identifies a path within a blocked directory.
123 // Blocked directories are those returned by BlockedPaths().
124 bool IsBundlePathBlocked(NSString* bundle_path) {
125 static NSArray* blocked_paths = [BlockedPaths() retain];
126
127 for (NSString* blocked_path in blocked_paths) {
128 NSUInteger blocked_path_length = [blocked_path length];
129
130 // Do a case-insensitive comparison because most users will be on
131 // case-insensitive HFS+ filesystems and it's cheaper than asking the
132 // disk. This is like [bundle_path hasPrefix:blocked_path] but is
133 // case-insensitive.
134 if ([bundle_path length] >= blocked_path_length &&
135 [bundle_path compare:blocked_path
136 options:NSCaseInsensitiveSearch
137 range:NSMakeRange(0, blocked_path_length)] ==
138 NSOrderedSame) {
139 // If bundle_path is inside blocked_path (it has blocked_path as a
140 // prefix), refuse to load it.
141 return true;
142 }
143 }
144
145 // bundle_path is not inside any blocked_path from blocked_paths.
146 return false;
147 }
148
149 // Returns true if bundle_id identifies a bundle that is allowed to be loaded
150 // even when found in a blocked directory.
151 bool IsBundleIDAllowed(NSString* bundle_id) {
152 return [bundle_id isEqualToString:@"com.google.osax.Google_Authenticator_BT"];
153 }
154
155 typedef Boolean (*_CFBundleLoadExecutableAndReturnError_Type)(CFBundleRef,
156 Boolean,
157 CFErrorRef*);
158
159 // Call this to execute the original implementation of
160 // _CFBundleLoadExecutableAndReturnError.
161 _CFBundleLoadExecutableAndReturnError_Type
162 g_original_underscore_cfbundle_load_executable_and_return_error;
163
164 Boolean ChromeCFBundleLoadExecutableAndReturnError(CFBundleRef bundle,
165 Boolean force_global,
166 CFErrorRef* error) {
167 base::mac::ScopedNSAutoreleasePool autorelease_pool;
168
169 DCHECK(g_original_underscore_cfbundle_load_executable_and_return_error);
170
171 base::mac::ScopedCFTypeRef<CFURLRef> url_cf(CFBundleCopyBundleURL(bundle));
172 base::mac::ScopedCFTypeRef<CFStringRef> path_cf(
173 CFURLCopyFileSystemPath(url_cf, kCFURLPOSIXPathStyle));
174 NSString* path_ns = base::mac::CFToNSCast(path_cf);
175
176 CFStringRef identifier_cf = CFBundleGetIdentifier(bundle);
177 NSString* identifier_ns = base::mac::CFToNSCast(identifier_cf);
178
179 if (IsBundlePathBlocked(path_ns) && !IsBundleIDAllowed(identifier_ns)) {
180 NSString* identifier_ns_print = identifier_ns ? identifier_ns : @"(nil)";
181
182 LOG(INFO) << "Blocking attempt to load bundle "
183 << [identifier_ns_print UTF8String]
184 << " at "
185 << [path_ns fileSystemRepresentation];
186
187 if (error) {
188 base::mac::ScopedCFTypeRef<CFStringRef> bundle_id(
189 base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
190
191 // 0xb10c10ad = "block load"
192 const CFIndex kBundleLoadBlocked = 0xb10c10ad;
193
194 NSMutableDictionary* error_dict =
195 [NSMutableDictionary dictionaryWithCapacity:3];
196 if (identifier_ns) {
197 [error_dict setObject:identifier_ns forKey:@"identifier"];
198 }
199 if (path_ns) {
200 [error_dict setObject:path_ns forKey:@"path"];
201 }
202 NSURL* url_ns = base::mac::CFToNSCast(url_cf);
203 NSString* url_absolute_string_ns = [url_ns absoluteString];
204 if (url_absolute_string_ns) {
205 [error_dict setObject:url_absolute_string_ns forKey:@"url"];
206 }
207
208 *error = CFErrorCreate(NULL,
209 bundle_id,
210 kBundleLoadBlocked,
211 base::mac::NSToCFCast(error_dict));
212 }
213
214 return FALSE;
215 }
216
217 // Not blocked. Call through to the original implementation.
218 return g_original_underscore_cfbundle_load_executable_and_return_error(
219 bundle, force_global, error);
220 }
221
222 } // namespace
223
224 void EnableCFBundleBlocker() {
225 if (base::mac::IsOSLionOrLater()) {
226 mach_error_t err = mach_override_ptr(
227 reinterpret_cast<void*>(_CFBundleLoadExecutableAndReturnError),
228 reinterpret_cast<void*>(ChromeCFBundleLoadExecutableAndReturnError),
229 reinterpret_cast<void**>(
230 &g_original_underscore_cfbundle_load_executable_and_return_error));
231 if (err != err_none) {
232 LOG(WARNING) << "mach_override _CFBundleLoadExecutableAndReturnError: "
233 << err;
234 }
235 }
236 }
237
238 } // namespace mac
239 } // namespace common
240 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/common/mac/cfbundle_blocker.h ('k') | third_party/mach_override/README.chromium » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698