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