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

Side by Side Diff: chrome/browser/safe_browsing/signature_evaluator_mac.mm

Issue 1363613004: Implement anonymous, opt-in, collection of OS X binary integrity incidents. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove spurious VLOG() Created 5 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
OLDNEW
(Empty)
1 // Copyright (c) 2015 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/browser/safe_browsing/signature_evaluator_mac.h"
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <Foundation/Foundation.h>
9 #include <Security/Security.h>
10 #include <sys/xattr.h>
11
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_cftyperef.h"
15 #include "base/mac/scoped_nsobject.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
18 #include "chrome/common/safe_browsing/csd.pb.h"
19 #include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
20
21 namespace safe_browsing {
22
23 namespace {
24
25 // OS X code signing data can be stored in extended attributes as well. This is
26 // a list of the extended attributes slots currently used in Security.framework,
27 // from codesign.h (see the kSecCS_* constants).
28 const char* const xattrs[] = {
29 "com.apple.cs.CodeDirectory",
30 "com.apple.cs.CodeSignature",
31 "com.apple.cs.CodeRequirements",
32 "com.apple.cs.CodeResources",
33 "com.apple.cs.CodeApplication",
34 "com.apple.cs.CodeEntitlements",
35 };
36
37 // Convenience function to get the appropriate path from a variety of NSObject
38 // types. For resources, code signing seems to give back an NSURL in which
39 // the path is relative to the bundle root. So in this case, we take the
40 // relative component, otherwise we take the entire path.
41 bool GetPathFromNSObject(id obj, std::string* output) {
42 if (NSString* str = base::mac::ObjCCast<NSString>(obj)) {
43 output->assign([str fileSystemRepresentation]);
44 return true;
45 } else if (NSURL* url = base::mac::ObjCCast<NSURL>(obj)) {
grt (UTC plus 2) 2015/11/02 20:20:15 remove "else" here and below since each if() body
46 output->assign([[url path] fileSystemRepresentation]);
47 return true;
48 } else if (NSBundle* bundle = base::mac::ObjCCast<NSBundle>(obj)) {
49 //TODO(kerrnel): remove this since we don't do nested code?
50 output->assign([[bundle bundlePath] fileSystemRepresentation]);
51 return true;
52 }
53 return false;
54 }
55
56 // Extract the signature information from the mach-o or extended attributes.
57 void ExtractSignatureInfo(const base::FilePath& path,
58 ClientDownloadRequest_ImageHeaders* image_headers,
59 ClientDownloadRequest_SignatureInfo* signature) {
60 scoped_refptr<BinaryFeatureExtractor> bfe = new BinaryFeatureExtractor();
61
62 // TODO(kerrnel): if Chrome ever opts into the OS X "kill" semantics, this
63 // call has to change. `ExtractImageFeatures` maps the file, which will
64 // cause Chrome to be killed before it can report on the invalid file.
65 // This call will need to read(2) the binary into a buffer.
66 if (!bfe->ExtractImageFeatures(
67 path,
68 BinaryFeatureExtractor::kDefaultOptions,
69 image_headers,
70 signature->mutable_signed_data())) {
71 // If this is not a mach-o file, search inside the extended attributes.
72 for (const char* attr : xattrs) {
73 ssize_t size = getxattr(path.value().c_str(), attr, nullptr, 0, 0, 0);
74 if (size >= 0) {
75 std::vector<uint8_t> xattr_data(size);
76 ssize_t post_size = getxattr(path.value().c_str(), attr,
77 &xattr_data[0], xattr_data.size(), 0, 0);
78 if (post_size >= 0) {
79 xattr_data.resize(post_size);
80 ClientDownloadRequest_ExtendedAttr* xattr_msg =
81 signature->add_xattr();
Robert Sesek 2015/11/02 19:42:12 nit: +2
grt (UTC plus 2) 2015/11/02 20:20:15 nit: indent
82 xattr_msg->set_key(attr);
83 xattr_msg->set_value(xattr_data.data(), xattr_data.size());
84 }
85 }
86 }
87 }
88 }
89
90 // Process the NSError information about any files that were altered.
91 void ReportAlteredFiles(
92 id detail,
93 const base::FilePath& bundle_path,
94 ClientIncidentReport_IncidentData_BinaryIntegrityIncident* incident) {
95 if (NSArray* arr = base::mac::ObjCCast<NSArray>(detail)) {
96 for (id obj in arr)
97 ReportAlteredFiles(obj, bundle_path, incident);
98 } else {
99 std::string path_str;
100 if (!GetPathFromNSObject(detail, &path_str))
101 return;
102 std::string relative_path;
103 base::FilePath path(path_str);
104 // If the relative path calculation fails, at least take the basename.
105 if (!MacSignatureEvaluator::GetRelativePathComponent(bundle_path,
106 path,
107 &relative_path)) {
108 relative_path = path.BaseName().value();
109 }
110
111 ClientIncidentReport_IncidentData_BinaryIntegrityIncident_ContainedFile*
112 contained_file = incident->add_contained_file();
Robert Sesek 2015/11/02 19:42:12 nit: +2
113 contained_file->set_relative_path(relative_path);
114 ExtractSignatureInfo(base::FilePath(path_str),
115 contained_file->mutable_image_headers(),
116 contained_file->mutable_signature());
117 }
118 }
119
120 } // namespace
121
122 MacSignatureEvaluator::MacSignatureEvaluator(
123 const base::FilePath& signed_object_path)
124 : path_(signed_object_path),
125 requirement_str_(),
126 has_requirement_(false),
127 code_(nullptr),
128 requirement_(nullptr) {}
129
130 MacSignatureEvaluator::MacSignatureEvaluator(
131 const base::FilePath& signed_object_path,
132 const std::string& requirement)
133 : path_(signed_object_path),
134 requirement_str_(requirement),
135 has_requirement_(true),
136 code_(nullptr),
137 requirement_(nullptr) {}
138
139 MacSignatureEvaluator::~MacSignatureEvaluator() {}
140
141 bool MacSignatureEvaluator::GetRelativePathComponent(
142 const base::FilePath& parent,
143 const base::FilePath& child,
144 std::string* out) {
145 if (!parent.IsParent(child))
146 return false;
147
148 std::vector<base::FilePath::StringType> parent_components;
149 std::vector<base::FilePath::StringType> child_components;
150 parent.GetComponents(&parent_components);
151 child.GetComponents(&child_components);
152
153 size_t i = 0;
154 while (i < parent_components.size() &&
155 child_components[i] == parent_components[i]) {
156 ++i;
157 }
158
159 while (i < child_components.size()) {
160 out->append(child_components[i]);
161 if (++i < child_components.size())
162 out->append("/");
163 }
164 return true;
165 }
166
167 bool MacSignatureEvaluator::Initialize() {
168 base::scoped_nsobject<NSURL> code_url([[NSURL alloc]
169 initFileURLWithPath:base::SysUTF8ToNSString(path_.value())]);
170 if (!code_url)
171 return false;
172
173 if (SecStaticCodeCreateWithPath(base::mac::NSToCFCast(code_url.get()),
174 kSecCSDefaultFlags,
175 code_.InitializeInto()) != errSecSuccess) {
176 return false;
177 }
178
179 if (has_requirement_) {
180 if (SecRequirementCreateWithString(
181 base::mac::NSToCFCast(base::SysUTF8ToNSString(requirement_str_)),
182 kSecCSDefaultFlags, requirement_.InitializeInto()) !=
183 errSecSuccess) {
184 return false;
185 }
186 }
187 return true;
188 }
189
190 bool MacSignatureEvaluator::PerformEvaluation(
191 ClientIncidentReport_IncidentData_BinaryIntegrityIncident* incident) {
192 DCHECK(incident->contained_file_size() == 0);
193 base::ScopedCFTypeRef<CFErrorRef> errors;
194 OSStatus err = SecStaticCodeCheckValidityWithErrors(
195 code_, kSecCSCheckAllArchitectures, requirement_,
196 errors.InitializeInto());
197 if (err == errSecSuccess)
198 return true;
199 // Add the signature of the main binary to the incident report.
200 incident->set_file_basename(path_.BaseName().value());
201 incident->set_sec_error(err);
202 // We heuristically detect if we are in a bundle or not by checking if
203 // the main executable is different from the path_.
204 base::ScopedCFTypeRef<CFDictionaryRef> info_dict;
205 if (SecCodeCopySigningInformation(code_,
206 kSecCSDefaultFlags,
207 info_dict.InitializeInto()) ==
208 errSecSuccess) {
209 CFURLRef exec_url = base::mac::CFCastStrict<CFURLRef>(
210 CFDictionaryGetValue(info_dict, kSecCodeInfoMainExecutable));
211 if (!exec_url)
212 return false;
213
214 base::FilePath exec_path(
215 [[base::mac::CFToNSCast(exec_url) path] fileSystemRepresentation]);
216 if (exec_path != path_) {
217 ReportAlteredFiles(base::mac::CFToNSCast(exec_url), path_, incident);
218 } else {
219 // We may be examing a flat executable file, so extract any signature.
220 ExtractSignatureInfo(path_,
221 incident->mutable_image_headers(),
222 incident->mutable_signature());
223 }
224 }
225
226 if (errors) {
227 NSDictionary* info = [base::mac::CFToNSCast(errors.get()) userInfo];
228 static const CFStringRef keys[] = {
229 kSecCFErrorResourceAltered, kSecCFErrorResourceMissing,
230 };
231 for (CFStringRef key : keys) {
232 if (id detail = [info objectForKey:base::mac::CFToNSCast(key)])
233 ReportAlteredFiles(detail, path_, incident);
234 }
235 }
236 return false;
237 }
238
239 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698