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 */ 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 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 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