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 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 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 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 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 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 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 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 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