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

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 2. 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 if (value_bytes->size() < terminator_size) {
557 value_bytes->insert(value_bytes->end(),
558 (terminator_size - value_bytes->size()), 0);
grt (UTC plus 2) 2017/07/21 08:09:00 nit: i would omit these extra parens around the ar
penny 2017/07/25 18:30:48 Done.
559 }
560
561 // Sanity check content size based on character size.
562 DWORD modulo = value_bytes->size() % sizeof(wchar_t);
563 value_bytes->insert(value_bytes->end(), modulo, 0);
564
565 // Now finally check for trailing terminator.
566 bool terminated = true;
567 size_t last_element = value_bytes->size() - 1;
568 for (size_t i = 0; i < terminator_size; i++) {
569 if ((*value_bytes)[last_element - i] != 0) {
570 terminated = false;
571 break;
572 }
573 }
574
575 if (terminated)
576 return;
577
578 // Append a full terminator to be safe.
579 value_bytes->insert(value_bytes->end(), terminator_size, 0);
580
581 return;
582 }
583
545 //------------------------------------------------------------------------------ 584 //------------------------------------------------------------------------------
546 // Misc wrapper functions - LOCAL 585 // Misc wrapper functions - LOCAL
547 //------------------------------------------------------------------------------ 586 //------------------------------------------------------------------------------
548 587
549 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, 588 NTSTATUS CreateKeyWrapper(const std::wstring& key_path,
550 ACCESS_MASK access, 589 ACCESS_MASK access,
551 HANDLE* out_handle, 590 HANDLE* out_handle,
552 ULONG* create_or_open OPTIONAL) { 591 ULONG* create_or_open OPTIONAL) {
553 UNICODE_STRING key_path_uni = {}; 592 UNICODE_STRING key_path_uni = {};
554 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); 593 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); 781 g_nt_close(key);
743 } 782 }
744 783
745 //------------------------------------------------------------------------------ 784 //------------------------------------------------------------------------------
746 // Getter functions 785 // Getter functions
747 //------------------------------------------------------------------------------ 786 //------------------------------------------------------------------------------
748 787
749 bool QueryRegKeyValue(HANDLE key, 788 bool QueryRegKeyValue(HANDLE key,
750 const wchar_t* value_name, 789 const wchar_t* value_name,
751 ULONG* out_type, 790 ULONG* out_type,
752 BYTE** out_buffer, 791 std::vector<BYTE>* out_buffer) {
753 DWORD* out_size) {
754 if (!g_initialized) 792 if (!g_initialized)
755 InitNativeRegApi(); 793 InitNativeRegApi();
756 794
757 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; 795 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
758 UNICODE_STRING value_uni = {}; 796 UNICODE_STRING value_uni = {};
759 g_rtl_init_unicode_string(&value_uni, value_name); 797 g_rtl_init_unicode_string(&value_uni, value_name);
760 DWORD size_needed = 0; 798 DWORD size_needed = 0;
761 bool success = false; 799 bool success = false;
762 800
763 // First call to find out how much room we need for the value! 801 // First call to find out how much room we need for the value!
764 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 802 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
765 nullptr, 0, &size_needed); 803 nullptr, 0, &size_needed);
766 if (ntstatus != STATUS_BUFFER_TOO_SMALL) 804 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
767 return false; 805 return false;
768 806
769 KEY_VALUE_FULL_INFORMATION* value_info = 807 KEY_VALUE_FULL_INFORMATION* value_info =
770 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]); 808 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]);
grt (UTC plus 2) 2017/07/21 08:09:00 please use std::unique_ptr where possible to avoid
penny 2017/07/25 18:30:47 Done.
771 809
772 // Second call to get the value. 810 // Second call to get the value.
773 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, 811 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
774 value_info, size_needed, &size_needed); 812 value_info, size_needed, &size_needed);
775 if (NT_SUCCESS(ntstatus)) { 813 if (NT_SUCCESS(ntstatus)) {
776 *out_type = value_info->Type; 814 *out_type = value_info->Type;
777 *out_size = value_info->DataLength; 815 DWORD data_size = value_info->DataLength;
778 *out_buffer = new BYTE[*out_size]; 816
779 ::memcpy(*out_buffer, 817 if (data_size) {
780 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset), 818 // Move the data into |out_buffer| vector.
781 *out_size); 819 BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset;
820 out_buffer->assign(data, data + data_size);
821 } else {
822 out_buffer->clear();
823 }
782 success = true; 824 success = true;
783 } 825 }
784 826
785 delete[] value_info; 827 delete[] value_info;
786 return success; 828 return success;
787 } 829 }
788 830
789 // wrapper function 831 // wrapper function
790 bool QueryRegValueDWORD(HANDLE key, 832 bool QueryRegValueDWORD(HANDLE key,
791 const wchar_t* value_name, 833 const wchar_t* value_name,
792 DWORD* out_dword) { 834 DWORD* out_dword) {
793 ULONG type = REG_NONE; 835 ULONG type = REG_NONE;
794 BYTE* value_bytes = nullptr; 836 std::vector<BYTE> value_bytes;
795 DWORD ret_size = 0;
796 837
797 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 838 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
798 type != REG_DWORD) 839 type != REG_DWORD) {
840 return false;
841 }
842
843 if (value_bytes.size() < sizeof(*out_dword))
799 return false; 844 return false;
800 845
801 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); 846 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes.data()));
802 847
803 delete[] value_bytes;
804 return true; 848 return true;
805 } 849 }
806 850
807 // wrapper function 851 // wrapper function
808 bool QueryRegValueDWORD(ROOT_KEY root, 852 bool QueryRegValueDWORD(ROOT_KEY root,
809 WOW64_OVERRIDE wow64_override, 853 WOW64_OVERRIDE wow64_override,
810 const wchar_t* key_path, 854 const wchar_t* key_path,
811 const wchar_t* value_name, 855 const wchar_t* value_name,
812 DWORD* out_dword) { 856 DWORD* out_dword) {
813 HANDLE key = INVALID_HANDLE_VALUE; 857 HANDLE key = INVALID_HANDLE_VALUE;
814 858
815 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) 859 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
816 return false; 860 return false;
817 861
818 if (!QueryRegValueDWORD(key, value_name, out_dword)) { 862 if (!QueryRegValueDWORD(key, value_name, out_dword)) {
819 CloseRegKey(key); 863 CloseRegKey(key);
820 return false; 864 return false;
821 } 865 }
822 866
823 CloseRegKey(key); 867 CloseRegKey(key);
824 return true; 868 return true;
825 } 869 }
826 870
827 // wrapper function 871 // wrapper function
828 bool QueryRegValueSZ(HANDLE key, 872 bool QueryRegValueSZ(HANDLE key,
829 const wchar_t* value_name, 873 const wchar_t* value_name,
830 std::wstring* out_sz) { 874 std::wstring* out_sz) {
831 BYTE* value_bytes = nullptr; 875 std::vector<BYTE> value_bytes;
832 DWORD ret_size = 0;
833 ULONG type = REG_NONE; 876 ULONG type = REG_NONE;
834 877
835 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 878 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
836 type != REG_SZ) 879 (type != REG_SZ && type != REG_EXPAND_SZ)) {
grt (UTC plus 2) 2017/07/21 08:09:00 maybe document in .h that REG_EXPAND_SZ values are
penny 2017/07/25 18:30:48 The .h function documentation declares support for
837 return false; 880 return false;
881 }
838 882
839 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); 883 EnsureTerminatedSZ(&value_bytes, false);
840 884
841 delete[] value_bytes; 885 *out_sz = reinterpret_cast<wchar_t*>(value_bytes.data());
886
842 return true; 887 return true;
843 } 888 }
844 889
845 // wrapper function 890 // wrapper function
846 bool QueryRegValueSZ(ROOT_KEY root, 891 bool QueryRegValueSZ(ROOT_KEY root,
847 WOW64_OVERRIDE wow64_override, 892 WOW64_OVERRIDE wow64_override,
848 const wchar_t* key_path, 893 const wchar_t* key_path,
849 const wchar_t* value_name, 894 const wchar_t* value_name,
850 std::wstring* out_sz) { 895 std::wstring* out_sz) {
851 HANDLE key = INVALID_HANDLE_VALUE; 896 HANDLE key = INVALID_HANDLE_VALUE;
852 897
853 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) 898 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL))
854 return false; 899 return false;
855 900
856 if (!QueryRegValueSZ(key, value_name, out_sz)) { 901 if (!QueryRegValueSZ(key, value_name, out_sz)) {
857 CloseRegKey(key); 902 CloseRegKey(key);
858 return false; 903 return false;
859 } 904 }
860 905
861 CloseRegKey(key); 906 CloseRegKey(key);
862 return true; 907 return true;
863 } 908 }
864 909
865 // wrapper function 910 // wrapper function
866 bool QueryRegValueMULTISZ(HANDLE key, 911 bool QueryRegValueMULTISZ(HANDLE key,
867 const wchar_t* value_name, 912 const wchar_t* value_name,
868 std::vector<std::wstring>* out_multi_sz) { 913 std::vector<std::wstring>* out_multi_sz) {
869 BYTE* value_bytes = nullptr; 914 std::vector<BYTE> value_bytes;
870 DWORD ret_size = 0;
871 ULONG type = REG_NONE; 915 ULONG type = REG_NONE;
872 916
873 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || 917 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
874 type != REG_MULTI_SZ) 918 type != REG_MULTI_SZ) {
875 return false; 919 return false;
920 }
876 921
877 // Make sure the vector is empty to start. 922 EnsureTerminatedSZ(&value_bytes, true);
878 (*out_multi_sz).resize(0);
879 923
880 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes); 924 // Make sure the out vector is empty to start.
925 (*out_multi_sz).clear();
grt (UTC plus 2) 2017/07/21 08:09:00 out_multi_sz->clear();
penny 2017/07/25 18:30:47 Done.
926
927 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes.data());
881 std::wstring temp = pointer; 928 std::wstring temp = pointer;
882 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in 929 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in
883 // a row). 930 // a row).
884 while (temp.length() != 0) { 931 while (temp.length() != 0) {
885 (*out_multi_sz).push_back(temp);
886
887 pointer += temp.length() + 1; 932 pointer += temp.length() + 1;
933 (*out_multi_sz).push_back(std::move(temp));
grt (UTC plus 2) 2017/07/21 08:09:00 out_multi_sz->push_back(std::move(temp));
penny 2017/07/25 18:30:48 Done.
888 temp = pointer; 934 temp = pointer;
889 } 935 }
890 936
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; 937 return true;
897 } 938 }
898 939
899 // wrapper function 940 // wrapper function
900 bool QueryRegValueMULTISZ(ROOT_KEY root, 941 bool QueryRegValueMULTISZ(ROOT_KEY root,
901 WOW64_OVERRIDE wow64_override, 942 WOW64_OVERRIDE wow64_override,
902 const wchar_t* key_path, 943 const wchar_t* key_path,
903 const wchar_t* value_name, 944 const wchar_t* value_name,
904 std::vector<std::wstring>* out_multi_sz) { 945 std::vector<std::wstring>* out_multi_sz) {
905 HANDLE key = INVALID_HANDLE_VALUE; 946 HANDLE key = INVALID_HANDLE_VALUE;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 if (!g_initialized) 1130 if (!g_initialized)
1090 InitNativeRegApi(); 1131 InitNativeRegApi();
1091 1132
1092 if (root == HKCU || (root == AUTO && !g_system_install)) 1133 if (root == HKCU || (root == AUTO && !g_system_install))
1093 return g_HKCU_override; 1134 return g_HKCU_override;
1094 1135
1095 return g_HKLM_override; 1136 return g_HKLM_override;
1096 } 1137 }
1097 1138
1098 }; // namespace nt 1139 }; // 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