]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / LockBox / SmmLockBox / SmmLockBox.c
1 /** @file
2 LockBox SMM driver.
3
4 Caution: This module requires additional review when modified.
5 This driver will have external input - communicate buffer in SMM mode.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 SmmLockBoxHandler(), SmmLockBoxRestore(), SmmLockBoxUpdate(), SmmLockBoxSave()
10 will receive untrusted input and do basic validation.
11
12 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
13
14 SPDX-License-Identifier: BSD-2-Clause-Patent
15
16 **/
17
18 #include <PiSmm.h>
19 #include <Library/UefiDriverEntryPoint.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/SmmMemLib.h>
27 #include <Library/LockBoxLib.h>
28
29 #include <Protocol/SmmReadyToLock.h>
30 #include <Protocol/SmmCommunication.h>
31 #include <Protocol/LockBox.h>
32 #include <Guid/SmmLockBox.h>
33
34 BOOLEAN mLocked = FALSE;
35
36 /**
37 Dispatch function for SMM lock box save.
38
39 Caution: This function may receive untrusted input.
40 Restore buffer and length are external input, so this function will validate
41 it is in SMRAM.
42
43 @param LockBoxParameterSave parameter of lock box save
44 **/
45 VOID
46 SmmLockBoxSave (
47 IN EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave
48 )
49 {
50 EFI_STATUS Status;
51 EFI_SMM_LOCK_BOX_PARAMETER_SAVE TempLockBoxParameterSave;
52
53 //
54 // Sanity check
55 //
56 if (mLocked) {
57 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
58 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
59 return ;
60 }
61
62 CopyMem (&TempLockBoxParameterSave, LockBoxParameterSave, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE));
63
64 //
65 // Sanity check
66 //
67 if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterSave.Buffer, (UINTN)TempLockBoxParameterSave.Length)) {
68 DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));
69 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
70 return ;
71 }
72 //
73 // The SpeculationBarrier() call here is to ensure the above range check for
74 // the CommBuffer have been completed before calling into SaveLockBox().
75 //
76 SpeculationBarrier ();
77
78 //
79 // Save data
80 //
81 Status = SaveLockBox (
82 &TempLockBoxParameterSave.Guid,
83 (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,
84 (UINTN)TempLockBoxParameterSave.Length
85 );
86 LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;
87 return ;
88 }
89
90 /**
91 Dispatch function for SMM lock box set attributes.
92
93 @param LockBoxParameterSetAttributes parameter of lock box set attributes
94 **/
95 VOID
96 SmmLockBoxSetAttributes (
97 IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes
98 )
99 {
100 EFI_STATUS Status;
101 EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;
102
103 //
104 // Sanity check
105 //
106 if (mLocked) {
107 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
108 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
109 return ;
110 }
111
112 CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));
113
114 //
115 // Update data
116 //
117 Status = SetLockBoxAttributes (
118 &TempLockBoxParameterSetAttributes.Guid,
119 TempLockBoxParameterSetAttributes.Attributes
120 );
121 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;
122 return ;
123 }
124
125 /**
126 Dispatch function for SMM lock box update.
127
128 Caution: This function may receive untrusted input.
129 Restore buffer and length are external input, so this function will validate
130 it is in SMRAM.
131
132 @param LockBoxParameterUpdate parameter of lock box update
133 **/
134 VOID
135 SmmLockBoxUpdate (
136 IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate
137 )
138 {
139 EFI_STATUS Status;
140 EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;
141
142 //
143 // Sanity check
144 //
145 if (mLocked) {
146 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
147 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
148 return ;
149 }
150
151 CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));
152
153 //
154 // Sanity check
155 //
156 if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {
157 DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
158 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
159 return ;
160 }
161 //
162 // The SpeculationBarrier() call here is to ensure the above range check for
163 // the CommBuffer have been completed before calling into UpdateLockBox().
164 //
165 SpeculationBarrier ();
166
167 //
168 // Update data
169 //
170 Status = UpdateLockBox (
171 &TempLockBoxParameterUpdate.Guid,
172 (UINTN)TempLockBoxParameterUpdate.Offset,
173 (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,
174 (UINTN)TempLockBoxParameterUpdate.Length
175 );
176 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;
177 return ;
178 }
179
180 /**
181 Dispatch function for SMM lock box restore.
182
183 Caution: This function may receive untrusted input.
184 Restore buffer and length are external input, so this function will validate
185 it is in SMRAM.
186
187 @param LockBoxParameterRestore parameter of lock box restore
188 **/
189 VOID
190 SmmLockBoxRestore (
191 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore
192 )
193 {
194 EFI_STATUS Status;
195 EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;
196
197 CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));
198
199 //
200 // Sanity check
201 //
202 if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
203 DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
204 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
205 return ;
206 }
207
208 //
209 // Restore data
210 //
211 if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
212 Status = RestoreLockBox (
213 &TempLockBoxParameterRestore.Guid,
214 NULL,
215 NULL
216 );
217 } else {
218 Status = RestoreLockBox (
219 &TempLockBoxParameterRestore.Guid,
220 (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
221 (UINTN *)&TempLockBoxParameterRestore.Length
222 );
223 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)) {
224 //
225 // Return the actual Length value.
226 //
227 LockBoxParameterRestore->Length = TempLockBoxParameterRestore.Length;
228 }
229 }
230 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
231 return ;
232 }
233
234 /**
235 Dispatch function for SMM lock box restore all in place.
236
237 @param LockBoxParameterRestoreAllInPlace parameter of lock box restore all in place
238 **/
239 VOID
240 SmmLockBoxRestoreAllInPlace (
241 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace
242 )
243 {
244 EFI_STATUS Status;
245
246 Status = RestoreAllLockBoxInPlace ();
247 LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
248 return ;
249 }
250
251 /**
252 Dispatch function for a Software SMI handler.
253
254 Caution: This function may receive untrusted input.
255 Communicate buffer and buffer size are external input, so this function will do basic validation.
256
257 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
258 @param Context Points to an optional handler context which was specified when the
259 handler was registered.
260 @param CommBuffer A pointer to a collection of data in memory that will
261 be conveyed from a non-SMM environment into an SMM environment.
262 @param CommBufferSize The size of the CommBuffer.
263
264 @retval EFI_SUCCESS Command is handled successfully.
265
266 **/
267 EFI_STATUS
268 EFIAPI
269 SmmLockBoxHandler (
270 IN EFI_HANDLE DispatchHandle,
271 IN CONST VOID *Context OPTIONAL,
272 IN OUT VOID *CommBuffer OPTIONAL,
273 IN OUT UINTN *CommBufferSize OPTIONAL
274 )
275 {
276 EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;
277 UINTN TempCommBufferSize;
278
279 DEBUG ((DEBUG_INFO, "SmmLockBox SmmLockBoxHandler Enter\n"));
280
281 //
282 // If input is invalid, stop processing this SMI
283 //
284 if (CommBuffer == NULL || CommBufferSize == NULL) {
285 return EFI_SUCCESS;
286 }
287
288 TempCommBufferSize = *CommBufferSize;
289
290 //
291 // Sanity check
292 //
293 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {
294 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));
295 return EFI_SUCCESS;
296 }
297 if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
298 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));
299 return EFI_SUCCESS;
300 }
301
302 LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);
303
304 LockBoxParameterHeader->ReturnStatus = (UINT64)-1;
305
306 DEBUG ((DEBUG_INFO, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));
307
308 DEBUG ((DEBUG_INFO, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));
309
310 switch (LockBoxParameterHeader->Command) {
311 case EFI_SMM_LOCK_BOX_COMMAND_SAVE:
312 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {
313 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));
314 break;
315 }
316 SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);
317 break;
318 case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:
319 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {
320 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));
321 break;
322 }
323 SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);
324 break;
325 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:
326 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {
327 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));
328 break;
329 }
330 SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);
331 break;
332 case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:
333 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {
334 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));
335 break;
336 }
337 SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);
338 break;
339 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:
340 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {
341 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));
342 break;
343 }
344 SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);
345 break;
346 default:
347 DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));
348 break;
349 }
350
351 LockBoxParameterHeader->Command = (UINT32)-1;
352
353 DEBUG ((DEBUG_INFO, "SmmLockBox SmmLockBoxHandler Exit\n"));
354
355 return EFI_SUCCESS;
356 }
357
358 /**
359 Smm Ready To Lock event notification handler.
360
361 It sets a flag indicating that SMRAM has been locked.
362
363 @param[in] Protocol Points to the protocol's unique identifier.
364 @param[in] Interface Points to the interface instance.
365 @param[in] Handle The handle on which the interface was installed.
366
367 @retval EFI_SUCCESS Notification handler runs successfully.
368 **/
369 EFI_STATUS
370 EFIAPI
371 SmmReadyToLockEventNotify (
372 IN CONST EFI_GUID *Protocol,
373 IN VOID *Interface,
374 IN EFI_HANDLE Handle
375 )
376 {
377 mLocked = TRUE;
378 return EFI_SUCCESS;
379 }
380
381 /**
382 Entry Point for LockBox SMM driver.
383
384 @param[in] ImageHandle Image handle of this driver.
385 @param[in] SystemTable A Pointer to the EFI System Table.
386
387 @retval EFI_SUCEESS
388 @return Others Some error occurs.
389 **/
390 EFI_STATUS
391 EFIAPI
392 SmmLockBoxEntryPoint (
393 IN EFI_HANDLE ImageHandle,
394 IN EFI_SYSTEM_TABLE *SystemTable
395 )
396 {
397 EFI_STATUS Status;
398 EFI_HANDLE DispatchHandle;
399 VOID *Registration;
400
401 //
402 // Register LockBox communication handler
403 //
404 Status = gSmst->SmiHandlerRegister (
405 SmmLockBoxHandler,
406 &gEfiSmmLockBoxCommunicationGuid,
407 &DispatchHandle
408 );
409 ASSERT_EFI_ERROR (Status);
410
411 //
412 // Register SMM Ready To Lock Protocol notification
413 //
414 Status = gSmst->SmmRegisterProtocolNotify (
415 &gEfiSmmReadyToLockProtocolGuid,
416 SmmReadyToLockEventNotify,
417 &Registration
418 );
419 ASSERT_EFI_ERROR (Status);
420
421 //
422 // Install NULL to DXE data base as notify
423 //
424 ImageHandle = NULL;
425 Status = gBS->InstallProtocolInterface (
426 &ImageHandle,
427 &gEfiLockBoxProtocolGuid,
428 EFI_NATIVE_INTERFACE,
429 NULL
430 );
431 ASSERT_EFI_ERROR (Status);
432
433 return Status;
434 }