Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] grub: workaround for OTA failure/otaclient crashing if rootfs is not sda #258

Merged
merged 9 commits into from
Nov 6, 2023
52 changes: 46 additions & 6 deletions otaclient/app/boot_control/_grub.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Implementation of grub boot control.

DEPRECATION WARNING(20231026):
Current mechanism of defining and detecting slots is proved to be not robust.
The design expects that rootfs device will always be sda, which might not be guaranteed
as the sdx naming scheme is based on the order of kernel recognizing block devices.
If rootfs somehow is not named as sda, the grub boot controller will fail to identifiy
the slots and/or finding corresponding ota-partition files, finally failing the OTA.
Also slots are detected by assuming the partition layout, which is less robust comparing to
cboot and rpi_boot implementation of boot controller.

TODO(20231026): design new mechanism to define and manage slot.

NOTE(20231027) A workaround fix is applied to handle the edge case of rootfs not named as sda,
Check GrubABPartitionDetector class for more details.
This workaround only means to avoid OTA failed on edge condition and maintain backward compatibility,
still expecting new mechanism to fundamentally resolve this issue.
"""


import re
Expand Down Expand Up @@ -282,11 +300,21 @@ class GrubABPartitionDetector:
- sdx3: A partition
- sdx4: B partition

slot_name is the dev name of the A/B partition.
We assume that last 2 partitions are A/B partitions, error will be raised
if the current rootfs is not one of the last 2 partitions.

NOTE(20231027): as workaround to rootfs not sda breaking OTA, slot naming schema
is fixed to "sda<partition_id>", and ota-partition folder is searched with this name.
For example, if current slot's device is nvme0n1p3, the slot_name is sda3.
"""

# assuming that the suffix digit are the partiton id, for example,
# sda3's pid is 3, nvme0n1p3's pid is also 3.
DEV_PATH_PA: ClassVar[re.Pattern] = re.compile(
r"^/dev/(?P<dev_name>\w*[a-z])(?P<partition_id>\d+)$"
)
SLOT_NAME_PREFIX: ClassVar[str] = "sda"

def __init__(self) -> None:
self.active_slot, self.active_dev = self._detect_active_slot()
self.standby_slot, self.standby_dev = self._detect_standby_slot(self.active_dev)
Expand Down Expand Up @@ -321,23 +349,33 @@ def _get_sibling_dev(self, active_dev: str) -> str:
)

def _detect_active_slot(self) -> Tuple[str, str]:
"""
"""Get active slot's slot_id.

Returns:
A tuple contains the slot_name and the full dev path
of the active slot.
"""
dev_path = CMDHelperFuncs.get_current_rootfs_dev()
slot_name = dev_path.lstrip("/dev/")
_dev_path_ma = self.DEV_PATH_PA.match(dev_path)
assert _dev_path_ma, f"dev path is invalid for OTA: {dev_path}"

_pid = _dev_path_ma.group("partition_id")
slot_name = f"{self.SLOT_NAME_PREFIX}{_pid}"
return slot_name, dev_path

def _detect_standby_slot(self, active_dev: str) -> Tuple[str, str]:
"""
"""Get standby slot's slot_id.

Returns:
A tuple contains the slot_name and the full dev path
of the standby slot.
"""
dev_path = self._get_sibling_dev(active_dev)
slot_name = dev_path.lstrip("/dev/")
_dev_path_ma = self.DEV_PATH_PA.match(dev_path)
assert _dev_path_ma, f"dev path is invalid for OTA: {dev_path}"

_pid = _dev_path_ma.group("partition_id")
slot_name = f"{self.SLOT_NAME_PREFIX}{_pid}"
return slot_name, dev_path


Expand All @@ -350,7 +388,9 @@ def __init__(self) -> None:
self.standby_root_dev = ab_detector.standby_dev
self.active_slot = ab_detector.active_slot
self.standby_slot = ab_detector.standby_slot
logger.info(f"{self.active_slot=}, {self.standby_slot=}")
logger.info(
f"{self.active_slot=}@{self.active_root_dev}, {self.standby_slot=}@{self.standby_root_dev}"
)

