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