xref: /rk3399_rockchip-uboot/lib/avb/libavb_user/avb_user_verification.c (revision ab608f806ee1d7fa63a18cc035e8ea62b67634e5)
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