1 /** @file
2 
3   Library implementing the LockBox interface for OVMF
4 
5   Copyright (C) 2013, Red Hat, Inc.
6   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
7 
8   This program and the accompanying materials are licensed and made available
9   under the terms and conditions of the BSD License which accompanies this
10   distribution. The full text of the license may be found at
11   http://opensource.org/licenses/bsd-license.php
12 
13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include <Uefi.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LockBoxLib.h>
22 #include <Library/PcdLib.h>
23 #include <LockBoxLib.h>
24 
25 #pragma pack(1)
26 typedef struct {
27   EFI_GUID             Guid;
28   EFI_PHYSICAL_ADDRESS OrigAddress;
29   EFI_PHYSICAL_ADDRESS CopyAddress;
30   UINT32               Size;
31   UINT64               Attributes;
32 } LOCK_BOX_ENTRY;
33 #pragma pack()
34 
35 LOCK_BOX_GLOBAL *mLockBoxGlobal = NULL;
36 STATIC LOCK_BOX_ENTRY *StartOfEntries = NULL;
37 STATIC LOCK_BOX_ENTRY *EndOfEntries = NULL;
38 
39 RETURN_STATUS
40 EFIAPI
LockBoxLibInitialize(VOID)41 LockBoxLibInitialize (
42   VOID
43   )
44 {
45   UINTN NumEntries;
46 
47   ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
48 
49   if (PcdGet32 (PcdOvmfLockBoxStorageSize) < sizeof (LOCK_BOX_GLOBAL)) {
50     return RETURN_UNSUPPORTED;
51   }
52 
53   mLockBoxGlobal = (LOCK_BOX_GLOBAL *)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase);
54   StartOfEntries = ((LOCK_BOX_ENTRY *) (mLockBoxGlobal + 1));
55   NumEntries = ((PcdGet32 (PcdOvmfLockBoxStorageSize) - sizeof (LOCK_BOX_GLOBAL)) /
56                 sizeof (LOCK_BOX_ENTRY));
57   EndOfEntries = StartOfEntries + NumEntries;
58   if (mLockBoxGlobal->Signature != LOCK_BOX_GLOBAL_SIGNATURE) {
59     //
60     // Note: This code depends on the lock box being cleared in early
61     // PEI before usage, so the SubPageBuffer and SubPageRemaining
62     // fields don't need to be set to 0.
63     //
64     mLockBoxGlobal->Signature = LOCK_BOX_GLOBAL_SIGNATURE;
65   }
66   return RETURN_SUCCESS;
67 }
68 
69 
70 /**
71   Find LockBox entry based on GUID.
72 
73   @param[in] Guid  The GUID to search for.
74 
75   @return  Address of the LOCK_BOX_ENTRY found.
76 
77            If NULL, then the item was not found, and there is no space
78            left to store a new item.
79 
80            If non-NULL and LOCK_BOX_ENTRY.Size == 0, then the item was not
81            found, but a new item can be inserted at the returned location.
82 
83            If non-NULL and LOCK_BOX_ENTRY.Size > 0, then the item was found.
84 **/
85 STATIC
86 LOCK_BOX_ENTRY *
87 EFIAPI
FindHeaderByGuid(IN CONST EFI_GUID * Guid)88 FindHeaderByGuid (
89   IN CONST EFI_GUID *Guid
90   )
91 {
92   LOCK_BOX_ENTRY *Header;
93 
94   for (Header = StartOfEntries; Header < EndOfEntries; Header++) {
95     if (Header->Size == 0 || CompareGuid (Guid, &Header->Guid)) {
96       return Header;
97     }
98   }
99 
100   return NULL;
101 }
102 
103 
104 /**
105   This function will save confidential information to lockbox.
106 
107   @param Guid       the guid to identify the confidential information
108   @param Buffer     the address of the confidential information
109   @param Length     the length of the confidential information
110 
111   @retval RETURN_SUCCESS            the information is saved successfully.
112   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or
113                                     Length is 0
114   @retval RETURN_ALREADY_STARTED    the requested GUID already exist.
115   @retval RETURN_OUT_OF_RESOURCES   no enough resource to save the information.
116   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
117   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
118   @retval RETURN_UNSUPPORTED        the service is not supported by
119                                     implementaion.
120 **/
121 RETURN_STATUS
122 EFIAPI
SaveLockBox(IN GUID * Guid,IN VOID * Buffer,IN UINTN Length)123 SaveLockBox (
124   IN  GUID                        *Guid,
125   IN  VOID                        *Buffer,
126   IN  UINTN                       Length
127   )
128 {
129   LOCK_BOX_ENTRY *Header;
130   VOID            *CopyBuffer;
131 
132   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p Length=0x%x\n", __FUNCTION__,
133     Guid, Buffer, (UINT32) Length));
134 
135   if (Guid == NULL || Buffer == NULL || Length == 0) {
136     return RETURN_INVALID_PARAMETER;
137   }
138 
139   if (Length > 0xFFFFFFFF) {
140     return RETURN_OUT_OF_RESOURCES;
141   }
142 
143   Header = FindHeaderByGuid (Guid);
144   if (Header == NULL) {
145     return RETURN_OUT_OF_RESOURCES;
146   }
147 
148   if (Header->Size > 0) {
149     return RETURN_ALREADY_STARTED;
150   }
151 
152   CopyBuffer = AllocateAcpiNvsPool (Length);
153   if (CopyBuffer == NULL) {
154     return RETURN_OUT_OF_RESOURCES;
155   }
156 
157   //
158   // overwrite the current terminator header with new metadata
159   //
160   CopyGuid (&Header->Guid, Guid);
161   Header->OrigAddress = (UINTN) Buffer;
162   Header->CopyAddress = (UINTN) CopyBuffer;
163   Header->Size        = (UINT32) Length;
164   Header->Attributes  = 0;
165 
166   //
167   // copy contents
168   //
169   CopyMem (CopyBuffer, Buffer, Length);
170 
171   return RETURN_SUCCESS;
172 }
173 
174 
175 /**
176   This function will set lockbox attributes.
177 
178   @param Guid       the guid to identify the confidential information
179   @param Attributes the attributes of the lockbox
180 
181   @retval RETURN_SUCCESS            the information is saved successfully.
182   @retval RETURN_INVALID_PARAMETER  attributes is invalid.
183   @retval RETURN_NOT_FOUND          the requested GUID not found.
184   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
185   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
186   @retval RETURN_UNSUPPORTED        the service is not supported by
187                                     implementaion.
188 **/
189 RETURN_STATUS
190 EFIAPI
SetLockBoxAttributes(IN GUID * Guid,IN UINT64 Attributes)191 SetLockBoxAttributes (
192   IN  GUID                        *Guid,
193   IN  UINT64                      Attributes
194   )
195 {
196   LOCK_BOX_ENTRY *Header;
197 
198   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Attributes=0x%Lx\n", __FUNCTION__, Guid,
199     Attributes));
200 
201   if (Guid == NULL) {
202     return RETURN_INVALID_PARAMETER;
203   }
204 
205   Header = FindHeaderByGuid (Guid);
206   if (!Header || Header->Size == 0) {
207     return RETURN_NOT_FOUND;
208   }
209   Header->Attributes = Attributes;
210 
211   return RETURN_SUCCESS;
212 }
213 
214 
215 /**
216   This function will update confidential information to lockbox.
217 
218   @param Guid   the guid to identify the original confidential information
219   @param Offset the offset of the original confidential information
220   @param Buffer the address of the updated confidential information
221   @param Length the length of the updated confidential information
222 
223   @retval RETURN_SUCCESS            the information is saved successfully.
224   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or Buffer is NULL, or
225                                     Length is 0.
226   @retval RETURN_NOT_FOUND          the requested GUID not found.
227   @retval RETURN_BUFFER_TOO_SMALL   the original buffer to too small to hold
228                                     new information.
229   @retval RETURN_ACCESS_DENIED      it is too late to invoke this interface
230   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
231   @retval RETURN_UNSUPPORTED        the service is not supported by
232                                     implementaion.
233 **/
234 RETURN_STATUS
235 EFIAPI
UpdateLockBox(IN GUID * Guid,IN UINTN Offset,IN VOID * Buffer,IN UINTN Length)236 UpdateLockBox (
237   IN  GUID                        *Guid,
238   IN  UINTN                       Offset,
239   IN  VOID                        *Buffer,
240   IN  UINTN                       Length
241   )
242 {
243   LOCK_BOX_ENTRY *Header;
244 
245   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Offset=0x%x Length=0x%x\n", __FUNCTION__,
246     Guid, (UINT32) Offset, (UINT32) Length));
247 
248   if (Guid == NULL || Buffer == NULL || Length == 0) {
249     return RETURN_INVALID_PARAMETER;
250   }
251 
252   Header = FindHeaderByGuid (Guid);
253   if (!Header || Header->Size == 0) {
254     return RETURN_NOT_FOUND;
255   }
256 
257   if (Header->Size < Offset ||
258       Length > Header->Size - Offset) {
259     return RETURN_BUFFER_TOO_SMALL;
260   }
261 
262   CopyMem ((UINT8 *)(UINTN) (Header->CopyAddress) + Offset, Buffer, Length);
263 
264   return RETURN_SUCCESS;
265 }
266 
267 
268 /**
269   This function will restore confidential information from lockbox.
270 
271   @param Guid   the guid to identify the confidential information
272   @param Buffer the address of the restored confidential information
273                 NULL means restored to original address, Length MUST be NULL at
274                 same time.
275   @param Length the length of the restored confidential information
276 
277   @retval RETURN_SUCCESS            the information is restored successfully.
278   @retval RETURN_INVALID_PARAMETER  the Guid is NULL, or one of Buffer and
279                                     Length is NULL.
280   @retval RETURN_WRITE_PROTECTED    Buffer and Length are NULL, but the LockBox
281                                     has no LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
282                                     attribute.
283   @retval RETURN_BUFFER_TOO_SMALL   the Length is too small to hold the
284                                     confidential information.
285   @retval RETURN_NOT_FOUND          the requested GUID not found.
286   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
287   @retval RETURN_ACCESS_DENIED      not allow to restore to the address
288   @retval RETURN_UNSUPPORTED        the service is not supported by
289                                     implementaion.
290 **/
291 RETURN_STATUS
292 EFIAPI
RestoreLockBox(IN GUID * Guid,IN VOID * Buffer,OPTIONAL IN OUT UINTN * Length OPTIONAL)293 RestoreLockBox (
294   IN  GUID                        *Guid,
295   IN  VOID                        *Buffer, OPTIONAL
296   IN  OUT UINTN                   *Length  OPTIONAL
297   )
298 {
299   LOCK_BOX_ENTRY *Header;
300 
301   DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__, Guid,
302     Buffer));
303 
304   if ((Guid == NULL) ||
305       ((Buffer == NULL) && (Length != NULL)) ||
306       ((Buffer != NULL) && (Length == NULL))) {
307     return EFI_INVALID_PARAMETER;
308   }
309 
310   Header = FindHeaderByGuid (Guid);
311   if (!Header || Header->Size == 0) {
312     return RETURN_NOT_FOUND;
313   }
314 
315   if (Buffer == NULL) {
316     if (!(Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE)) {
317       return RETURN_WRITE_PROTECTED;
318     }
319     if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
320       return RETURN_UNSUPPORTED;
321     }
322     Buffer = (VOID *)(UINTN) Header->OrigAddress;
323   }
324 
325   //
326   // Set RestoreLength
327   //
328   if (Length != NULL) {
329     if (Header->Size > *Length) {
330       //
331       // Input buffer is too small to hold all data.
332       //
333       *Length = Header->Size;
334       return EFI_BUFFER_TOO_SMALL;
335     }
336     *Length = Header->Size;
337   }
338 
339   CopyMem (Buffer, (VOID*)(UINTN) Header->CopyAddress, Header->Size);
340 
341   return RETURN_SUCCESS;
342 }
343 
344 
345 /**
346   This function will restore confidential information from all lockbox which
347   have RestoreInPlace attribute.
348 
349   @retval RETURN_SUCCESS            the information is restored successfully.
350   @retval RETURN_NOT_STARTED        it is too early to invoke this interface
351   @retval RETURN_UNSUPPORTED        the service is not supported by
352                                     implementaion.
353 **/
354 RETURN_STATUS
355 EFIAPI
RestoreAllLockBoxInPlace(VOID)356 RestoreAllLockBoxInPlace (
357   VOID
358   )
359 {
360   LOCK_BOX_ENTRY *Header;
361 
362   for (Header = StartOfEntries;
363        Header < EndOfEntries && Header->Size > 0;
364        Header++) {
365     if (Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) {
366       VOID *Buffer;
367 
368       if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {
369         return RETURN_UNSUPPORTED;
370       }
371       Buffer = (VOID *)(UINTN) Header->OrigAddress;
372       CopyMem (Buffer, (VOID*)(UINTN)Header->CopyAddress, Header->Size);
373       DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__,
374         &Header->Guid, Buffer));
375     }
376   }
377   return RETURN_SUCCESS;
378 }
379