1 /** @file
2 SetImage instance to report system firmware and act as agent to system update.
3
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 FmpSetImage() will receive untrusted input and do basic validation.
10
11 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
12 This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution. The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20 **/
21
22 #include "SystemFirmwareDxe.h"
23
24 //
25 // SystemFmp driver private data
26 //
27 SYSTEM_FMP_PRIVATE_DATA *mSystemFmpPrivate = NULL;
28
29 /**
30 Dispatch system FMP images.
31
32 Caution: This function may receive untrusted input.
33
34 @param[in] Image The EDKII system FMP capsule image.
35 @param[in] ImageSize The size of the EDKII system FMP capsule image in bytes.
36 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
37 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
38
39 @retval EFI_SUCESS Process Capsule Image successfully.
40 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
41 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
42 @retval EFI_OUT_OF_RESOURCES Not enough memory.
43 **/
44 EFI_STATUS
DispatchSystemFmpImages(IN VOID * Image,IN UINTN ImageSize,OUT UINT32 * LastAttemptVersion,OUT UINT32 * LastAttemptStatus)45 DispatchSystemFmpImages (
46 IN VOID *Image,
47 IN UINTN ImageSize,
48 OUT UINT32 *LastAttemptVersion,
49 OUT UINT32 *LastAttemptStatus
50 )
51 {
52 EFI_STATUS Status;
53 VOID *AuthenticatedImage;
54 UINTN AuthenticatedImageSize;
55 VOID *DispatchFvImage;
56 UINTN DispatchFvImageSize;
57 EFI_HANDLE FvProtocolHandle;
58 EFI_FIRMWARE_VOLUME_HEADER *FvImage;
59 BOOLEAN Result;
60
61 AuthenticatedImage = NULL;
62 AuthenticatedImageSize = 0;
63
64 DEBUG((DEBUG_INFO, "DispatchSystemFmpImages\n"));
65
66 //
67 // Verify
68 //
69 Status = CapsuleAuthenticateSystemFirmware(Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
70 if (EFI_ERROR(Status)) {
71 DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status));
72 return Status;
73 }
74
75 //
76 // Get FV
77 //
78 Result = ExtractDriverFvImage(AuthenticatedImage, AuthenticatedImageSize, &DispatchFvImage, &DispatchFvImageSize);
79 if (Result) {
80 DEBUG((DEBUG_INFO, "ExtractDriverFvImage\n"));
81 //
82 // Dispatch
83 //
84 if (((EFI_FIRMWARE_VOLUME_HEADER *)DispatchFvImage)->FvLength == DispatchFvImageSize) {
85 FvImage = AllocatePages(EFI_SIZE_TO_PAGES(DispatchFvImageSize));
86 if (FvImage != NULL) {
87 CopyMem(FvImage, DispatchFvImage, DispatchFvImageSize);
88 Status = gDS->ProcessFirmwareVolume(
89 (VOID *)FvImage,
90 (UINTN)FvImage->FvLength,
91 &FvProtocolHandle
92 );
93 DEBUG((DEBUG_INFO, "ProcessFirmwareVolume - %r\n", Status));
94 if (!EFI_ERROR(Status)) {
95 gDS->Dispatch();
96 DEBUG((DEBUG_INFO, "Dispatch Done\n"));
97 }
98 }
99 }
100 }
101
102 return EFI_SUCCESS;
103 }
104
105 /**
106 Updates the firmware image of the device.
107
108 This function updates the hardware with the new firmware image.
109 This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
110 If the firmware image is updatable, the function should perform the following minimal validations
111 before proceeding to do the firmware image update.
112 - Validate the image authentication if image has attribute
113 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
114 EFI_SECURITY_VIOLATION if the validation fails.
115 - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
116 the image is unsupported. The function can optionally provide more detailed information on
117 why the image is not a supported image.
118 - Validate the data from VendorCode if not null. Image validation must be performed before
119 VendorCode data validation. VendorCode data is ignored or considered invalid if image
120 validation failed. The function returns EFI_ABORTED if the data is invalid.
121
122 VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
123 the caller did not specify the policy or use the default policy. As an example, vendor can implement
124 a policy to allow an option to force a firmware image update when the abort reason is due to the new
125 firmware image version is older than the current firmware image version or bad image checksum.
126 Sensitive operations such as those wiping the entire firmware image and render the device to be
127 non-functional should be encoded in the image itself rather than passed with the VendorCode.
128 AbortReason enables vendor to have the option to provide a more detailed description of the abort
129 reason to the caller.
130
131 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
132 @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
133 The number is between 1 and DescriptorCount.
134 @param[in] Image Points to the new image.
135 @param[in] ImageSize Size of the new image in bytes.
136 @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
137 Null indicates the caller did not specify the policy or use the default policy.
138 @param[in] Progress A function used by the driver to report the progress of the firmware update.
139 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
140 details for the aborted operation. The buffer is allocated by this function
141 with AllocatePool(), and it is the caller's responsibility to free it with a
142 call to FreePool().
143
144 @retval EFI_SUCCESS The device was successfully updated with the new image.
145 @retval EFI_ABORTED The operation is aborted.
146 @retval EFI_INVALID_PARAMETER The Image was NULL.
147 @retval EFI_UNSUPPORTED The operation is not supported.
148 @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
149
150 **/
151 EFI_STATUS
152 EFIAPI
FmpSetImage(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN UINT8 ImageIndex,IN CONST VOID * Image,IN UINTN ImageSize,IN CONST VOID * VendorCode,IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,OUT CHAR16 ** AbortReason)153 FmpSetImage (
154 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
155 IN UINT8 ImageIndex,
156 IN CONST VOID *Image,
157 IN UINTN ImageSize,
158 IN CONST VOID *VendorCode,
159 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
160 OUT CHAR16 **AbortReason
161 )
162 {
163 SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate;
164 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *SystemFmp;
165 EFI_STATUS Status;
166 EFI_STATUS VarStatus;
167
168 if (Image == NULL || ImageSize == 0 || AbortReason == NULL) {
169 return EFI_INVALID_PARAMETER;
170 }
171
172 SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP(This);
173 *AbortReason = NULL;
174
175 if (ImageIndex == 0 || ImageIndex > SystemFmpPrivate->DescriptorCount) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 //
180 // Process FV
181 //
182 Status = DispatchSystemFmpImages((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus);
183 DEBUG((DEBUG_INFO, "(Agent)SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));
184 if (EFI_ERROR(Status)) {
185 VarStatus = gRT->SetVariable(
186 SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME,
187 &gSystemFmpLastAttemptVariableGuid,
188 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
189 sizeof(SystemFmpPrivate->LastAttempt),
190 &SystemFmpPrivate->LastAttempt
191 );
192 DEBUG((DEBUG_INFO, "(Agent)SetLastAttemp - %r\n", VarStatus));
193 return Status;
194 }
195
196 //
197 // Pass Thru
198 //
199 Status = gBS->LocateProtocol(&gSystemFmpProtocolGuid, NULL, (VOID **)&SystemFmp);
200 if (EFI_ERROR(Status)) {
201 DEBUG((DEBUG_INFO, "(Agent)SetImage - SystemFmpProtocol - %r\n", Status));
202 SystemFmpPrivate->LastAttempt.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
203 VarStatus = gRT->SetVariable(
204 SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME,
205 &gSystemFmpLastAttemptVariableGuid,
206 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
207 sizeof(SystemFmpPrivate->LastAttempt),
208 &SystemFmpPrivate->LastAttempt
209 );
210 DEBUG((DEBUG_INFO, "(Agent)SetLastAttemp - %r\n", VarStatus));
211 return Status;
212 }
213
214 return SystemFmp->SetImage(SystemFmp, ImageIndex, Image, ImageSize, VendorCode, Progress, AbortReason);
215 }
216
217 /**
218 System FMP module entrypoint
219
220 @param[in] ImageHandle The firmware allocated handle for the EFI image.
221 @param[in] SystemTable A pointer to the EFI System Table.
222
223 @return EFI_SUCCESS System FMP module is initialized.
224 **/
225 EFI_STATUS
226 EFIAPI
SystemFirmwareReportMainDxe(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)227 SystemFirmwareReportMainDxe (
228 IN EFI_HANDLE ImageHandle,
229 IN EFI_SYSTEM_TABLE *SystemTable
230 )
231 {
232 EFI_STATUS Status;
233
234 //
235 // Initialize SystemFmpPrivateData
236 //
237 mSystemFmpPrivate = AllocateZeroPool (sizeof(SYSTEM_FMP_PRIVATE_DATA));
238 if (mSystemFmpPrivate == NULL) {
239 return EFI_OUT_OF_RESOURCES;
240 }
241
242 Status = InitializePrivateData(mSystemFmpPrivate);
243 if (EFI_ERROR(Status)) {
244 FreePool(mSystemFmpPrivate);
245 mSystemFmpPrivate = NULL;
246 return Status;
247 }
248
249 //
250 // Install FMP protocol.
251 //
252 Status = gBS->InstallProtocolInterface (
253 &mSystemFmpPrivate->Handle,
254 &gEfiFirmwareManagementProtocolGuid,
255 EFI_NATIVE_INTERFACE,
256 &mSystemFmpPrivate->Fmp
257 );
258 if (EFI_ERROR (Status)) {
259 FreePool(mSystemFmpPrivate);
260 mSystemFmpPrivate = NULL;
261 return Status;
262 }
263
264 return Status;
265 }
266