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
12Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
13
14This program and the accompanying materials
15are licensed and made available under the terms and conditions
16of the BSD License which accompanies this distribution.  The
17full text of the license may be found at
18http://opensource.org/licenses/bsd-license.php
19
20THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21WITHOUT 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
41BOOLEAN              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**/
52VOID
53SmmLockBoxSave (
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**/
97VOID
98SmmLockBoxSetAttributes (
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**/
136VOID
137SmmLockBoxUpdate (
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**/
186VOID
187SmmLockBoxRestore (
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**/
230VOID
231SmmLockBoxRestoreAllInPlace (
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**/
258EFI_STATUS
259EFIAPI
260SmmLockBoxHandler (
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 **/
360EFI_STATUS
361EFIAPI
362SmmReadyToLockEventNotify (
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**/
381EFI_STATUS
382EFIAPI
383SmmLockBoxEntryPoint (
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