1 /*
2 * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <CppUTest/TestHarness.h>
8 #include <vector>
9
10 #include "protocols/service/fwu/status.h"
11 #include "service/fwu/test/fwu_dut/fwu_dut.h"
12 #include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
13 #include "service/fwu/test/image_directory_checker/image_directory_checker.h"
14
15 /*
16 * Tests that check behaviour when oversize images are installed.
17 */
TEST_GROUP(FwuOversizeImageTests)18 TEST_GROUP(FwuOversizeImageTests)
19 {
20 void setup()
21 {
22 m_dut = NULL;
23 m_fwu_client = NULL;
24 }
25
26 void teardown()
27 {
28 delete m_fwu_client;
29 m_fwu_client = NULL;
30
31 delete m_dut;
32 m_dut = NULL;
33 }
34
35 size_t max_image_size(const struct uuid_octets *uuid)
36 {
37 image_directory_checker dir_checker;
38
39 int status = dir_checker.fetch_image_directory(m_fwu_client);
40 LONGS_EQUAL(0, status);
41
42 const struct fwu_image_info_entry *img_entry = dir_checker.find_entry(uuid);
43 CHECK_TRUE(img_entry);
44
45 return static_cast<size_t>(img_entry->img_max_size);
46 }
47
48 fwu_dut *m_dut;
49 fwu_client *m_fwu_client;
50 };
51
TEST(FwuOversizeImageTests,maxSizeInstall)52 TEST(FwuOversizeImageTests, maxSizeInstall)
53 {
54 int status = 0;
55 struct uuid_octets uuid;
56 uint32_t stream_handle = 0;
57
58 /* Performs an update with an image of the maximum size advertised by
59 * the image directory.
60 */
61 m_dut = fwu_dut_factory::create(1, false);
62 m_fwu_client = m_dut->create_fwu_client();
63
64 m_dut->boot();
65
66 /* Generate image that should just fit */
67 m_dut->whole_volume_image_type_uuid(0, &uuid);
68 size_t img_size = max_image_size(&uuid);
69 std::vector<uint8_t> image_data;
70 m_dut->generate_image_data(&image_data, img_size);
71
72 /* Install the image */
73 status = m_fwu_client->begin_staging(0, 0, NULL);
74 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
75
76 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
77 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
78
79 status = m_fwu_client->write_stream(stream_handle,
80 reinterpret_cast<const uint8_t *>(image_data.data()),
81 image_data.size());
82 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
83
84 status = m_fwu_client->commit(stream_handle, false);
85 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
86
87 status = m_fwu_client->end_staging();
88 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
89
90 /* Check for reboot with no errors */
91 m_dut->shutdown();
92 m_dut->boot();
93 }
94
TEST(FwuOversizeImageTests,oversizeInstallCancelStaging)95 TEST(FwuOversizeImageTests, oversizeInstallCancelStaging)
96 {
97 int status = 0;
98 struct uuid_octets uuid;
99 uint32_t stream_handle = 0;
100
101 /* Performs an update with an oversized image where the client
102 * cancels staging on seeing the error. This is the expected
103 * client behavior when an error occurs during installation.
104 */
105 m_dut = fwu_dut_factory::create(1, false);
106 m_fwu_client = m_dut->create_fwu_client();
107
108 m_dut->boot();
109
110 /* Generate image that's too big */
111 m_dut->whole_volume_image_type_uuid(0, &uuid);
112 size_t img_size = max_image_size(&uuid) + 1;
113 std::vector<uint8_t> image_data;
114 m_dut->generate_image_data(&image_data, img_size);
115
116 /* Install the image */
117 status = m_fwu_client->begin_staging(0, 0, NULL);
118 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
119
120 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
121 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
122
123 status = m_fwu_client->write_stream(stream_handle,
124 reinterpret_cast<const uint8_t *>(image_data.data()),
125 image_data.size());
126 LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
127
128 /* Client response to the error by cancelling staging */
129 status = m_fwu_client->cancel_staging();
130 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
131
132 /* Check for reboot with no errors */
133 m_dut->shutdown();
134 m_dut->boot();
135 }
136
TEST(FwuOversizeImageTests,oversizeInstallEndStaging)137 TEST(FwuOversizeImageTests, oversizeInstallEndStaging)
138 {
139 int status = 0;
140 struct uuid_octets uuid;
141 uint32_t stream_handle = 0;
142
143 /* Performs an update with an oversized image where the client
144 * attempts to proceed with the update beyond the point where an error
145 * was reported due to an attempt to install an oversized image.
146 */
147 m_dut = fwu_dut_factory::create(1, false);
148 m_fwu_client = m_dut->create_fwu_client();
149
150 m_dut->boot();
151
152 /* Generate image that's too big */
153 m_dut->whole_volume_image_type_uuid(0, &uuid);
154 size_t img_size = max_image_size(&uuid) + 1;
155 std::vector<uint8_t> image_data;
156 m_dut->generate_image_data(&image_data, img_size);
157
158 /* Install the image */
159 status = m_fwu_client->begin_staging(0, 0, NULL);
160 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
161
162 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
163 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
164
165 status = m_fwu_client->write_stream(stream_handle,
166 reinterpret_cast<const uint8_t *>(image_data.data()),
167 image_data.size());
168 LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
169
170 status = m_fwu_client->commit(stream_handle, false);
171 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
172
173 /* Client has ignored the error and proceeded to end staging. Because
174 * the DUT was configured to not support partial updates, expect end_staging
175 * to fail.
176 */
177 status = m_fwu_client->end_staging();
178 LONGS_EQUAL(FWU_STATUS_NOT_AVAILABLE, status);
179
180 /* Check for reboot with no errors */
181 m_dut->shutdown();
182 m_dut->boot();
183 }
184
TEST(FwuOversizeImageTests,oversizeInstallMultiLocationEndStaging)185 TEST(FwuOversizeImageTests, oversizeInstallMultiLocationEndStaging)
186 {
187 int status = 0;
188 struct uuid_octets uuid;
189 uint32_t stream_handle = 0;
190
191 /* Performs an update with one oversized image when the DUT has
192 * multiple locations. This checks handling when some installs are
193 * successful but one fails because the image is too big. Because
194 * the DUT allows partial updates, if the client proceeds to
195 * finalize the update, any images handled by the errored installer
196 * will be ignored and treated as if they weren't updated.
197 */
198 m_dut = fwu_dut_factory::create(3, true);
199 m_fwu_client = m_dut->create_fwu_client();
200
201 m_dut->boot();
202
203 /* Perform multi-image update transaction */
204 status = m_fwu_client->begin_staging(0, 0, NULL);
205 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
206
207 /* Install good image for location 0 */
208 std::vector<uint8_t> image_data;
209 m_dut->whole_volume_image_type_uuid(0, &uuid);
210 size_t img_size = max_image_size(&uuid);
211 m_dut->generate_image_data(&image_data, img_size);
212
213 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
214 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
215
216 status = m_fwu_client->write_stream(stream_handle,
217 reinterpret_cast<const uint8_t *>(image_data.data()),
218 image_data.size());
219 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
220
221 status = m_fwu_client->commit(stream_handle, false);
222 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
223
224 /* Install oversized image for location 1 */
225 m_dut->whole_volume_image_type_uuid(1, &uuid);
226 img_size = max_image_size(&uuid) + 1;
227 m_dut->generate_image_data(&image_data, img_size);
228
229 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
230 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
231
232 status = m_fwu_client->write_stream(stream_handle,
233 reinterpret_cast<const uint8_t *>(image_data.data()),
234 image_data.size());
235 LONGS_EQUAL(FWU_STATUS_OUT_OF_BOUNDS, status);
236
237 status = m_fwu_client->commit(stream_handle, false);
238 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
239
240 /* Install good image for location 2 */
241 m_dut->whole_volume_image_type_uuid(2, &uuid);
242 img_size = max_image_size(&uuid);
243 m_dut->generate_image_data(&image_data, img_size);
244
245 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
246 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
247
248 status = m_fwu_client->write_stream(stream_handle,
249 reinterpret_cast<const uint8_t *>(image_data.data()),
250 image_data.size());
251 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
252
253 status = m_fwu_client->commit(stream_handle, false);
254 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
255
256 /* Expect end staging to be successful and that the errored image is
257 * excluded from the update. This should be confirmed by the following
258 * boot being error-free.
259 */
260 status = m_fwu_client->end_staging();
261 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
262
263 /* Check for reboot with no errors */
264 m_dut->shutdown();
265 m_dut->boot();
266 }
267