self.boot_dir = Path(cfg.BOOT_DIR)
self.grub_file = Path(cfg.GRUB_CFG_PATH)
Expand Down
18 changes: 9 additions & 9 deletions tests/keys/interm.pem
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6zCCAZCgAwIBAgIUWO/ANSZ6jsn+aIK9RQDgniCR92gwCgYIKoZIzj0EAwIw
MIIB6jCCAZCgAwIBAgIUclYCFrRLcGCulcyR1uc8oA7t8vYwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMQ4wDAYDVQQKDAVUaWVyNDEW
MBQGA1UEAwwNcm9vdC50aWVyNC5qcDAeFw0yMjEwMDMwNDE5MDNaFw0zMjEwMDUw
NDE5MDNaME0xCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UECgwF
MBQGA1UEAwwNcm9vdC50aWVyNC5qcDAeFw0yMzEwMjcwNjU2MjdaFw0zMzEwMjkw
NjU2MjdaME0xCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UECgwF
VGllcjQxHjAcBgNVBAMMFWludGVybWVkaWF0ZS50aWVyNC5qcDBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABBKX8h546xKxJR8qArXmyBngW/T9+XbxowBssCg0yjZ6
/tsRNPF5RlCDzI4C8DactlQP0t27NvxZQQhXFXpr4kujVjBUMB0GA1UdDgQWBBSL
03kBOi7DPLY0IQ+Q5ci4ObMfJzAfBgNVHSMEGDAWgBTUIPiXLIF4b/36Hgu4S/KU
sBjhGDASBgNVHRMBAf8ECDAGAQH/AgEAMAoGCCqGSM49BAMCA0kAMEYCIQCWNbaK
dkGer4rjV1rdkHv+jN5iYqL0H4ZeFKZ7wbgdKQIhAMZb8AC+Va1o1L0U9294jdI0
aooIZ7UavjKy6t0mXB99
AgEGCCqGSM49AwEHA0IABIu6gNzIRcDFoykqMWBRCxQfBx2BGK5lfFbJAfgYvxNN
OViBFZDOPxTHhFmuFX6txaT4pqfpWhQXpP2h+VzpCuGjVjBUMB0GA1UdDgQWBBRi
ik8kqC+T+dNnU1eML+lLEKAOGzAfBgNVHSMEGDAWgBRSteexpfLelFY6oPQL1dXH
Ky5+kTASBgNVHRMBAf8ECDAGAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIHb9ZcDN
z3RUhVXaJd8WvkUlYHPNP5LP+0IFaJ7IzumTAiEAo1nLsbCF8WkLf4VXtJNk9Hu3
1MbvWqS/Hhk5+tV7+AI=
-----END CERTIFICATE-----
18 changes: 9 additions & 9 deletions tests/keys/root.pem
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB3zCCAYWgAwIBAgIUVcCyMLO2J6JKxw8Ye4cn21ty8XUwCgYIKoZIzj0EAwIw
MIIB3jCCAYWgAwIBAgIUGYEMZsuwqHrRhrLot++BqE+xbQ4wCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMQ4wDAYDVQQKDAVUaWVyNDEW
MBQGA1UEAwwNcm9vdC50aWVyNC5qcDAeFw0yMjEwMDMwNDE5MDNaFw0zMjEwMDUw
NDE5MDNaMEUxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UECgwF
MBQGA1UEAwwNcm9vdC50aWVyNC5qcDAeFw0yMzEwMjcwNjU2MjdaFw0zMzEwMjkw
NjU2MjdaMEUxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UECgwF
VGllcjQxFjAUBgNVBAMMDXJvb3QudGllcjQuanAwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAARH1pYCjqPrXGGVIsMWIXvRIZfNCSH07X1iPn3lyNq7kIN4bJFiHdMi
LxxOh94uvhh7psYcrDizFi/l3SsLihbxo1MwUTAdBgNVHQ4EFgQU1CD4lyyBeG/9
+h4LuEvylLAY4RgwHwYDVR0jBBgwFoAU1CD4lyyBeG/9+h4LuEvylLAY4RgwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAhJLAk9SRQ2Q61m9e2VoM
m86odWMLRv+EKbpWebe4WTwCICnch1agvDomA7PMbkPvg0kz/jot2YoN3xZ24O6G
zjmb
PQMBBwNCAAR6Fa70+SJgvwq0adME6CAqq4VwNeJhAUxUdgz9QS+DpI7LcdMS6cmq
3EqA2vJ5Z9jpVAOUuJ2kXqrtalhN69bCo1MwUTAdBgNVHQ4EFgQUUrXnsaXy3pRW
OqD0C9XVxysufpEwHwYDVR0jBBgwFoAUUrXnsaXy3pRWOqD0C9XVxysufpEwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiACPOdQ/zjz+tokGgb6APQp
ptM9N5JXgHTYTFBBpT72cAIgIWCnbPU68z6YiI4A1JqMzO4mUfnSP+5ssWTHLC2O
Bfg=
-----END CERTIFICATE-----
6 changes: 3 additions & 3 deletions tests/keys/sign.key
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFBCLuRbpajW14w5MMqAjprChcTHz6+s0NxLEZaL6uTXoAoGCCqGSM49
AwEHoUQDQgAEGxHFx+A641vv8cZ4M/YnrstGo0JfyTdGyaXX7Q5T9z0yRF0B35US
sqYSlja5cgt2bmJxk8EJrHxfUBrSQLi3PQ==
MHcCAQEEIDdgqKIQ3e30Dp0ZHz1ZWxkR6OAACEVCru/Klrepmj9xoAoGCCqGSM49
AwEHoUQDQgAET8KH6J7rVkECpv9WfGGyyv4hj1ck8vBPMpLZSneePFzMFlxi0pYA
u2qsM/vssHsWi3j3Gii0l/CtyQSK1OK75g==
-----END EC PRIVATE KEY-----
14 changes: 7 additions & 7 deletions tests/keys/sign.pem
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBjjCCATMCFAgcTp8kYozCqL4Aib6cooc5o2tnMAoGCCqGSM49BAMCME0xCzAJ
MIIBjTCCATMCFG4r2lF/oNv7Ew2T7XDbfuQEuOW3MAoGCCqGSM49BAMCME0xCzAJ
BgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UECgwFVGllcjQxHjAcBgNV
BAMMFWludGVybWVkaWF0ZS50aWVyNC5qcDAeFw0yMjEwMDMwNDE5MDNaFw0yMzEw
MDMwNDE5MDNaMEUxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UE
BAMMFWludGVybWVkaWF0ZS50aWVyNC5qcDAeFw0yMzEwMjcwNjU2MjdaFw0yNDEw
MjYwNjU2MjdaMEUxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEOMAwGA1UE
CgwFVGllcjQxFjAUBgNVBAMMDXNpZ24udGllcjQuanAwWTATBgcqhkjOPQIBBggq
hkjOPQMBBwNCAAQbEcXH4DrjW+/xxngz9ieuy0ajQl/JN0bJpdftDlP3PTJEXQHf
lRKyphKWNrlyC3ZuYnGTwQmsfF9QGtJAuLc9MAoGCCqGSM49BAMCA0kAMEYCIQCx
Pn2DN1k1M2X1+96qTkvwCibD3uDB1pPMdM0oBRWFswIhAIwU9tRlTQj1M3TShBuP
01qYR4cuhMyec7VLI0VPyfBa
hkjOPQMBBwNCAARPwofonutWQQKm/1Z8YbLK/iGPVyTy8E8yktlKd548XMwWXGLS
lgC7aqwz++ywexaLePcaKLSX8K3JBIrU4rvmMAoGCCqGSM49BAMCA0gAMEUCIQCL
U0RAelUktN4KWBk/S3ZL7pV6BHIz5pir8QN7pzGuwQIgdrkTFIGSeNoLIi1naZbU
16HdWbQJOVtrmjHx1tZBP7o=
-----END CERTIFICATE-----
Loading