blob: 0221514dd9bda749966f3a0aeafa80299f352265 [file] [log] [blame]
Jason Chiu33031712023-11-27 16:52:08 +08001/*
2 * Copyright (C) 2023 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#define LOG_TAG "bootcontrolhal"
18
19#include "BootControl.h"
20
21#include <android-base/file.h>
22#include <android-base/logging.h>
23#include <android-base/unique_fd.h>
24#include <bootloader_message/bootloader_message.h>
25#include <cutils/properties.h>
26#include <libboot_control/libboot_control.h>
27#include <log/log.h>
28#include <trusty/tipc.h>
29
30#include "DevInfo.h"
31#include "GptUtils.h"
32
33using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus;
34using ndk::ScopedAStatus;
35
36using android::bootable::GetMiscVirtualAbMergeStatus;
37using android::bootable::InitMiscVirtualAbMessageIfNeeded;
38using android::bootable::SetMiscVirtualAbMergeStatus;
39
40namespace aidl::android::hardware::boot {
41
42namespace {
43
44// clang-format off
45
46#define BOOT_A_PATH "/dev/block/by-name/boot_a"
47#define BOOT_B_PATH "/dev/block/by-name/boot_b"
48#define DEVINFO_PATH "/dev/block/by-name/devinfo"
49
50// slot flags
51#define AB_ATTR_PRIORITY_SHIFT 52
52#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT)
53#define AB_ATTR_ACTIVE_SHIFT 54
54#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT)
55#define AB_ATTR_RETRY_COUNT_SHIFT (55)
56#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT)
57#define AB_ATTR_SUCCESSFUL (1UL << 58)
58#define AB_ATTR_UNBOOTABLE (1UL << 59)
59
60#define AB_ATTR_MAX_PRIORITY 3UL
61#define AB_ATTR_MAX_RETRY_COUNT 3UL
62
63// clang-format on
64
65static std::string getDevPath(int32_t in_slot) {
66 char real_path[PATH_MAX];
67
68 const char *path = in_slot == 0 ? BOOT_A_PATH : BOOT_B_PATH;
69
70 int ret = readlink(path, real_path, sizeof real_path);
71 if (ret < 0) {
72 ALOGE("readlink failed for boot device %s\n", strerror(errno));
73 return std::string();
74 }
75
76 std::string dp(real_path);
77 // extract /dev/sda.. part
78 return dp.substr(0, sizeof "/dev/block/sdX" - 1);
79}
80
81static bool isSlotFlagSet(int32_t in_slot, uint64_t flag) {
82 std::string dev_path = getDevPath(in_slot);
83 if (dev_path.empty()) {
84 ALOGI("Could not get device path for slot %d\n", in_slot);
85 return false;
86 }
87
88 GptUtils gpt(dev_path);
89 if (gpt.Load()) {
90 ALOGI("failed to load gpt data\n");
91 return false;
92 }
93
94 gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a");
95 if (e == nullptr) {
96 ALOGI("failed to get gpt entry\n");
97 return false;
98 }
99
100 return !!(e->attr & flag);
101}
102
103static bool setSlotFlag(int32_t in_slot, uint64_t flag) {
104 std::string dev_path = getDevPath(in_slot);
105 if (dev_path.empty()) {
106 ALOGI("Could not get device path for slot %d\n", in_slot);
107 return false;
108 }
109
110 GptUtils gpt(dev_path);
111 if (gpt.Load()) {
112 ALOGI("failed to load gpt data\n");
113 return false;
114 }
115
116 gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a");
117 if (e == nullptr) {
118 ALOGI("failed to get gpt entry\n");
119 return false;
120 }
121
122 e->attr |= flag;
123 gpt.Sync();
124
125 return true;
126}
127
128static bool is_devinfo_valid;
129static bool is_devinfo_initialized;
130static std::mutex devinfo_lock;
131static devinfo_t devinfo;
132
133static bool isDevInfoValid() {
134 const std::lock_guard<std::mutex> lock(devinfo_lock);
135
136 if (is_devinfo_initialized) {
137 return is_devinfo_valid;
138 }
139
140 is_devinfo_initialized = true;
141
142 ::android::base::unique_fd fd(open(DEVINFO_PATH, O_RDONLY));
143 ::android::base::ReadFully(fd, &devinfo, sizeof devinfo);
144
145 if (devinfo.magic != DEVINFO_MAGIC) {
146 return is_devinfo_valid;
147 }
148
149 uint32_t version = ((uint32_t)devinfo.ver_major << 16) | devinfo.ver_minor;
150 // only version 3.3+ supports A/B data
151 if (version >= 0x0003'0003) {
152 is_devinfo_valid = true;
153 }
154
155 return is_devinfo_valid;
156}
157
158static bool DevInfoSync() {
159 if (!isDevInfoValid()) {
160 return false;
161 }
162
163 ::android::base::unique_fd fd(open(DEVINFO_PATH, O_WRONLY | O_DSYNC));
164 return ::android::base::WriteFully(fd, &devinfo, sizeof devinfo);
165}
166
167static void DevInfoInitSlot(devinfo_ab_slot_data_t &slot_data) {
168 slot_data.retry_count = AB_ATTR_MAX_RETRY_COUNT;
169 slot_data.unbootable = 0;
170 slot_data.successful = 0;
171 slot_data.active = 1;
172 slot_data.fastboot_ok = 0;
173}
174
175static int blow_otp_AR(bool secure) {
176 static const char *dev_name = "/dev/trusty-ipc-dev0";
177 static const char *otp_name = "com.android.trusty.otp_manager.tidl";
178 int fd = 1, ret = 0;
179 uint32_t cmd = secure? OTP_CMD_write_antirbk_secure_ap : OTP_CMD_write_antirbk_non_secure_ap;
180 fd = tipc_connect(dev_name, otp_name);
181 if (fd < 0) {
182 ALOGI("Failed to connect to OTP_MGR ns TA - is it missing?\n");
183 ret = -1;
184 return ret;
185 }
186
187 struct otp_mgr_req_base req = {
188 .command = cmd,
189 .resp_payload_size = 0,
190 };
191 struct iovec iov[] = {
192 {
193 .iov_base = &req,
194 .iov_len = sizeof(req),
195 },
196 };
197
198 size_t rc = tipc_send(fd, iov, 1, NULL, 0);
199 if (rc != sizeof(req)) {
200 ALOGI("Send fail! %zx\n", rc);
201 return rc;
202 }
203
204 struct otp_mgr_rsp_base resp;
205 rc = read(fd, &resp, sizeof(resp));
206 if (rc < 0) {
207 ALOGI("Read fail! %zx\n", rc);
208 return rc;
209 }
210
211 if (rc < sizeof(resp)) {
212 ALOGI("Not enough data! %zx\n", rc);
213 return -EIO;
214 }
215
216 if (resp.command != (cmd | OTP_RESP_BIT)) {
217 ALOGI("Wrong command! %x\n", resp.command);
218 return -EINVAL;
219 }
220
221 if (resp.result != 0) {
222 fprintf(stderr, "AR writing error! %x\n", resp.result);
223 return -EINVAL;
224 }
225
226 tipc_close(fd);
227 return 0;
228}
229
230static bool blowAR() {
231 int ret = blow_otp_AR(true);
232 if (ret) {
233 ALOGI("Blow secure anti-rollback OTP failed");
234 return false;
235 }
236
237 ret = blow_otp_AR(false);
238 if (ret) {
239 ALOGI("Blow non-secure anti-rollback OTP failed");
240 return false;
241 }
242
243 return true;
244}
245
246static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) {
247 switch (status) {
248 case HIDLMergeStatus::NONE:
249 return MergeStatus::NONE;
250 case HIDLMergeStatus::UNKNOWN:
251 return MergeStatus::UNKNOWN;
252 case HIDLMergeStatus::SNAPSHOTTED:
253 return MergeStatus::SNAPSHOTTED;
254 case HIDLMergeStatus::MERGING:
255 return MergeStatus::MERGING;
256 case HIDLMergeStatus::CANCELLED:
257 return MergeStatus::CANCELLED;
258 }
259}
260
261static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) {
262 switch (status) {
263 case MergeStatus::NONE:
264 return HIDLMergeStatus::NONE;
265 case MergeStatus::UNKNOWN:
266 return HIDLMergeStatus::UNKNOWN;
267 case MergeStatus::SNAPSHOTTED:
268 return HIDLMergeStatus::SNAPSHOTTED;
269 case MergeStatus::MERGING:
270 return HIDLMergeStatus::MERGING;
271 case MergeStatus::CANCELLED:
272 return HIDLMergeStatus::CANCELLED;
273 }
274}
275
276} // namespace
277
278BootControl::BootControl() {
279 CHECK(InitMiscVirtualAbMessageIfNeeded());
280}
281
282ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) {
283 int32_t slots = 0;
284 getNumberSlots(&slots);
285 if (slots == 0) {
286 *_aidl_return = 0;
287 return ScopedAStatus::ok();
288 }
289
290 if (isDevInfoValid()) {
291 *_aidl_return = devinfo.ab_data.slots[1].active ? 1 : 0;
292 return ScopedAStatus::ok();
293 }
294 *_aidl_return = isSlotFlagSet(1, AB_ATTR_ACTIVE) ? 1 : 0;
295 return ScopedAStatus::ok();
296}
297
298ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) {
299 char suffix[PROPERTY_VALUE_MAX];
300 property_get("ro.boot.slot_suffix", suffix, "_a");
301 *_aidl_return = std::string(suffix) == "_b" ? 1 : 0;
302 return ScopedAStatus::ok();
303}
304
305ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) {
306 int32_t slots = 0;
307
308 if (access(BOOT_A_PATH, F_OK) == 0)
309 slots++;
310
311 if (access(BOOT_B_PATH, F_OK) == 0)
312 slots++;
313
314 *_aidl_return = slots;
315 return ScopedAStatus::ok();
316}
317
318ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) {
319 HIDLMergeStatus status;
320 int32_t current_slot = 0;
321 getCurrentSlot(&current_slot);
322 if (!GetMiscVirtualAbMergeStatus(current_slot, &status)) {
323 *_aidl_return = MergeStatus::UNKNOWN;
324 return ScopedAStatus::ok();
325 }
326 *_aidl_return = ToAIDLMergeStatus(status);
327 return ScopedAStatus::ok();
328}
329
330ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
331 *_aidl_return = in_slot == 0 ? "_a" : in_slot == 1 ? "_b" : "";
332 return ScopedAStatus::ok();
333}
334
335ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) {
336 int32_t slots = 0;
337 getNumberSlots(&slots);
338 if (slots == 0) {
339 *_aidl_return = false;
340 return ScopedAStatus::ok();
341 }
342 if (in_slot >= slots)
343 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
344 INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
345
346 bool unbootable;
347 if (isDevInfoValid()) {
348 auto &slot_data = devinfo.ab_data.slots[in_slot];
349 unbootable = !!slot_data.unbootable;
350 } else {
351 unbootable = isSlotFlagSet(in_slot, AB_ATTR_UNBOOTABLE);
352 }
353
354 *_aidl_return = unbootable ? false: true;
355 return ScopedAStatus::ok();
356}
357
358ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) {
359 int32_t slots = 0;
360 getNumberSlots(&slots);
361 if (slots == 0) {
362 // just return true so that we don't we another call trying to mark it as successful
363 // when there is no slots
364 *_aidl_return = true;
365 return ScopedAStatus::ok();
366 }
367 if (in_slot >= slots)
368 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
369 INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
370
371 bool successful;
372 if (isDevInfoValid()) {
373 auto &slot_data = devinfo.ab_data.slots[in_slot];
374 successful = !!slot_data.successful;
375 } else {
376 successful = isSlotFlagSet(in_slot, AB_ATTR_SUCCESSFUL);
377 }
378
379 *_aidl_return = successful ? true : false;
380 return ScopedAStatus::ok();
381}
382
383ScopedAStatus BootControl::markBootSuccessful() {
384 int32_t slots = 0;
385 getNumberSlots(&slots);
386 if (slots == 0) {
387 // no slots, just return true otherwise Android keeps trying
388 return ScopedAStatus::ok();
389 }
390
391 bool ret;
392 int32_t current_slot = 0;
393 getCurrentSlot(&current_slot);
394 if (isDevInfoValid()) {
395 auto const slot = current_slot;
396 devinfo.ab_data.slots[slot].successful = 1;
397 ret = DevInfoSync();
398 } else {
399 ret = setSlotFlag(current_slot, AB_ATTR_SUCCESSFUL);
400 }
401
402 if (!ret) {
403 return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
404 "Failed to set successful flag");
405 }
406
407 if (!blowAR()) {
408 ALOGE("Failed to blow anti-rollback counter");
409 // Ignore the error, since ABL will re-trigger it on reboot
410 }
411
412 return ScopedAStatus::ok();
413}
414
415ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) {
416 if (in_slot >= 2) {
417 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
418 INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
419 }
420
421 if (isDevInfoValid()) {
422 auto &active_slot_data = devinfo.ab_data.slots[in_slot];
423 auto &inactive_slot_data = devinfo.ab_data.slots[!in_slot];
424
425 inactive_slot_data.active = 0;
426 DevInfoInitSlot(active_slot_data);
427
428 if (!DevInfoSync()) {
429 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
430 COMMAND_FAILED, "Could not update DevInfo data");
431 }
432 } else {
433 std::string dev_path = getDevPath(in_slot);
434 if (dev_path.empty()) {
435 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
436 COMMAND_FAILED, "Could not get device path for slot");
437 }
438
439 GptUtils gpt(dev_path);
440 if (gpt.Load()) {
441 return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
442 "failed to load gpt data");
443 }
444
445 gpt_entry *active_entry = gpt.GetPartitionEntry(in_slot == 0 ? "boot_a" : "boot_b");
446 gpt_entry *inactive_entry = gpt.GetPartitionEntry(in_slot == 0 ? "boot_b" : "boot_a");
447 if (active_entry == nullptr || inactive_entry == nullptr) {
448 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
449 COMMAND_FAILED, "failed to get entries for boot partitions");
450 }
451
452 ALOGV("slot active attributes %lx\n", active_entry->attr);
453 ALOGV("slot inactive attributes %lx\n", inactive_entry->attr);
454
455 // update attributes for active and inactive
456 inactive_entry->attr &= ~AB_ATTR_ACTIVE;
457 active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) |
458 (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT);
459 }
460
461 char boot_dev[PROPERTY_VALUE_MAX];
462 property_get("ro.boot.bootdevice", boot_dev, "");
463 if (boot_dev[0] == '\0') {
Jason Chiu2a201a72023-11-25 02:53:02 +0800464 ALOGI("failed to get ro.boot.bootdevice. try ro.boot.boot_devices\n");
465 property_get("ro.boot.boot_devices", boot_dev, "");
466 if (boot_dev[0] == '\0') {
467 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
468 COMMAND_FAILED, "invalid ro.boot.bootdevice and ro.boot.boot_devices prop");
469 }
Jason Chiu33031712023-11-27 16:52:08 +0800470 }
471
472 std::string boot_lun_path =
473 std::string("/sys/devices/platform/") + boot_dev + "/pixel/boot_lun_enabled";
474 int fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC);
475 if (fd < 0) {
476 // Try old path for kernels < 5.4
477 // TODO: remove once kernel 4.19 support is deprecated
478 std::string boot_lun_path =
479 std::string("/sys/devices/platform/") + boot_dev + "/attributes/boot_lun_enabled";
480 fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC);
481 if (fd < 0) {
482 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
483 COMMAND_FAILED, "failed to open ufs attr boot_lun_enabled");
484 }
485 }
486
487 //
488 // bBootLunEn
489 // 0x1 => Boot LU A = enabled, Boot LU B = disable
490 // 0x2 => Boot LU A = disable, Boot LU B = enabled
491 //
492 int ret = ::android::base::WriteStringToFd(in_slot == 0 ? "1" : "2", fd);
493 close(fd);
494 if (ret < 0) {
495 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
496 COMMAND_FAILED, "faied to write boot_lun_enabled attribute");
497 }
498
499 return ScopedAStatus::ok();
500}
501
502ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) {
503 if (in_slot >= 2)
504 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
505 INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
506
507 if (isDevInfoValid()) {
508 auto &slot_data = devinfo.ab_data.slots[in_slot];
509 slot_data.unbootable = 1;
510 if (!DevInfoSync()) {
511 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
512 COMMAND_FAILED, "Could not update DevInfo data");
513 }
514 } else {
515 std::string dev_path = getDevPath(in_slot);
516 if (dev_path.empty()) {
517 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
518 COMMAND_FAILED, "Could not get device path for slot");
519 }
520
521 GptUtils gpt(dev_path);
522 gpt.Load();
523
524 gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a");
525 e->attr |= AB_ATTR_UNBOOTABLE;
526
527 gpt.Sync();
528 }
529
530 return ScopedAStatus::ok();
531}
532
533ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) {
534 int32_t current_slot = 0;
535 getCurrentSlot(&current_slot);
536 if (!SetMiscVirtualAbMergeStatus(current_slot, ToHIDLMergeStatus(in_status)))
537 return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
538 "Operation failed");
539 return ScopedAStatus::ok();
540}
541
542} // namespace aidl::android::hardware::boot