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

Side by Side Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 2885243002: [NtRegistry] Ensure REG_SZ and REG_MULTI_SZ are null terminated. (Closed)
Patch Set: Code review fixes, part 3. Created 3 years, 5 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
« no previous file with comments | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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_elf/nt_registry/nt_registry.h" 5 #include "chrome_elf/nt_registry/nt_registry.h"
6 6
7 #include <assert.h> 7 #include <assert.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 9
10 #include <memory>
11
10 namespace { 12 namespace {
11 13
12 // Function pointers used for registry access. 14 // Function pointers used for registry access.
13 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; 15 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr;
14 NtCreateKeyFunction g_nt_create_key = nullptr; 16 NtCreateKeyFunction g_nt_create_key = nullptr;
15 NtDeleteKeyFunction g_nt_delete_key = nullptr; 17 NtDeleteKeyFunction g_nt_delete_key = nullptr;
16 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; 18 NtOpenKeyExFunction g_nt_open_key_ex = nullptr;
17 NtCloseFunction g_nt_close = nullptr; 19 NtCloseFunction g_nt_close = nullptr;
18 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; 20 NtQueryValueKeyFunction g_nt_query_value_key = nullptr;
19 NtSetValueKeyFunction g_nt_set_value_key = nullptr; 21 NtSetValueKeyFunction g_nt_set_value_key = nullptr;
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 out_base->push_back(L'\\'); 537 out_base->push_back(L'\\');
536 } 538 }
537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); 539 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens);
538 } else { 540 } else {
539 out_base->assign(converted_root); 541 out_base->assign(converted_root);
540 } 542 }
541 543
542 return true; 544 return true;
543 } 545 }
544 546
547 // String safety.
548 // - NOTE: only working with wchar_t here.
549 // - Also ensures the content of |value_bytes| is at least a terminator.
550 // - Pass "true" for |multi| for MULTISZ.
551 void EnsureTerminatedSZ(std::vector<BYTE>* value_bytes, bool multi) {
552 DWORD terminator_size = sizeof(wchar_t);
553
554 if (multi)
555 terminator_size = 2 * sizeof(wchar_t);
556
557 // Ensure content is at least the size of a terminator.
558 if (value_bytes->size() < terminator_size) {
559 value_bytes->insert(value_bytes->end(),
560 terminator_size - value_bytes->size(), 0);
561 }
562
563 // Sanity check content size based on character size.
564 DWORD modulo = value_bytes->size() % sizeof(wchar_t);
565 value_bytes->insert(value_bytes->end(), modulo, 0);
566
567 // Now finally check for trailing terminator.
568 bool terminated = true;
569 size_t last_element = value_bytes->size() - 1;
570 for (size_t i = 0; i < terminator_size; i++) {
571 if ((*value_bytes)[last_element - i] != 0) {
572 terminated = false;
573 break;
574 }
575 }
576
577 if (terminated)
578 return;
579
580 // Append a full terminator to be safe.
581 value_bytes->insert(value_bytes->end(), terminator_size, 0);
582
583 return;
584 }
585
545 //------------------------------------------------------------------------------ 586 //------------------------------------------------------------------------------
546 // Misc wrapper functions - LOCAL 587 // Misc wrapper functions - LOCAL
547 //------------------------------------------------------------------------------ 588 //------------------------------------------------------------------------------
548 589
549 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, 590 NTSTATUS CreateKeyWrapper(const std::wstring& key_path,
550 ACCESS_MASK access, 591 ACCESS_MASK access,
551 HANDLE* out_handle, 592 HANDLE* out_handle,
552 ULONG* create_or_open OPTIONAL) { 593 ULONG* create_or_open OPTIONAL) {
553 UNICODE_STRING key_path_uni = {}; 594 UNICODE_STRING key_path_uni = {};
554 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); 595 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str());
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 g_nt_close(key); 783 g_nt_close(key);
743 } 784 }
744 785
745 //------------------------------------------------------------------------------ 786 //------------------------------------------------------------------------------
746 // Getter functions 787 // Getter functions
747 //------------------------------------------------------------------------------ 788 //------------------------------------------------------------------------------
748 789
749 bool QueryRegKeyValue(HANDLE key, 790 bool QueryRegKeyValue(HANDLE key,
750 const wchar_t* value_name, 791 const wchar_t* value_name,
751 ULONG* out_type, 792 ULONG* out_type,
752 BYTE** out_buffer, 793 std::vector<BYTE>* out_buffer) {
753 DWORD* out_size) {
754 if (!g_initialized) 794 if (!g_initialized)
755 InitNativeRegApi(); 795 InitNativeRegApi();
756 796
757 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; 797 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
758 UNICODE_STRING value_uni = {}; 798 UNICODE_STRING value_uni = {};
759 g_rtl_init_unicode_string(&value_uni, value_name); 799 g_rtl_init_unicode_string(&value_uni, value_name);
760 DWORD size_needed = 0; 800 DWORD size_needed = 0;
761 bool success = false;
762 801
763 // First call to find out how much room we need for the value! 802 // First call to find out how much room we need for the value!
764 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 803 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
765 nullptr, 0, &size_needed); 804 nullptr, 0, &size_needed);
766 if (ntstatus != STATUS_BUFFER_TOO_SMALL) 805 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
767 return false; 806 return false;
768 807
808 std::unique_ptr<BYTE[]> buffer(new BYTE[size_needed]);
769 KEY_VALUE_FULL_INFORMATION* value_info = 809 KEY_VALUE_FULL_INFORMATION* value_info =
770 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]); 810 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.get());
771 811
772 // Second call to get the value. 812 // Second call to get the value.
773 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 813 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
774 value_info, size_needed, &size_needed); 814 value_info, size_needed, &size_needed);
775 if (NT_SUCCESS(ntstatus)) { 815 if (!NT_SUCCESS(ntstatus))
776 *out_type = value_info->Type; 816 return false;
777 *out_size = value_info->DataLength; 817
778 *out_buffer = new BYTE[*out_size]; 818 *out_type = value_info->Type;
779 ::memcpy(*out_buffer, 819 DWORD data_size = value_info->DataLength;
780 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset), 820
781 *out_size); 821 if (data_size) {
782 success = true; 822 // Move the data into |out_buffer| vector.
823 BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset;
824 out_buffer->assign(data, data + data_size);
825 } else {
826 out_buffer->clear();
783 } 827 }
784 828
785 delete[] value_info; 829 return true;
786 return success;
787 } 830 }
788 831
789 // wrapper function 832 // wrapper function
790 bool QueryRegValueDWORD(HANDLE key, 833 bool QueryRegValueDWORD(HANDLE key,
791 const wchar_t* value_name, 834 const wchar_t* value_name,
792 DWORD* out_dword) { 835 DWORD* out_dword) {
793 ULONG type = REG_NONE; 836 ULONG type = REG_NONE;
794 BYTE* value_bytes = nullptr; 837 std::vector<BYTE> value_bytes;
795 DWORD ret_size = 0;
796 838
797 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 839 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
798 type != REG_DWORD) 840 type != REG_DWORD) {
841 return false;
842 }
843
844 if (value_bytes.size() < sizeof(*out_dword))
799 return false; 845 return false;
800 846
801 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); 847 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes.data()));
802 848
803 delete[] value_bytes;
804 return true; 849 return true;
805 } 850 }
806 851
807 // wrapper function 852 // wrapper function
808 bool QueryRegValueDWORD(ROOT_KEY root, 853 bool QueryRegValueDWORD(ROOT_KEY root,
809 WOW64_OVERRIDE wow64_override, 854 WOW64_OVERRIDE wow64_override,
810 const wchar_t* key_path, 855 const wchar_t* key_path,
811 const wchar_t* value_name, 856 const wchar_t* value_name,
812 DWORD* out_dword) { 857 DWORD* out_dword) {
813 HANDLE key = INVALID_HANDLE_VALUE; 858 HANDLE key = INVALID_HANDLE_VALUE;
814 859
815 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) 860 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
816 return false; 861 return false;
817 862
818 if (!QueryRegValueDWORD(key, value_name, out_dword)) { 863 if (!QueryRegValueDWORD(key, value_name, out_dword)) {
819 CloseRegKey(key); 864 CloseRegKey(key);
820 return false; 865 return false;
821 } 866 }
822 867
823 CloseRegKey(key); 868 CloseRegKey(key);
824 return true; 869 return true;
825 } 870 }
826 871
827 // wrapper function 872 // wrapper function
828 bool QueryRegValueSZ(HANDLE key, 873 bool QueryRegValueSZ(HANDLE key,
829 const wchar_t* value_name, 874 const wchar_t* value_name,
830 std::wstring* out_sz) { 875 std::wstring* out_sz) {
831 BYTE* value_bytes = nullptr; 876 std::vector<BYTE> value_bytes;
832 DWORD ret_size = 0;
833 ULONG type = REG_NONE; 877 ULONG type = REG_NONE;
834 878
835 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 879 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
836 type != REG_SZ) 880 (type != REG_SZ && type != REG_EXPAND_SZ)) {
837 return false; 881 return false;
882 }
838 883
839 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); 884 EnsureTerminatedSZ(&value_bytes, false);
840 885
841 delete[] value_bytes; 886 *out_sz = reinterpret_cast<wchar_t*>(value_bytes.data());
887
842 return true; 888 return true;
843 } 889 }
844 890
845 // wrapper function 891 // wrapper function
846 bool QueryRegValueSZ(ROOT_KEY root, 892 bool QueryRegValueSZ(ROOT_KEY root,
847 WOW64_OVERRIDE wow64_override, 893 WOW64_OVERRIDE wow64_override,
848 const wchar_t* key_path, 894 const wchar_t* key_path,
849 const wchar_t* value_name, 895 const wchar_t* value_name,
850 std::wstring* out_sz) { 896 std::wstring* out_sz) {
851 HANDLE key = INVALID_HANDLE_VALUE; 897 HANDLE key = INVALID_HANDLE_VALUE;
852 898
853 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) 899 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
854 return false; 900 return false;
855 901
856 if (!QueryRegValueSZ(key, value_name, out_sz)) { 902 if (!QueryRegValueSZ(key, value_name, out_sz)) {
857 CloseRegKey(key); 903 CloseRegKey(key);
858 return false; 904 return false;
859 } 905 }
860 906
861 CloseRegKey(key); 907 CloseRegKey(key);
862 return true; 908 return true;
863 } 909 }
864 910
865 // wrapper function 911 // wrapper function
866 bool QueryRegValueMULTISZ(HANDLE key, 912 bool QueryRegValueMULTISZ(HANDLE key,
867 const wchar_t* value_name, 913 const wchar_t* value_name,
868 std::vector<std::wstring>* out_multi_sz) { 914 std::vector<std::wstring>* out_multi_sz) {
869 BYTE* value_bytes = nullptr; 915 std::vector<BYTE> value_bytes;
870 DWORD ret_size = 0;
871 ULONG type = REG_NONE; 916 ULONG type = REG_NONE;
872 917
873 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 918 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
874 type != REG_MULTI_SZ) 919 type != REG_MULTI_SZ) {
875 return false; 920 return false;
921 }
876 922
877 // Make sure the vector is empty to start. 923 EnsureTerminatedSZ(&value_bytes, true);
878 (*out_multi_sz).resize(0);
879 924
880 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes); 925 // Make sure the out vector is empty to start.
926 out_multi_sz->clear();
927
928 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes.data());
881 std::wstring temp = pointer; 929 std::wstring temp = pointer;
882 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in 930 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in
883 // a row). 931 // a row).
884 while (temp.length() != 0) { 932 while (!temp.empty()) {
885 (*out_multi_sz).push_back(temp);
886
887 pointer += temp.length() + 1; 933 pointer += temp.length() + 1;
934 out_multi_sz->push_back(std::move(temp));
888 temp = pointer; 935 temp = pointer;
889 } 936 }
890 937
891 // Handle the case of "empty multi_sz".
892 if (out_multi_sz->size() == 0)
893 out_multi_sz->push_back(L"");
894
895 delete[] value_bytes;
896 return true; 938 return true;
897 } 939 }
898 940
899 // wrapper function 941 // wrapper function
900 bool QueryRegValueMULTISZ(ROOT_KEY root, 942 bool QueryRegValueMULTISZ(ROOT_KEY root,
901 WOW64_OVERRIDE wow64_override, 943 WOW64_OVERRIDE wow64_override,
902 const wchar_t* key_path, 944 const wchar_t* key_path,
903 const wchar_t* value_name, 945 const wchar_t* value_name,
904 std::vector<std::wstring>* out_multi_sz) { 946 std::vector<std::wstring>* out_multi_sz) {
905 HANDLE key = INVALID_HANDLE_VALUE; 947 HANDLE key = INVALID_HANDLE_VALUE;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 if (!g_initialized) 1131 if (!g_initialized)
1090 InitNativeRegApi(); 1132 InitNativeRegApi();
1091 1133
1092 if (root == HKCU || (root == AUTO && !g_system_install)) 1134 if (root == HKCU || (root == AUTO && !g_system_install))
1093 return g_HKCU_override; 1135 return g_HKCU_override;
1094 1136
1095 return g_HKLM_override; 1137 return g_HKLM_override;
1096 } 1138 }
1097 1139
1098 }; // namespace nt 1140 }; // namespace nt
OLDNEW
« no previous file with comments | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698