1 /*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "avb_manager.h"
18
19 #include <string.h>
20 #include <uapi/err.h>
21
22 #include "secure_storage_interface.h"
23
24 #define DEBUG 0
25
26 const unsigned int kRollbackSlotMax = 32;
27
28 static const uint32_t kAvbVersion = 1;
29 static const char* kAvbRollbackFilename = "avb.rollback";
30 static const unsigned int kPermanentAttributesLengthMax = 2048;
31 static const char* kPermanentAttributesFilename = "avb.ppa";
32 static const char* kLockStateFile = "avb.lock_state";
33 static const unsigned int kStorageIdLengthMax = 64;
34
35 static const uint32_t kTypeMask = 0xF000;
36 static const unsigned int kTypeShift = 12;
37
38 // Helper function to get |filename| and |slot| and based on type flag
39 // in |raw_slot|. |filename| is assumed to be allocated with
40 // kStorageIdLengthMax bytes.
GetFilenameAndSlot(uint32_t raw_slot,char filename[kStorageIdLengthMax],uint32_t * slot)41 static int GetFilenameAndSlot(uint32_t raw_slot,
42 char filename[kStorageIdLengthMax],
43 uint32_t* slot) {
44 // Upper 16 bits should not be set
45 if (raw_slot & 0xFFFF0000) {
46 TLOGE("Error: Slot value %u invalid\n", raw_slot);
47 return ERR_NOT_VALID;
48 }
49 // Mask type flag from raw slot to get index
50 *slot = raw_slot & ~kTypeMask;
51 if (*slot >= kRollbackSlotMax) {
52 TLOGE("Error: Slot value %u larger than supported %u\n", *slot,
53 kRollbackSlotMax);
54 return ERR_NOT_VALID;
55 }
56 // Choose correct file for rollback index type
57 strcpy(filename, kAvbRollbackFilename);
58 int index_type = (raw_slot & kTypeMask) >> kTypeShift;
59 char postfix[4];
60 snprintf(postfix, 4, ".%01X", index_type);
61 strcat(filename, postfix);
62 return NO_ERROR;
63 }
64
65 namespace avb {
66
ReadRollbackIndex(const RollbackIndexRequest & request,RollbackIndexResponse * response)67 void AvbManager::ReadRollbackIndex(const RollbackIndexRequest& request,
68 RollbackIndexResponse* response) {
69 uint32_t slot;
70 char filename[kStorageIdLengthMax];
71 if (GetFilenameAndSlot(request.get_slot(), filename, &slot) < 0) {
72 response->set_error(AvbError::kInvalid);
73 TLOGE("Error: Invalid slot value: %u\n", request.get_slot());
74 return;
75 }
76
77 int rc = storage_->open(filename);
78 if (rc < 0) {
79 response->set_error(AvbError::kInternal);
80 TLOGE("Error: failed to open file %s: %d\n", filename, rc);
81 return;
82 }
83 uint64_t size;
84 rc = storage_->get_file_size(&size);
85 if (rc < 0) {
86 response->set_error(AvbError::kInternal);
87 TLOGE("Error: failed to get size of file %s: %d\n", filename, rc);
88 return;
89 }
90
91 // If no valid rollback counter file is found, initialize to 0
92 uint64_t rollback_counter;
93 if (size < kRollbackSlotMax * sizeof(uint64_t)) {
94 TLOGD("No valid rollback index file found. Initializing to 0\n");
95 uint64_t write_buf[kRollbackSlotMax] = {0};
96 rc = storage_->write(0, write_buf, sizeof(write_buf));
97 rollback_counter = 0;
98 } else {
99 TLOGD("Rollback index file found\n");
100 rc = storage_->read(sizeof(rollback_counter) * slot, &rollback_counter,
101 sizeof(rollback_counter));
102 }
103
104 if (rc < 0) {
105 response->set_error(AvbError::kInternal);
106 TLOGE("Error: reading storage object: %d\n", rc);
107 return;
108 }
109
110 if (static_cast<size_t>(rc) < sizeof(rollback_counter)) {
111 response->set_error(AvbError::kInternal);
112 TLOGE("Error: invalid object size: %d\n", rc);
113 return;
114 }
115
116 response->set_value(rollback_counter);
117 }
118
WriteRollbackIndex(const RollbackIndexRequest & request,RollbackIndexResponse * response)119 void AvbManager::WriteRollbackIndex(const RollbackIndexRequest& request,
120 RollbackIndexResponse* response) {
121 uint32_t slot;
122 char filename[kStorageIdLengthMax];
123 if (GetFilenameAndSlot(request.get_slot(), filename, &slot) < 0) {
124 response->set_error(AvbError::kInvalid);
125 TLOGE("Error: Invalid slot value: %u\n", request.get_slot());
126 return;
127 }
128
129 int rc = storage_->open(filename);
130 if (rc < 0) {
131 response->set_error(AvbError::kInternal);
132 TLOGE("Error: failed to open file %s: %d\n", filename, rc);
133 return;
134 }
135 uint64_t size;
136 rc = storage_->get_file_size(&size);
137 if (rc < 0) {
138 response->set_error(AvbError::kInternal);
139 TLOGE("Error: failed to get size of file %s: %d\n", filename, rc);
140 return;
141 }
142
143 // If no valid rollback counter file is found, initialize to 0
144 uint64_t request_value = request.get_value();
145 if (static_cast<size_t>(size) < kRollbackSlotMax * sizeof(uint64_t)) {
146 TLOGD("No valid rollback index file found. Initializing to 0\n");
147 uint64_t write_buf[kRollbackSlotMax] = {0};
148 write_buf[slot] = request_value;
149 rc = storage_->write(0, write_buf, sizeof(write_buf));
150 } else {
151 uint64_t rollback_counter;
152 TLOGD("Found a rollback index file\n");
153 rc = storage_->read(sizeof(rollback_counter) * slot, &rollback_counter,
154 sizeof(rollback_counter));
155
156 // Write value to specified slot in file
157 if (request_value < rollback_counter) {
158 response->set_error(AvbError::kInvalid);
159 TLOGE("Error: Requested write [%lu] is less than existing counter value "
160 "[%lu]\n",
161 static_cast<long unsigned>(request_value),
162 static_cast<long unsigned>(rollback_counter));
163 response->set_value(rollback_counter);
164 return;
165 }
166 rc = storage_->write(sizeof(request_value) * slot, &request_value,
167 sizeof(request_value));
168 }
169
170 if (rc < 0) {
171 response->set_error(AvbError::kInternal);
172 TLOGE("Error: accessing storage object [%d]\n", rc);
173 return;
174 }
175
176 if (static_cast<size_t>(rc) < sizeof(request_value)) {
177 response->set_error(AvbError::kInternal);
178 TLOGE("Error: invalid object size [%d]\n", rc);
179 return;
180 }
181
182 response->set_value(request_value);
183 }
184
GetVersion(const GetVersionRequest & request,GetVersionResponse * response)185 void AvbManager::GetVersion(const GetVersionRequest& request,
186 GetVersionResponse* response) {
187 response->set_version(kAvbVersion);
188 }
189
ReadPermanentAttributes(const ReadPermanentAttributesRequest & request,ReadPermanentAttributesResponse * response)190 void AvbManager::ReadPermanentAttributes(
191 const ReadPermanentAttributesRequest& request,
192 ReadPermanentAttributesResponse* response) {
193 int rc = storage_->open(kPermanentAttributesFilename);
194 if (rc < 0) {
195 response->set_error(AvbError::kInternal);
196 TLOGE("Error: failed to open attributes file: %d\n", rc);
197 return;
198 }
199
200 // Read permanent product attributes
201 UniquePtr<uint8_t[]> attributes(new uint8_t[kPermanentAttributesLengthMax]);
202 rc = storage_->read(0, attributes.get(), kPermanentAttributesLengthMax);
203 if (rc <= 0) {
204 response->set_error(AvbError::kInternal);
205 TLOGE("Error: %s attributes file [%d]\n",
206 rc == 0 ? "missing" : "accessing", rc);
207 return;
208 }
209 uint32_t attributes_size = static_cast<uint32_t>(rc);
210 response->set_attributes_buf(attributes.get(), attributes_size);
211 }
212
WritePermanentAttributes(const WritePermanentAttributesRequest & request,WritePermanentAttributesResponse * response)213 void AvbManager::WritePermanentAttributes(
214 const WritePermanentAttributesRequest& request,
215 WritePermanentAttributesResponse* response) {
216 int rc = storage_->open(kPermanentAttributesFilename);
217 if (rc < 0) {
218 response->set_error(AvbError::kInternal);
219 TLOGE("Error: failed to open attributes file: %d\n", rc);
220 return;
221 }
222 uint64_t size;
223 rc = storage_->get_file_size(&size);
224 if (rc < 0) {
225 response->set_error(AvbError::kInternal);
226 TLOGE("Error: failed to get size of attributes file: %d\n", rc);
227 return;
228 }
229
230 if (size) {
231 response->set_error(AvbError::kInvalid);
232 TLOGE("Error: Permanent attributes already set!\n");
233 return;
234 }
235 // New file, write serialized permanent product attributes to storage
236 uint32_t attributes_size = request.get_attributes_size();
237 uint8_t* attributes = request.get_attributes_buf();
238 rc = storage_->write(0, attributes, attributes_size);
239
240 if (rc < 0 || static_cast<size_t>(rc) < attributes_size) {
241 response->set_error(AvbError::kInternal);
242 TLOGE("Error: accessing storage object [%d]\n", rc);
243 return;
244 }
245 }
246
ReadLockState(const ReadLockStateRequest & request,ReadLockStateResponse * response)247 void AvbManager::ReadLockState(const ReadLockStateRequest& request,
248 ReadLockStateResponse* response) {
249 int rc = storage_->open(kLockStateFile);
250 if (rc < 0) {
251 response->set_error(AvbError::kInternal);
252 TLOGE("Error: failed to open lock state file: %d\n", rc);
253 return;
254 }
255 uint64_t size;
256 rc = storage_->get_file_size(&size);
257 if (rc < 0) {
258 response->set_error(AvbError::kInternal);
259 TLOGE("Error: failed to get size of lock state file: %d\n", rc);
260 return;
261 }
262
263 uint8_t lock_state = 1;
264 if (size == 0) {
265 // No lock state found, assume initial state is locked and write it
266 rc = storage_->write(0, &lock_state, sizeof(lock_state));
267 } else {
268 rc = storage_->read(0, &lock_state, sizeof(lock_state));
269 }
270 if (rc < 0 || static_cast<size_t>(rc) < sizeof(lock_state)) {
271 response->set_error(AvbError::kInternal);
272 TLOGE("Error: accessing storage object [%d]\n", rc);
273 return;
274 }
275 response->set_lock_state(lock_state);
276 }
277
WriteLockState(const WriteLockStateRequest & request,WriteLockStateResponse * response)278 void AvbManager::WriteLockState(const WriteLockStateRequest& request,
279 WriteLockStateResponse* response) {
280 // Only 0 and 1 are valid lock states
281 uint8_t request_lock_state = request.get_lock_state();
282 if (request_lock_state != 0 && request_lock_state != 1) {
283 response->set_error(AvbError::kInvalid);
284 TLOGE("Error: invalid lock state requested: %d\n", request_lock_state);
285 return;
286 }
287
288 int rc = storage_->open(kLockStateFile);
289 if (rc < 0) {
290 response->set_error(AvbError::kInternal);
291 TLOGE("Error: failed to open lock state file: %d\n", rc);
292 return;
293 }
294
295 // Try to read existing lock state
296 uint8_t stored_lock_state = 0xFF;
297 storage_->read(0, &stored_lock_state, sizeof(stored_lock_state));
298
299 // If no lock state file was found, or the device is changing lock state,
300 // clear rollback index data
301 if (stored_lock_state != request_lock_state) {
302 if (DeleteRollbackIndexFiles() < 0) {
303 response->set_error(AvbError::kInternal);
304 TLOGE("Error: clearing rollback index data\n");
305 return;
306 }
307 }
308
309 // Write new lock state
310 rc = storage_->write(0, &request_lock_state, sizeof(request_lock_state));
311 if (rc < 0 || static_cast<size_t>(rc) < sizeof(request_lock_state)) {
312 response->set_error(AvbError::kInternal);
313 TLOGE("Error: accessing storage object [%d]\n", rc);
314 return;
315 }
316 }
317
318 // Rollback counters are stored in files avb.rollback.{0..F}. When a device
319 // changes lock state, data in rollback index files must be deleted.
DeleteRollbackIndexFiles()320 int AvbManager::DeleteRollbackIndexFiles() {
321 char filename[kStorageIdLengthMax];
322 char postfix[4];
323 int rc = NO_ERROR;
324
325 for (unsigned int i = 0x0; i <= 0xF; ++i) {
326 strcpy(filename, kAvbRollbackFilename);
327 snprintf(postfix, 4, ".%01X", i);
328 strcat(filename, postfix);
329 int storage_rc = storage_->delete_file(filename);
330 if (storage_rc < 0 && storage_rc != ERR_NOT_FOUND) {
331 rc = storage_rc;
332 TLOGE("Error: deleting file %s: %d\n", filename, rc);
333 continue;
334 }
335 }
336 return rc;
337 }
338
339 }; // namespace avb
340