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