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

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 1. 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 namespace { 10 namespace {
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 out_base->push_back(L'\\'); 535 out_base->push_back(L'\\');
536 } 536 }
537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); 537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens);
538 } else { 538 } else {
539 out_base->assign(converted_root); 539 out_base->assign(converted_root);
540 } 540 }
541 541
542 return true; 542 return true;
543 } 543 }
544 544
545 // String safety.
546 // - NOTE: only working with wchar_t here.
547 // - Also ensures the content of |value_bytes| is at least a terminator.
548 // - Pass "true" for |multi| for MULTISZ.
549 void EnsureTerminatedSZ(std::vector<BYTE>* value_bytes, bool multi) {
550 DWORD terminator_size = sizeof(wchar_t);
551
552 if (multi)
553 terminator_size = 2 * sizeof(wchar_t);
554
555 // Ensure content is at least the size of a terminator.
556 for (size_t i = value_bytes->size(); i < terminator_size; i++)
grt (UTC plus 2) 2017/07/20 05:22:53 if (value_bytes->size() < terminator_size) { v
penny 2017/07/20 18:38:37 Done. <sigh> Thank you for your 1337 c++ skillz
557 value_bytes->push_back(0);
558
559 // Sanity check content size based on character size.
560 DWORD modulo = value_bytes->size() % sizeof(wchar_t);
561 while (modulo) {
grt (UTC plus 2) 2017/07/20 05:22:53 value_bytes->insert(value_bytes->end(), modulo, 0)
penny 2017/07/20 18:38:37 Done.
562 value_bytes->push_back(0);
563 modulo--;
564 }
565
566 // Now finally check for trailing terminator.
567 bool terminated = true;
568 size_t last_element = value_bytes->size() - 1;
569 for (size_t i = 0; i < terminator_size; i++) {
570 if ((*value_bytes)[last_element - i] != 0) {
571 terminated = false;
572 break;
573 }
574 }
575
576 if (terminated)
577 return;
578
579 // Append a full terminator to be safe.
580 for (size_t i = 0; i < terminator_size; i++)
grt (UTC plus 2) 2017/07/20 05:22:53 value_bytes->insert(value_bytes->end(), terminator
penny 2017/07/20 18:38:37 Done.
581 value_bytes->push_back(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; 801 bool success = false;
762 802
763 // First call to find out how much room we need for the value! 803 // First call to find out how much room we need for the value!
764 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 804 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
765 nullptr, 0, &size_needed); 805 nullptr, 0, &size_needed);
766 if (ntstatus != STATUS_BUFFER_TOO_SMALL) 806 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
767 return false; 807 return false;
768 808
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*>(new BYTE[size_needed]);
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 *out_type = value_info->Type;
777 *out_size = value_info->DataLength; 817 DWORD data_size = value_info->DataLength;
778 *out_buffer = new BYTE[*out_size]; 818 out_buffer->clear();
grt (UTC plus 2) 2017/07/20 05:22:53 nit: by using assign() below, clear() is only need
penny 2017/07/20 18:38:36 Done.
779 ::memcpy(*out_buffer, 819 if (data_size) {
780 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset), 820 // Move the data into |out_buffer| vector.
781 *out_size); 821 BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset;
822 for (size_t i = 0; i < data_size; i++)
grt (UTC plus 2) 2017/07/20 05:22:53 out_buffer->assign(data, data + data_size);
penny 2017/07/20 18:38:37 assign. thank you.
823 out_buffer->push_back(data[i]);
824 }
782 success = true; 825 success = true;
783 } 826 }
784 827
785 delete[] value_info; 828 delete[] value_info;
786 return success; 829 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());
grt (UTC plus 2) 2017/07/20 05:22:53 should this preserve embedded nulls? if yes, use o
penny 2017/07/20 18:38:37 I never expected the result of the QueryRegValueSZ
grt (UTC plus 2) 2017/07/21 08:09:00 Sounds reasonable to me. Please document this beha
penny 2017/07/25 18:30:47 Done.
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;
robertshield 2017/07/20 17:14:04 Won't this truncate any characters after the first
penny 2017/07/20 18:38:37 No. It merely creates a new wstring object, and c
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.length() != 0) {
grt (UTC plus 2) 2017/07/20 05:22:53 nit: !temp.empty()
penny 2017/07/20 18:38:37 I wasn't entirely sure whether an empty string (""
grt (UTC plus 2) 2017/07/21 08:09:00 The spec more-or-less says that a std::basic_strin
penny 2017/07/25 18:30:47 Done. Clear as mud!
885 (*out_multi_sz).push_back(temp); 933 (*out_multi_sz).push_back(temp);
grt (UTC plus 2) 2017/07/20 05:22:53 nit: avoid making another copy of |temp| with:
penny 2017/07/20 18:38:36 Done. I didn't even think push_back could take th
grt (UTC plus 2) 2017/07/21 08:09:00 I didn't know either -- I just figured something l
886 934
887 pointer += temp.length() + 1; 935 pointer += temp.length() + 1;
888 temp = pointer; 936 temp = pointer;
889 } 937 }
890 938
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; 939 return true;
897 } 940 }
898 941
899 // wrapper function 942 // wrapper function
900 bool QueryRegValueMULTISZ(ROOT_KEY root, 943 bool QueryRegValueMULTISZ(ROOT_KEY root,
901 WOW64_OVERRIDE wow64_override, 944 WOW64_OVERRIDE wow64_override,
902 const wchar_t* key_path, 945 const wchar_t* key_path,
903 const wchar_t* value_name, 946 const wchar_t* value_name,
904 std::vector<std::wstring>* out_multi_sz) { 947 std::vector<std::wstring>* out_multi_sz) {
905 HANDLE key = INVALID_HANDLE_VALUE; 948 HANDLE key = INVALID_HANDLE_VALUE;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 if (!g_initialized) 1132 if (!g_initialized)
1090 InitNativeRegApi(); 1133 InitNativeRegApi();
1091 1134
1092 if (root == HKCU || (root == AUTO && !g_system_install)) 1135 if (root == HKCU || (root == AUTO && !g_system_install))
1093 return g_HKCU_override; 1136 return g_HKCU_override;
1094 1137
1095 return g_HKLM_override; 1138 return g_HKLM_override;
1096 } 1139 }
1097 1140
1098 }; // namespace nt 1141 }; // 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