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

Side by Side Diff: components/policy/core/common/preg_parser.cc

Issue 2481753002: Push preg_parser and registry_dict changes upstream (Closed)
Patch Set: Minor formatting Created 4 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "components/policy/core/common/preg_parser_win.h" 5 #include "components/policy/core/common/preg_parser.h"
6 6
7 #include <windows.h>
8 #include <stddef.h> 7 #include <stddef.h>
9 #include <stdint.h> 8 #include <stdint.h>
10 9
11 #include <algorithm> 10 #include <algorithm>
12 #include <functional> 11 #include <functional>
13 #include <iterator> 12 #include <iterator>
13 #include <memory>
14 #include <string>
14 #include <utility> 15 #include <utility>
15 #include <vector> 16 #include <vector>
16 17
17 #include "base/files/file_path.h" 18 #include "base/files/file_path.h"
18 #include "base/files/memory_mapped_file.h" 19 #include "base/files/memory_mapped_file.h"
19 #include "base/i18n/case_conversion.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/macros.h" 21 #include "base/macros.h"
22 #include "base/memory/ptr_util.h" 22 #include "base/memory/ptr_util.h"
23 #include "base/strings/string16.h" 23 #include "base/strings/string16.h"
24 #include "base/strings/string_split.h" 24 #include "base/strings/string_split.h"
25 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
26 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
27 #include "base/sys_byteorder.h" 27 #include "base/sys_byteorder.h"
28 #include "base/values.h" 28 #include "base/values.h"
29 #include "components/policy/core/common/policy_load_status.h" 29 #include "components/policy/core/common/policy_load_status.h"
30 #include "components/policy/core/common/registry_dict_win.h" 30 #include "components/policy/core/common/registry_dict.h"
31 31
32 namespace policy { 32 #if defined(OS_WIN)
33 namespace preg_parser { 33 #include "windows.h"
34 #else
35 // Registry data type constants.
36 #define REG_NONE 0
37 #define REG_SZ 1
38 #define REG_EXPAND_SZ 2
39 #define REG_BINARY 3
40 #define REG_DWORD_LITTLE_ENDIAN 4
41 #define REG_DWORD_BIG_ENDIAN 5
42 #define REG_LINK 6
43 #define REG_MULTI_SZ 7
44 #define REG_RESOURCE_LIST 8
45 #define REG_FULL_RESOURCE_DESCRIPTOR 9
46 #define REG_RESOURCE_REQUIREMENTS_LIST 10
47 #define REG_QWORD_LITTLE_ENDIAN 11
48 #endif
34 49
35 const char kPRegFileHeader[8] = 50 using RegistryDict = policy::RegistryDict;
36 { 'P', 'R', 'e', 'g', '\x01', '\x00', '\x00', '\x00' }; 51
52 namespace {
37 53
38 // Maximum PReg file size we're willing to accept. 54 // Maximum PReg file size we're willing to accept.
39 const int64_t kMaxPRegFileSize = 1024 * 1024 * 16; 55 const int64_t kMaxPRegFileSize = 1024 * 1024 * 16;
40 56
41 // Constants for PReg file delimiters. 57 // Constants for PReg file delimiters.
42 const base::char16 kDelimBracketOpen = L'['; 58 const base::char16 kDelimBracketOpen = L'[';
43 const base::char16 kDelimBracketClose = L']'; 59 const base::char16 kDelimBracketClose = L']';
44 const base::char16 kDelimSemicolon = L';'; 60 const base::char16 kDelimSemicolon = L';';
45 61
46 // Registry path separator. 62 // Registry path separator.
47 const base::char16 kRegistryPathSeparator[] = L"\\"; 63 const base::string16 kRegistryPathSeparator = base::ASCIIToUTF16("\\");
48 64
49 // Magic strings for the PReg value field to trigger special actions. 65 // Magic strings for the PReg value field to trigger special actions.
50 const char kActionTriggerPrefix[] = "**"; 66 const char kActionTriggerPrefix[] = "**";
51 const char kActionTriggerDeleteValues[] = "deletevalues"; 67 const char kActionTriggerDeleteValues[] = "deletevalues";
52 const char kActionTriggerDel[] = "del."; 68 const char kActionTriggerDel[] = "del.";
53 const char kActionTriggerDelVals[] = "delvals"; 69 const char kActionTriggerDelVals[] = "delvals";
54 const char kActionTriggerDeleteKeys[] = "deletekeys"; 70 const char kActionTriggerDeleteKeys[] = "deletekeys";
55 const char kActionTriggerSecureKey[] = "securekey"; 71 const char kActionTriggerSecureKey[] = "securekey";
56 const char kActionTriggerSoft[] = "soft"; 72 const char kActionTriggerSoft[] = "soft";
57 73
58 // Returns the character at |cursor| and increments it, unless the end is here 74 // Returns the character at |cursor| and increments it, unless the end is here
59 // in which case -1 is returned. 75 // in which case -1 is returned.
60 int NextChar(const uint8_t** cursor, const uint8_t* end) { 76 int NextChar(const uint8_t** cursor, const uint8_t* end) {
61 // Only read the character if a full base::char16 is available. 77 // Only read the character if a full base::char16 is available.
62 if (*cursor + sizeof(base::char16) > end) 78 // This comparison makes sure no overflow can happen.
79 if (*cursor >= end ||
80 static_cast<size_t>(end - *cursor) < sizeof(base::char16))
63 return -1; 81 return -1;
64 82
65 int result = **cursor | (*(*cursor + 1) << 8); 83 int result = **cursor | (*(*cursor + 1) << 8);
66 *cursor += sizeof(base::char16); 84 *cursor += sizeof(base::char16);
67 return result; 85 return result;
68 } 86 }
69 87
70 // Reads a fixed-size field from a PReg file. 88 // Reads a fixed-size field from a PReg file.
71 bool ReadFieldBinary(const uint8_t** cursor, 89 bool ReadFieldBinary(const uint8_t** cursor,
72 const uint8_t* end, 90 const uint8_t* end,
73 uint32_t size, 91 uint32_t size,
74 uint8_t* data) { 92 uint8_t* data) {
75 if (size == 0) 93 if (size == 0)
76 return true; 94 return true;
77 95
96 // Be careful to prevent possible overflows here (don't do *cursor + size).
97 if (*cursor >= end || static_cast<size_t>(end - *cursor) < size)
98 return false;
78 const uint8_t* field_end = *cursor + size; 99 const uint8_t* field_end = *cursor + size;
79 if (field_end <= *cursor || field_end > end)
80 return false;
81 std::copy(*cursor, field_end, data); 100 std::copy(*cursor, field_end, data);
82 *cursor = field_end; 101 *cursor = field_end;
83 return true; 102 return true;
84 } 103 }
85 104
86 bool ReadField32(const uint8_t** cursor, const uint8_t* end, uint32_t* data) { 105 bool ReadField32(const uint8_t** cursor, const uint8_t* end, uint32_t* data) {
87 uint32_t value = 0; 106 uint32_t value = 0;
88 if (!ReadFieldBinary(cursor, end, sizeof(uint32_t), 107 if (!ReadFieldBinary(cursor, end, sizeof(uint32_t),
89 reinterpret_cast<uint8_t*>(&value))) { 108 reinterpret_cast<uint8_t*>(&value))) {
90 return false; 109 return false;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 case REG_FULL_RESOURCE_DESCRIPTOR: 166 case REG_FULL_RESOURCE_DESCRIPTOR:
148 case REG_RESOURCE_REQUIREMENTS_LIST: 167 case REG_RESOURCE_REQUIREMENTS_LIST:
149 case REG_QWORD_LITTLE_ENDIAN: 168 case REG_QWORD_LITTLE_ENDIAN:
150 default: 169 default:
151 LOG(ERROR) << "Unsupported registry data type " << type; 170 LOG(ERROR) << "Unsupported registry data type " << type;
152 } 171 }
153 172
154 return false; 173 return false;
155 } 174 }
156 175
157 // Adds the record data passed via parameters to |dict| in case the data is 176 // Adds |value| and |data| to |dict| or an appropriate sub-dictionary indicated
158 // relevant policy for Chromium. 177 // by |key_name|. Creates sub-dictionaries if necessary. Also handles special
178 // action triggers, see |kActionTrigger*|, that can, for instance, remove an
179 // existing value.
159 void HandleRecord(const base::string16& key_name, 180 void HandleRecord(const base::string16& key_name,
160 const base::string16& value, 181 const base::string16& value,
161 uint32_t type, 182 uint32_t type,
162 const std::vector<uint8_t>& data, 183 const std::vector<uint8_t>& data,
163 RegistryDict* dict) { 184 RegistryDict* dict) {
164 // Locate/create the dictionary to place the value in. 185 // Locate/create the dictionary to place the value in.
165 std::vector<base::string16> path; 186 std::vector<base::string16> path;
166 187
167 for (const base::string16& entry : 188 for (const base::string16& entry :
168 base::SplitString(key_name, kRegistryPathSeparator, 189 base::SplitString(key_name, kRegistryPathSeparator,
(...skipping 16 matching lines...) Expand all
185 if (!base::StartsWith(value_name, kActionTriggerPrefix, 206 if (!base::StartsWith(value_name, kActionTriggerPrefix,
186 base::CompareCase::SENSITIVE)) { 207 base::CompareCase::SENSITIVE)) {
187 std::unique_ptr<base::Value> value; 208 std::unique_ptr<base::Value> value;
188 if (DecodePRegValue(type, data, &value)) 209 if (DecodePRegValue(type, data, &value))
189 dict->SetValue(value_name, std::move(value)); 210 dict->SetValue(value_name, std::move(value));
190 return; 211 return;
191 } 212 }
192 213
193 std::string action_trigger(base::ToLowerASCII(value_name.substr( 214 std::string action_trigger(base::ToLowerASCII(value_name.substr(
194 arraysize(kActionTriggerPrefix) - 1))); 215 arraysize(kActionTriggerPrefix) - 1)));
195 if (action_trigger == kActionTriggerDeleteValues) { 216 if (action_trigger == kActionTriggerDeleteValues) {
pastarmovj 2016/11/09 12:26:06 please revert.
ljusten (tachyonic) 2016/11/09 15:09:56 Done.
196 for (const std::string& value : 217 for (const std::string& value :
197 base::SplitString(DecodePRegStringValue(data), ";", 218 base::SplitString(DecodePRegStringValue(data), ";",
198 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) 219 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY))
199 dict->RemoveValue(value); 220 dict->RemoveValue(value);
200 } else if (base::StartsWith(action_trigger, kActionTriggerDeleteKeys, 221 } else if (base::StartsWith(action_trigger, kActionTriggerDeleteKeys,
201 base::CompareCase::SENSITIVE)) { 222 base::CompareCase::SENSITIVE)) {
202 for (const std::string& key : 223 for (const std::string& key :
203 base::SplitString(DecodePRegStringValue(data), ";", 224 base::SplitString(DecodePRegStringValue(data), ";",
204 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) 225 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY))
205 dict->RemoveKey(key); 226 dict->RemoveKey(key);
206 } else if (base::StartsWith(action_trigger, kActionTriggerDel, 227 } else if (base::StartsWith(action_trigger, kActionTriggerDel,
207 base::CompareCase::SENSITIVE)) { 228 base::CompareCase::SENSITIVE)) {
208 dict->RemoveValue( 229 dict->RemoveValue(
pastarmovj 2016/11/09 12:26:06 ditto.
ljusten (tachyonic) 2016/11/09 15:09:56 Done.
209 value_name.substr(arraysize(kActionTriggerPrefix) - 1 + 230 value_name.substr(arraysize(kActionTriggerPrefix) - 1 +
210 arraysize(kActionTriggerDel) - 1)); 231 arraysize(kActionTriggerDel) - 1));
211 } else if (base::StartsWith(action_trigger, kActionTriggerDelVals, 232 } else if (base::StartsWith(action_trigger, kActionTriggerDelVals,
212 base::CompareCase::SENSITIVE)) { 233 base::CompareCase::SENSITIVE)) {
213 // Delete all values. 234 // Delete all values.
214 dict->ClearValues(); 235 dict->ClearValues();
215 } else if (base::StartsWith(action_trigger, kActionTriggerSecureKey, 236 } else if (base::StartsWith(action_trigger, kActionTriggerSecureKey,
216 base::CompareCase::SENSITIVE) || 237 base::CompareCase::SENSITIVE) ||
217 base::StartsWith(action_trigger, kActionTriggerSoft, 238 base::StartsWith(action_trigger, kActionTriggerSoft,
218 base::CompareCase::SENSITIVE)) { 239 base::CompareCase::SENSITIVE)) {
219 // Doesn't affect values. 240 // Doesn't affect values.
220 } else { 241 } else {
221 LOG(ERROR) << "Bad action trigger " << value_name; 242 LOG(ERROR) << "Bad action trigger " << value_name;
222 } 243 }
223 } 244 }
224 245
246 } // namespace
247
248 namespace policy {
249 namespace preg_parser {
250
251 const char kPRegFileHeader[8] =
252 { 'P', 'R', 'e', 'g', '\x01', '\x00', '\x00', '\x00' };
253
225 bool ReadFile(const base::FilePath& file_path, 254 bool ReadFile(const base::FilePath& file_path,
226 const base::string16& root, 255 const base::string16& root,
227 RegistryDict* dict, 256 RegistryDict* dict,
228 PolicyLoadStatusSample* status) { 257 PolicyLoadStatusSample* status) {
229 base::MemoryMappedFile mapped_file; 258 base::MemoryMappedFile mapped_file;
230 if (!mapped_file.Initialize(file_path) || !mapped_file.IsValid()) { 259 if (!mapped_file.Initialize(file_path) || !mapped_file.IsValid()) {
231 PLOG(ERROR) << "Failed to map " << file_path.value(); 260 PLOG(ERROR) << "Failed to map " << file_path.value();
232 status->Add(POLICY_LOAD_STATUS_READ_ERROR); 261 status->Add(POLICY_LOAD_STATUS_READ_ERROR);
233 return false; 262 return false;
234 } 263 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 data.resize(size); 325 data.resize(size);
297 if (!ReadFieldBinary(&cursor, end, size, data.data())) 326 if (!ReadFieldBinary(&cursor, end, size, data.data()))
298 break; 327 break;
299 current = NextChar(&cursor, end); 328 current = NextChar(&cursor, end);
300 } 329 }
301 330
302 if (current != kDelimBracketClose) 331 if (current != kDelimBracketClose)
303 break; 332 break;
304 333
305 // Process the record if it is within the |root| subtree. 334 // Process the record if it is within the |root| subtree.
306 if (base::StartsWith(base::i18n::ToLower(key_name), 335 if (base::StartsWith(key_name, root, base::CompareCase::INSENSITIVE_ASCII))
pastarmovj 2016/11/09 12:26:06 I just wonder if this can be used as a way to tric
ljusten (tachyonic) 2016/11/09 15:09:56 This is not possible. Here's the proof: Theorem -
307 base::i18n::ToLower(root),
308 base::CompareCase::SENSITIVE))
309 HandleRecord(key_name.substr(root.size()), value, type, data, dict); 336 HandleRecord(key_name.substr(root.size()), value, type, data, dict);
310 } 337 }
311 338
312 LOG(ERROR) << "Error parsing " << file_path.value() << " at offset " 339 LOG(ERROR) << "Error parsing " << file_path.value() << " at offset "
313 << reinterpret_cast<const uint8_t*>(cursor - 1) - 340 << reinterpret_cast<const uint8_t*>(cursor - 1) -
314 mapped_file.data(); 341 mapped_file.data();
315 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR); 342 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR);
316 return false; 343 return false;
317 } 344 }
318 345
319 } // namespace preg_parser 346 } // namespace preg_parser
320 } // namespace policy 347 } // namespace policy
OLDNEW
« no previous file with comments | « components/policy/core/common/preg_parser.h ('k') | components/policy/core/common/preg_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698