summaryrefslogtreecommitdiffstats
path: root/nixos/modules/image/assert_uki_repart_match.py
blob: e0f266cf15bfb5467f1d77fa3ec092cb18ce76a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import json
import sys

store_verity_type = "@NIX_STORE_VERITY@"  # replaced at import by Nix


def extract_uki_cmdline_params(ukify_json: dict) -> dict[str, str]:
    """
    Return a dict of the parameters in the .cmdline section of the UKI
    Exits early if "usrhash" is not included.
    """
    cmdline = ukify_json.get(".cmdline", {}).get("text")
    if cmdline is None:
        print("Failed to get cmdline from ukify output")

    params = {}
    for param in cmdline.split():
        key, val = param.partition("=")[::2]
        params[key] = val

    if "usrhash" not in params:
        print(
            f"UKI cmdline does not contain a usrhash:\n{cmdline}"
        )
        exit(1)

    return params


def hashes_match(partition: dict[str, str], expected: str) -> bool:
    """
    Checks if the value of the "roothash" key in the passed partition object matches `expected`.
    """
    if partition.get("roothash") != expected:
        pretty_part = json.dumps(partition, indent=2)
        print(
            f"hash mismatch, expected to find roothash {expected} in:\n{pretty_part}"
        )
        return False
    else:
        return True


def check_partitions(
    partitions: list[dict], uki_params: dict[str, str]
) -> bool:
    """
    Checks if the usrhash from `uki_params` has a matching roothash
    for the corresponding partition in `partitions`.
    """
    for part in partitions:
        if part.get("type") == store_verity_type:
            expected = uki_params["usrhash"]
            return hashes_match(part, expected)

    return False


def main() -> None:
    ukify_json = json.load(sys.stdin)
    repart_json_output = sys.argv[1]

    with open(repart_json_output, "r") as r:
        repart_json = json.load(r)

    uki_params = extract_uki_cmdline_params(ukify_json)

    if check_partitions(repart_json, uki_params):
        print("UKI and repart verity hashes match")
    else:
        print("Compatibility check for UKI and image failed!")
        print(f"UKI cmdline parameters:\n{uki_params}")
        print(f"repart config: {repart_json_output}")
        exit(1)


if __name__ == "__main__":
    main()