1*37a7bc39SJason Zhu /*
2*37a7bc39SJason Zhu * Copyright (C) 2017 The Android Open Source Project
3*37a7bc39SJason Zhu *
4*37a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person
5*37a7bc39SJason Zhu * obtaining a copy of this software and associated documentation
6*37a7bc39SJason Zhu * files (the "Software"), to deal in the Software without
7*37a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy,
8*37a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies
9*37a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is
10*37a7bc39SJason Zhu * furnished to do so, subject to the following conditions:
11*37a7bc39SJason Zhu *
12*37a7bc39SJason Zhu * The above copyright notice and this permission notice shall be
13*37a7bc39SJason Zhu * included in all copies or substantial portions of the Software.
14*37a7bc39SJason Zhu *
15*37a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*37a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*37a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*37a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*37a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*37a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*37a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*37a7bc39SJason Zhu * SOFTWARE.
23*37a7bc39SJason Zhu */
24*37a7bc39SJason Zhu
25*37a7bc39SJason Zhu #include <android_avb/avb_user_verification.h>
26*37a7bc39SJason Zhu
27*37a7bc39SJason Zhu /* Maximum allow length (in bytes) of a partition name, including
28*37a7bc39SJason Zhu * ab_suffix.
29*37a7bc39SJason Zhu */
30*37a7bc39SJason Zhu #define AVB_PART_NAME_MAX_SIZE 32
31*37a7bc39SJason Zhu
32*37a7bc39SJason Zhu /* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by
33*37a7bc39SJason Zhu * |ab_suffix| into |vbmeta_image|. No validation, verification, or
34*37a7bc39SJason Zhu * byteswapping is performed.
35*37a7bc39SJason Zhu *
36*37a7bc39SJason Zhu * If successful, |true| is returned and the partition it was loaded
37*37a7bc39SJason Zhu * from is returned in |out_partition_name| and the offset on said
38*37a7bc39SJason Zhu * partition is returned in |out_vbmeta_offset|.
39*37a7bc39SJason Zhu */
load_top_level_vbmeta_header(AvbOps * ops,const char * ab_suffix,uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],char out_partition_name[AVB_PART_NAME_MAX_SIZE],uint64_t * out_vbmeta_offset)40*37a7bc39SJason Zhu static bool load_top_level_vbmeta_header(
41*37a7bc39SJason Zhu AvbOps* ops,
42*37a7bc39SJason Zhu const char* ab_suffix,
43*37a7bc39SJason Zhu uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
44*37a7bc39SJason Zhu char out_partition_name[AVB_PART_NAME_MAX_SIZE],
45*37a7bc39SJason Zhu uint64_t* out_vbmeta_offset) {
46*37a7bc39SJason Zhu uint64_t vbmeta_offset = 0;
47*37a7bc39SJason Zhu size_t num_read;
48*37a7bc39SJason Zhu bool ret = false;
49*37a7bc39SJason Zhu AvbIOResult io_res;
50*37a7bc39SJason Zhu
51*37a7bc39SJason Zhu /* Construct full partition name. */
52*37a7bc39SJason Zhu if (!avb_str_concat(out_partition_name,
53*37a7bc39SJason Zhu AVB_PART_NAME_MAX_SIZE,
54*37a7bc39SJason Zhu "vbmeta",
55*37a7bc39SJason Zhu 6,
56*37a7bc39SJason Zhu ab_suffix,
57*37a7bc39SJason Zhu avb_strlen(ab_suffix))) {
58*37a7bc39SJason Zhu avb_error("Partition name and suffix does not fit.\n");
59*37a7bc39SJason Zhu goto out;
60*37a7bc39SJason Zhu }
61*37a7bc39SJason Zhu
62*37a7bc39SJason Zhu /* Only read the header, not the entire struct. */
63*37a7bc39SJason Zhu io_res = ops->read_from_partition(ops,
64*37a7bc39SJason Zhu out_partition_name,
65*37a7bc39SJason Zhu vbmeta_offset,
66*37a7bc39SJason Zhu AVB_VBMETA_IMAGE_HEADER_SIZE,
67*37a7bc39SJason Zhu vbmeta_image,
68*37a7bc39SJason Zhu &num_read);
69*37a7bc39SJason Zhu if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
70*37a7bc39SJason Zhu AvbFooter footer;
71*37a7bc39SJason Zhu
72*37a7bc39SJason Zhu /* Try looking for the vbmeta struct in 'boot' via the footer. */
73*37a7bc39SJason Zhu if (!avb_str_concat(out_partition_name,
74*37a7bc39SJason Zhu AVB_PART_NAME_MAX_SIZE,
75*37a7bc39SJason Zhu "boot",
76*37a7bc39SJason Zhu 4,
77*37a7bc39SJason Zhu ab_suffix,
78*37a7bc39SJason Zhu avb_strlen(ab_suffix))) {
79*37a7bc39SJason Zhu avb_error("Partition name and suffix does not fit.\n");
80*37a7bc39SJason Zhu goto out;
81*37a7bc39SJason Zhu }
82*37a7bc39SJason Zhu io_res = ops->read_from_partition(ops,
83*37a7bc39SJason Zhu out_partition_name,
84*37a7bc39SJason Zhu -AVB_FOOTER_SIZE,
85*37a7bc39SJason Zhu AVB_FOOTER_SIZE,
86*37a7bc39SJason Zhu &footer,
87*37a7bc39SJason Zhu &num_read);
88*37a7bc39SJason Zhu if (io_res != AVB_IO_RESULT_OK) {
89*37a7bc39SJason Zhu avb_errorv("Error loading footer from partition '",
90*37a7bc39SJason Zhu out_partition_name,
91*37a7bc39SJason Zhu "'\n",
92*37a7bc39SJason Zhu NULL);
93*37a7bc39SJason Zhu goto out;
94*37a7bc39SJason Zhu }
95*37a7bc39SJason Zhu
96*37a7bc39SJason Zhu if (avb_memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) {
97*37a7bc39SJason Zhu avb_errorv("Data from '",
98*37a7bc39SJason Zhu out_partition_name,
99*37a7bc39SJason Zhu "' does not look like a vbmeta footer.\n",
100*37a7bc39SJason Zhu NULL);
101*37a7bc39SJason Zhu goto out;
102*37a7bc39SJason Zhu }
103*37a7bc39SJason Zhu
104*37a7bc39SJason Zhu vbmeta_offset = avb_be64toh(footer.vbmeta_offset);
105*37a7bc39SJason Zhu io_res = ops->read_from_partition(ops,
106*37a7bc39SJason Zhu out_partition_name,
107*37a7bc39SJason Zhu vbmeta_offset,
108*37a7bc39SJason Zhu AVB_VBMETA_IMAGE_HEADER_SIZE,
109*37a7bc39SJason Zhu vbmeta_image,
110*37a7bc39SJason Zhu &num_read);
111*37a7bc39SJason Zhu }
112*37a7bc39SJason Zhu
113*37a7bc39SJason Zhu if (io_res != AVB_IO_RESULT_OK) {
114*37a7bc39SJason Zhu avb_errorv(
115*37a7bc39SJason Zhu "Error loading from partition '", out_partition_name, "'\n", NULL);
116*37a7bc39SJason Zhu goto out;
117*37a7bc39SJason Zhu }
118*37a7bc39SJason Zhu
119*37a7bc39SJason Zhu if (out_vbmeta_offset != NULL) {
120*37a7bc39SJason Zhu *out_vbmeta_offset = vbmeta_offset;
121*37a7bc39SJason Zhu }
122*37a7bc39SJason Zhu
123*37a7bc39SJason Zhu ret = true;
124*37a7bc39SJason Zhu
125*37a7bc39SJason Zhu out:
126*37a7bc39SJason Zhu return ret;
127*37a7bc39SJason Zhu }
128*37a7bc39SJason Zhu
avb_user_verification_get(AvbOps * ops,const char * ab_suffix,bool * out_verification_enabled)129*37a7bc39SJason Zhu bool avb_user_verification_get(AvbOps* ops,
130*37a7bc39SJason Zhu const char* ab_suffix,
131*37a7bc39SJason Zhu bool* out_verification_enabled) {
132*37a7bc39SJason Zhu uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
133*37a7bc39SJason Zhu char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */
134*37a7bc39SJason Zhu AvbVBMetaImageHeader* header;
135*37a7bc39SJason Zhu uint32_t flags;
136*37a7bc39SJason Zhu bool ret = false;
137*37a7bc39SJason Zhu
138*37a7bc39SJason Zhu if (!load_top_level_vbmeta_header(
139*37a7bc39SJason Zhu ops, ab_suffix, vbmeta_image, partition_name, NULL)) {
140*37a7bc39SJason Zhu goto out;
141*37a7bc39SJason Zhu }
142*37a7bc39SJason Zhu
143*37a7bc39SJason Zhu if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
144*37a7bc39SJason Zhu avb_errorv("Data from '",
145*37a7bc39SJason Zhu partition_name,
146*37a7bc39SJason Zhu "' does not look like a vbmeta header.\n",
147*37a7bc39SJason Zhu NULL);
148*37a7bc39SJason Zhu goto out;
149*37a7bc39SJason Zhu }
150*37a7bc39SJason Zhu
151*37a7bc39SJason Zhu /* Set/clear the VERIFICATION_DISABLED bit, as requested. */
152*37a7bc39SJason Zhu header = (AvbVBMetaImageHeader*)vbmeta_image;
153*37a7bc39SJason Zhu flags = avb_be32toh(header->flags);
154*37a7bc39SJason Zhu
155*37a7bc39SJason Zhu if (out_verification_enabled != NULL) {
156*37a7bc39SJason Zhu *out_verification_enabled =
157*37a7bc39SJason Zhu !(flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
158*37a7bc39SJason Zhu }
159*37a7bc39SJason Zhu
160*37a7bc39SJason Zhu ret = true;
161*37a7bc39SJason Zhu
162*37a7bc39SJason Zhu out:
163*37a7bc39SJason Zhu return ret;
164*37a7bc39SJason Zhu }
165*37a7bc39SJason Zhu
avb_user_verification_set(AvbOps * ops,const char * ab_suffix,bool enable_verification)166*37a7bc39SJason Zhu bool avb_user_verification_set(AvbOps* ops,
167*37a7bc39SJason Zhu const char* ab_suffix,
168*37a7bc39SJason Zhu bool enable_verification) {
169*37a7bc39SJason Zhu uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
170*37a7bc39SJason Zhu char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */
171*37a7bc39SJason Zhu uint64_t vbmeta_offset;
172*37a7bc39SJason Zhu AvbIOResult io_res;
173*37a7bc39SJason Zhu AvbVBMetaImageHeader* header;
174*37a7bc39SJason Zhu uint32_t flags;
175*37a7bc39SJason Zhu bool ret = false;
176*37a7bc39SJason Zhu
177*37a7bc39SJason Zhu if (!load_top_level_vbmeta_header(
178*37a7bc39SJason Zhu ops, ab_suffix, vbmeta_image, partition_name, &vbmeta_offset)) {
179*37a7bc39SJason Zhu goto out;
180*37a7bc39SJason Zhu }
181*37a7bc39SJason Zhu
182*37a7bc39SJason Zhu if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
183*37a7bc39SJason Zhu avb_errorv("Data from '",
184*37a7bc39SJason Zhu partition_name,
185*37a7bc39SJason Zhu "' does not look like a vbmeta header.\n",
186*37a7bc39SJason Zhu NULL);
187*37a7bc39SJason Zhu goto out;
188*37a7bc39SJason Zhu }
189*37a7bc39SJason Zhu
190*37a7bc39SJason Zhu /* Set/clear the VERIFICATION_DISABLED bit, as requested. */
191*37a7bc39SJason Zhu header = (AvbVBMetaImageHeader*)vbmeta_image;
192*37a7bc39SJason Zhu flags = avb_be32toh(header->flags);
193*37a7bc39SJason Zhu flags &= ~AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
194*37a7bc39SJason Zhu if (!enable_verification) {
195*37a7bc39SJason Zhu flags |= AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
196*37a7bc39SJason Zhu }
197*37a7bc39SJason Zhu header->flags = avb_htobe32(flags);
198*37a7bc39SJason Zhu
199*37a7bc39SJason Zhu /* Write the header. */
200*37a7bc39SJason Zhu io_res = ops->write_to_partition(ops,
201*37a7bc39SJason Zhu partition_name,
202*37a7bc39SJason Zhu vbmeta_offset,
203*37a7bc39SJason Zhu AVB_VBMETA_IMAGE_HEADER_SIZE,
204*37a7bc39SJason Zhu vbmeta_image);
205*37a7bc39SJason Zhu if (io_res != AVB_IO_RESULT_OK) {
206*37a7bc39SJason Zhu avb_errorv("Error writing to partition '", partition_name, "'\n", NULL);
207*37a7bc39SJason Zhu goto out;
208*37a7bc39SJason Zhu }
209*37a7bc39SJason Zhu
210*37a7bc39SJason Zhu ret = true;
211*37a7bc39SJason Zhu
212*37a7bc39SJason Zhu out:
213*37a7bc39SJason Zhu return ret;
214*37a7bc39SJason Zhu }
215