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