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 - 2015, 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
SmmLockBoxSave(IN EFI_SMM_LOCK_BOX_PARAMETER_SAVE * LockBoxParameterSave)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 //
81 // Save data
82 //
83 Status = SaveLockBox (
84 &TempLockBoxParameterSave.Guid,
85 (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,
86 (UINTN)TempLockBoxParameterSave.Length
87 );
88 LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;
89 return ;
90 }
91
92 /**
93 Dispatch function for SMM lock box set attributes.
94
95 @param LockBoxParameterSetAttributes parameter of lock box set attributes
96 **/
97 VOID
SmmLockBoxSetAttributes(IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES * LockBoxParameterSetAttributes)98 SmmLockBoxSetAttributes (
99 IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes
100 )
101 {
102 EFI_STATUS Status;
103 EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;
104
105 //
106 // Sanity check
107 //
108 if (mLocked) {
109 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
110 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
111 return ;
112 }
113
114 CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));
115
116 //
117 // Update data
118 //
119 Status = SetLockBoxAttributes (
120 &TempLockBoxParameterSetAttributes.Guid,
121 TempLockBoxParameterSetAttributes.Attributes
122 );
123 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;
124 return ;
125 }
126
127 /**
128 Dispatch function for SMM lock box update.
129
130 Caution: This function may receive untrusted input.
131 Restore buffer and length are external input, so this function will validate
132 it is in SMRAM.
133
134 @param LockBoxParameterUpdate parameter of lock box update
135 **/
136 VOID
SmmLockBoxUpdate(IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE * LockBoxParameterUpdate)137 SmmLockBoxUpdate (
138 IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate
139 )
140 {
141 EFI_STATUS Status;
142 EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;
143
144 //
145 // Sanity check
146 //
147 if (mLocked) {
148 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));
149 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
150 return ;
151 }
152
153 CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));
154
155 //
156 // Sanity check
157 //
158 if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {
159 DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
160 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
161 return ;
162 }
163
164 //
165 // Update data
166 //
167 Status = UpdateLockBox (
168 &TempLockBoxParameterUpdate.Guid,
169 (UINTN)TempLockBoxParameterUpdate.Offset,
170 (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,
171 (UINTN)TempLockBoxParameterUpdate.Length
172 );
173 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;
174 return ;
175 }
176
177 /**
178 Dispatch function for SMM lock box restore.
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 LockBoxParameterRestore parameter of lock box restore
185 **/
186 VOID
SmmLockBoxRestore(IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE * LockBoxParameterRestore)187 SmmLockBoxRestore (
188 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore
189 )
190 {
191 EFI_STATUS Status;
192 EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;
193
194 CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));
195
196 //
197 // Sanity check
198 //
199 if (!SmmIsBufferOutsideSmmValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {
200 DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
201 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;
202 return ;
203 }
204
205 //
206 // Restore data
207 //
208 if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {
209 Status = RestoreLockBox (
210 &TempLockBoxParameterRestore.Guid,
211 NULL,
212 NULL
213 );
214 } else {
215 Status = RestoreLockBox (
216 &TempLockBoxParameterRestore.Guid,
217 (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,
218 (UINTN *)&TempLockBoxParameterRestore.Length
219 );
220 }
221 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
222 return ;
223 }
224
225 /**
226 Dispatch function for SMM lock box restore all in place.
227
228 @param LockBoxParameterRestoreAllInPlace parameter of lock box restore all in place
229 **/
230 VOID
SmmLockBoxRestoreAllInPlace(IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE * LockBoxParameterRestoreAllInPlace)231 SmmLockBoxRestoreAllInPlace (
232 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace
233 )
234 {
235 EFI_STATUS Status;
236
237 Status = RestoreAllLockBoxInPlace ();
238 LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
239 return ;
240 }
241
242 /**
243 Dispatch function for a Software SMI handler.
244
245 Caution: This function may receive untrusted input.
246 Communicate buffer and buffer size are external input, so this function will do basic validation.
247
248 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
249 @param Context Points to an optional handler context which was specified when the
250 handler was registered.
251 @param CommBuffer A pointer to a collection of data in memory that will
252 be conveyed from a non-SMM environment into an SMM environment.
253 @param CommBufferSize The size of the CommBuffer.
254
255 @retval EFI_SUCCESS Command is handled successfully.
256
257 **/
258 EFI_STATUS
259 EFIAPI
SmmLockBoxHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context OPTIONAL,IN OUT VOID * CommBuffer OPTIONAL,IN OUT UINTN * CommBufferSize OPTIONAL)260 SmmLockBoxHandler (
261 IN EFI_HANDLE DispatchHandle,
262 IN CONST VOID *Context OPTIONAL,
263 IN OUT VOID *CommBuffer OPTIONAL,
264 IN OUT UINTN *CommBufferSize OPTIONAL
265 )
266 {
267 EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;
268 UINTN TempCommBufferSize;
269
270 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Enter\n"));
271
272 //
273 // If input is invalid, stop processing this SMI
274 //
275 if (CommBuffer == NULL || CommBufferSize == NULL) {
276 return EFI_SUCCESS;
277 }
278
279 TempCommBufferSize = *CommBufferSize;
280
281 //
282 // Sanity check
283 //
284 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {
285 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));
286 return EFI_SUCCESS;
287 }
288 if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
289 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));
290 return EFI_SUCCESS;
291 }
292
293 LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);
294
295 LockBoxParameterHeader->ReturnStatus = (UINT64)-1;
296
297 DEBUG ((EFI_D_ERROR, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));
298
299 DEBUG ((EFI_D_ERROR, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));
300
301 switch (LockBoxParameterHeader->Command) {
302 case EFI_SMM_LOCK_BOX_COMMAND_SAVE:
303 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {
304 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));
305 break;
306 }
307 SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);
308 break;
309 case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:
310 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {
311 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));
312 break;
313 }
314 SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);
315 break;
316 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:
317 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {
318 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));
319 break;
320 }
321 SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);
322 break;
323 case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:
324 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {
325 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));
326 break;
327 }
328 SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);
329 break;
330 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:
331 if (TempCommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {
332 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));
333 break;
334 }
335 SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);
336 break;
337 default:
338 DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));
339 break;
340 }
341
342 LockBoxParameterHeader->Command = (UINT32)-1;
343
344 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Exit\n"));
345
346 return EFI_SUCCESS;
347 }
348
349 /**
350 Smm Ready To Lock event notification handler.
351
352 It sets a flag indicating that SMRAM has been locked.
353
354 @param[in] Protocol Points to the protocol's unique identifier.
355 @param[in] Interface Points to the interface instance.
356 @param[in] Handle The handle on which the interface was installed.
357
358 @retval EFI_SUCCESS Notification handler runs successfully.
359 **/
360 EFI_STATUS
361 EFIAPI
SmmReadyToLockEventNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)362 SmmReadyToLockEventNotify (
363 IN CONST EFI_GUID *Protocol,
364 IN VOID *Interface,
365 IN EFI_HANDLE Handle
366 )
367 {
368 mLocked = TRUE;
369 return EFI_SUCCESS;
370 }
371
372 /**
373 Entry Point for LockBox SMM driver.
374
375 @param[in] ImageHandle Image handle of this driver.
376 @param[in] SystemTable A Pointer to the EFI System Table.
377
378 @retval EFI_SUCEESS
379 @return Others Some error occurs.
380 **/
381 EFI_STATUS
382 EFIAPI
SmmLockBoxEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)383 SmmLockBoxEntryPoint (
384 IN EFI_HANDLE ImageHandle,
385 IN EFI_SYSTEM_TABLE *SystemTable
386 )
387 {
388 EFI_STATUS Status;
389 EFI_HANDLE DispatchHandle;
390 VOID *Registration;
391
392 //
393 // Register LockBox communication handler
394 //
395 Status = gSmst->SmiHandlerRegister (
396 SmmLockBoxHandler,
397 &gEfiSmmLockBoxCommunicationGuid,
398 &DispatchHandle
399 );
400 ASSERT_EFI_ERROR (Status);
401
402 //
403 // Register SMM Ready To Lock Protocol notification
404 //
405 Status = gSmst->SmmRegisterProtocolNotify (
406 &gEfiSmmReadyToLockProtocolGuid,
407 SmmReadyToLockEventNotify,
408 &Registration
409 );
410 ASSERT_EFI_ERROR (Status);
411
412 //
413 // Install NULL to DXE data base as notify
414 //
415 ImageHandle = NULL;
416 Status = gBS->InstallProtocolInterface (
417 &ImageHandle,
418 &gEfiLockBoxProtocolGuid,
419 EFI_NATIVE_INTERFACE,
420 NULL
421 );
422 ASSERT_EFI_ERROR (Status);
423
424 return Status;
425 }
426