]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c
MdeModulePkg: Fix use-after-free error in InstallConfigurationTable()
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / InstallConfigurationTable.c
1 /** @file
2 UEFI Miscellaneous boot Services InstallConfigurationTable service
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "DxeMain.h"
16
17 #define CONFIG_TABLE_SIZE_INCREASED 0x10
18
19 UINTN mSystemTableAllocateSize = 0;
20
21 /**
22 Boot Service called to add, modify, or remove a system configuration table from
23 the EFI System Table.
24
25 @param Guid Pointer to the GUID for the entry to add, update, or
26 remove
27 @param Table Pointer to the configuration table for the entry to add,
28 update, or remove, may be NULL.
29
30 @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
31 @return EFI_INVALID_PARAMETER Input GUID is NULL.
32 @return EFI_NOT_FOUND Attempted to delete non-existant entry
33 @return EFI_OUT_OF_RESOURCES Not enough memory available
34
35 **/
36 EFI_STATUS
37 EFIAPI
38 CoreInstallConfigurationTable (
39 IN EFI_GUID *Guid,
40 IN VOID *Table
41 )
42 {
43 UINTN Index;
44 EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
45 EFI_CONFIGURATION_TABLE *OldTable;
46
47 //
48 // If Guid is NULL, then this operation cannot be performed
49 //
50 if (Guid == NULL) {
51 return EFI_INVALID_PARAMETER;
52 }
53
54 EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
55
56 //
57 // Search all the table for an entry that matches Guid
58 //
59 for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
60 if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
61 break;
62 }
63 }
64
65 if (Index < gDxeCoreST->NumberOfTableEntries) {
66 //
67 // A match was found, so this is either a modify or a delete operation
68 //
69 if (Table != NULL) {
70 //
71 // If Table is not NULL, then this is a modify operation.
72 // Modify the table entry and return.
73 //
74 gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
75
76 //
77 // Signal Configuration Table change
78 //
79 CoreNotifySignalList (Guid);
80
81 return EFI_SUCCESS;
82 }
83
84 //
85 // A match was found and Table is NULL, so this is a delete operation.
86 //
87 gDxeCoreST->NumberOfTableEntries--;
88
89 //
90 // Copy over deleted entry
91 //
92 CopyMem (
93 &(EfiConfigurationTable[Index]),
94 &(gDxeCoreST->ConfigurationTable[Index + 1]),
95 (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
96 );
97
98 } else {
99
100 //
101 // No matching GUIDs were found, so this is an add operation.
102 //
103
104 if (Table == NULL) {
105 //
106 // If Table is NULL on an add operation, then return an error.
107 //
108 return EFI_NOT_FOUND;
109 }
110
111 //
112 // Assume that Index == gDxeCoreST->NumberOfTableEntries
113 //
114 if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
115 //
116 // Allocate a table with one additional entry.
117 //
118 mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
119 EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
120 if (EfiConfigurationTable == NULL) {
121 //
122 // If a new table could not be allocated, then return an error.
123 //
124 return EFI_OUT_OF_RESOURCES;
125 }
126
127 if (gDxeCoreST->ConfigurationTable != NULL) {
128 //
129 // Copy the old table to the new table.
130 //
131 CopyMem (
132 EfiConfigurationTable,
133 gDxeCoreST->ConfigurationTable,
134 Index * sizeof (EFI_CONFIGURATION_TABLE)
135 );
136
137 //
138 // Record the old table pointer.
139 //
140 OldTable = gDxeCoreST->ConfigurationTable;
141
142 //
143 // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
144 // in its calling stack, updating System table to the new table pointer must
145 // be done before calling CoreFreePool() to free the old table.
146 // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
147 // and avoid the errors of use-after-free to the old table by the reenter of
148 // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
149 //
150 gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
151
152 //
153 // Free the old table after updating System Table to the new table pointer.
154 //
155 CoreFreePool (OldTable);
156 } else {
157 //
158 // Update System Table
159 //
160 gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
161 }
162 }
163
164 //
165 // Fill in the new entry
166 //
167 CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
168 EfiConfigurationTable[Index].VendorTable = Table;
169
170 //
171 // This is an add operation, so increment the number of table entries
172 //
173 gDxeCoreST->NumberOfTableEntries++;
174 }
175
176 //
177 // Fix up the CRC-32 in the EFI System Table
178 //
179 CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
180
181 //
182 // Signal Configuration Table change
183 //
184 CoreNotifySignalList (Guid);
185
186 return EFI_SUCCESS;
187 }