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